gpu allocation optimizations (ryubing/ryujinx!195)

See merge request ryubing/ryujinx!195
This commit is contained in:
LotP 2025-10-26 14:14:51 -05:00
parent 718652599d
commit c94ffaa00a
20 changed files with 297 additions and 234 deletions

View file

@ -99,7 +99,6 @@ namespace Ryujinx.Audio.Renderer.Server
break; break;
case CommandType.BiquadFilterFloatCoeff: case CommandType.BiquadFilterFloatCoeff:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.Mix: case CommandType.Mix:
_mixCommandPool.Release((MixCommand)command); _mixCommandPool.Release((MixCommand)command);
break; break;
@ -159,7 +158,6 @@ namespace Ryujinx.Audio.Renderer.Server
break; break;
case CommandType.MultiTapBiquadFilterFloatCoeff: case CommandType.MultiTapBiquadFilterFloatCoeff:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.CaptureBuffer: case CommandType.CaptureBuffer:
_captureBufferCommandPool.Release((CaptureBufferCommand)command); _captureBufferCommandPool.Release((CaptureBufferCommand)command);
break; break;
@ -171,25 +169,19 @@ namespace Ryujinx.Audio.Renderer.Server
break; break;
case CommandType.BiquadFilterAndMixFloatCoeff: case CommandType.BiquadFilterAndMixFloatCoeff:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.MultiTapBiquadFilterAndMix: case CommandType.MultiTapBiquadFilterAndMix:
_multiTapBiquadFilterAndMixCommandPool.Release((MultiTapBiquadFilterAndMixCommand)command); _multiTapBiquadFilterAndMixCommandPool.Release((MultiTapBiquadFilterAndMixCommand)command);
break; break;
case CommandType.MultiTapBiquadFilterAndMixFloatCoef: case CommandType.MultiTapBiquadFilterAndMixFloatCoef:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.AuxiliaryBufferGrouped: case CommandType.AuxiliaryBufferGrouped:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.FillMixBuffer: case CommandType.FillMixBuffer:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.BiquadFilterCrossFade: case CommandType.BiquadFilterCrossFade:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.MultiTapBiquadFilterCrossFade: case CommandType.MultiTapBiquadFilterCrossFade:
throw new NotImplementedException(); throw new NotImplementedException();
break;
case CommandType.FillBuffer: case CommandType.FillBuffer:
_fillBufferCommandPool.Release((FillBufferCommand)command); _fillBufferCommandPool.Release((FillBufferCommand)command);
break; break;

View file

@ -7,11 +7,11 @@ namespace Ryujinx.Common
where T : class where T : class
{ {
private int _size = size; private int _size = size;
private readonly ConcurrentStack<T> _items = new(); private readonly ConcurrentBag<T> _items = new();
public T Allocate() public T Allocate()
{ {
bool success = _items.TryPop(out T instance); bool success = _items.TryTake(out T instance);
if (!success) if (!success)
{ {
@ -25,7 +25,7 @@ namespace Ryujinx.Common
{ {
if (_size < 0 || _items.Count < _size) if (_size < 0 || _items.Count < _size)
{ {
_items.Push(obj); _items.Add(obj);
} }
} }

View file

@ -151,6 +151,11 @@ namespace Ryujinx.Cpu.AppleHv
} }
} }
public override bool TryReadUnsafe(ulong va, int length, out Span<byte> data)
{
throw new NotImplementedException();
}
public override void Write(ulong va, ReadOnlySpan<byte> data) public override void Write(ulong va, ReadOnlySpan<byte> data)
{ {
try try

View file

@ -174,6 +174,11 @@ namespace Ryujinx.Cpu.Jit
} }
} }
} }
public override bool TryReadUnsafe(ulong va, int length, out Span<byte> data)
{
throw new NotImplementedException();
}
public override void Write(ulong va, ReadOnlySpan<byte> data) public override void Write(ulong va, ReadOnlySpan<byte> data)
{ {

View file

@ -151,6 +151,11 @@ namespace Ryujinx.Cpu.Jit
return default; return default;
} }
} }
public override bool TryReadUnsafe(ulong va, int length, out Span<byte> data)
{
throw new NotImplementedException();
}
public override T ReadTracked<T>(ulong va) public override T ReadTracked<T>(ulong va)
{ {

View file

@ -227,6 +227,11 @@ namespace Ryujinx.Cpu.Jit
} }
} }
} }
public override bool TryReadUnsafe(ulong va, int length, out Span<byte> data)
{
throw new NotImplementedException();
}
public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data) public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
{ {

View file

@ -29,9 +29,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose() public unsafe void Dispose()
{ {
_renderer.New<CounterEventDisposeCommand>().Set(Ref(this)); _renderer.New<CounterEventDisposeCommand>()->Set(Ref(this));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }

View file

@ -21,15 +21,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose() public unsafe void Dispose()
{ {
_renderer.New<ImageArrayDisposeCommand>().Set(Ref(this)); _renderer.New<ImageArrayDisposeCommand>()->Set(Ref(this));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImages(int index, ITexture[] images) public unsafe void SetImages(int index, ITexture[] images)
{ {
_renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images)); _renderer.New<ImageArraySetImagesCommand>()->Set(Ref(this), index, Ref(images));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
} }

View file

@ -21,25 +21,25 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose() public unsafe void Dispose()
{ {
_renderer.New<ProgramDisposeCommand>().Set(Ref(this)); _renderer.New<ProgramDisposeCommand>()->Set(Ref(this));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public byte[] GetBinary() public unsafe byte[] GetBinary()
{ {
ResultBox<byte[]> box = new(); ResultBox<byte[]> box = new();
_renderer.New<ProgramGetBinaryCommand>().Set(Ref(this), Ref(box)); _renderer.New<ProgramGetBinaryCommand>()->Set(Ref(this), Ref(box));
_renderer.InvokeCommand(); _renderer.InvokeCommand();
return box.Result; return box.Result;
} }
public ProgramLinkStatus CheckProgramLink(bool blocking) public unsafe ProgramLinkStatus CheckProgramLink(bool blocking)
{ {
ResultBox<ProgramLinkStatus> box = new(); ResultBox<ProgramLinkStatus> box = new();
_renderer.New<ProgramCheckLinkCommand>().Set(Ref(this), blocking, Ref(box)); _renderer.New<ProgramCheckLinkCommand>()->Set(Ref(this), blocking, Ref(box));
_renderer.InvokeCommand(); _renderer.InvokeCommand();
return box.Result; return box.Result;

View file

@ -13,9 +13,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
_renderer = renderer; _renderer = renderer;
} }
public void Dispose() public unsafe void Dispose()
{ {
_renderer.New<SamplerDisposeCommand>().Set(new TableRef<ThreadedSampler>(_renderer, this)); _renderer.New<SamplerDisposeCommand>()->Set(new TableRef<ThreadedSampler>(_renderer, this));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
} }

View file

@ -28,25 +28,25 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void CopyTo(ITexture destination, int firstLayer, int firstLevel) public unsafe void CopyTo(ITexture destination, int firstLayer, int firstLevel)
{ {
_renderer.New<TextureCopyToCommand>().Set(Ref(this), Ref((ThreadedTexture)destination), firstLayer, firstLevel); _renderer.New<TextureCopyToCommand>()->Set(Ref(this), Ref((ThreadedTexture)destination), firstLayer, firstLevel);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel) public unsafe void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{ {
_renderer.New<TextureCopyToSliceCommand>().Set(Ref(this), Ref((ThreadedTexture)destination), srcLayer, dstLayer, srcLevel, dstLevel); _renderer.New<TextureCopyToSliceCommand>()->Set(Ref(this), Ref((ThreadedTexture)destination), srcLayer, dstLayer, srcLevel, dstLevel);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter) public unsafe void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
{ {
ThreadedTexture dest = (ThreadedTexture)destination; ThreadedTexture dest = (ThreadedTexture)destination;
if (_renderer.IsGpuThread()) if (_renderer.IsGpuThread())
{ {
_renderer.New<TextureCopyToScaledCommand>().Set(Ref(this), Ref(dest), srcRegion, dstRegion, linearFilter); _renderer.New<TextureCopyToScaledCommand>()->Set(Ref(this), Ref(dest), srcRegion, dstRegion, linearFilter);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
else else
@ -59,21 +59,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
} }
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel) public unsafe ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
{ {
ThreadedTexture newTex = new(_renderer, info); ThreadedTexture newTex = new(_renderer, info);
_renderer.New<TextureCreateViewCommand>().Set(Ref(this), Ref(newTex), info, firstLayer, firstLevel); _renderer.New<TextureCreateViewCommand>()->Set(Ref(this), Ref(newTex), info, firstLayer, firstLevel);
_renderer.QueueCommand(); _renderer.QueueCommand();
return newTex; return newTex;
} }
public PinnedSpan<byte> GetData() public unsafe PinnedSpan<byte> GetData()
{ {
if (_renderer.IsGpuThread()) if (_renderer.IsGpuThread())
{ {
ResultBox<PinnedSpan<byte>> box = new(); ResultBox<PinnedSpan<byte>> box = new();
_renderer.New<TextureGetDataCommand>().Set(Ref(this), Ref(box)); _renderer.New<TextureGetDataCommand>()->Set(Ref(this), Ref(box));
_renderer.InvokeCommand(); _renderer.InvokeCommand();
return box.Result; return box.Result;
@ -86,12 +86,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
} }
public PinnedSpan<byte> GetData(int layer, int level) public unsafe PinnedSpan<byte> GetData(int layer, int level)
{ {
if (_renderer.IsGpuThread()) if (_renderer.IsGpuThread())
{ {
ResultBox<PinnedSpan<byte>> box = new(); ResultBox<PinnedSpan<byte>> box = new();
_renderer.New<TextureGetDataSliceCommand>().Set(Ref(this), Ref(box), layer, level); _renderer.New<TextureGetDataSliceCommand>()->Set(Ref(this), Ref(box), layer, level);
_renderer.InvokeCommand(); _renderer.InvokeCommand();
return box.Result; return box.Result;
@ -104,42 +104,42 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
} }
public void CopyTo(BufferRange range, int layer, int level, int stride) public unsafe void CopyTo(BufferRange range, int layer, int level, int stride)
{ {
_renderer.New<TextureCopyToBufferCommand>().Set(Ref(this), range, layer, level, stride); _renderer.New<TextureCopyToBufferCommand>()->Set(Ref(this), range, layer, level, stride);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data) public unsafe void SetData(MemoryOwner<byte> data)
{ {
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data)); _renderer.New<TextureSetDataCommand>()->Set(Ref(this), Ref(data));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level) public unsafe void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level); _renderer.New<TextureSetDataSliceCommand>()->Set(Ref(this), Ref(data), layer, level);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public unsafe void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region); _renderer.New<TextureSetDataSliceRegionCommand>()->Set(Ref(this), Ref(data), layer, level, region);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetStorage(BufferRange buffer) public unsafe void SetStorage(BufferRange buffer)
{ {
_renderer.New<TextureSetStorageCommand>().Set(Ref(this), buffer); _renderer.New<TextureSetStorageCommand>()->Set(Ref(this), buffer);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void Release() public unsafe void Release()
{ {
_renderer.New<TextureReleaseCommand>().Set(Ref(this)); _renderer.New<TextureReleaseCommand>()->Set(Ref(this));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
} }

View file

@ -22,21 +22,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose() public unsafe void Dispose()
{ {
_renderer.New<TextureArrayDisposeCommand>().Set(Ref(this)); _renderer.New<TextureArrayDisposeCommand>()->Set(Ref(this));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetSamplers(int index, ISampler[] samplers) public unsafe void SetSamplers(int index, ISampler[] samplers)
{ {
_renderer.New<TextureArraySetSamplersCommand>().Set(Ref(this), index, Ref(samplers.ToArray())); _renderer.New<TextureArraySetSamplersCommand>()->Set(Ref(this), index, Ref(samplers.ToArray()));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetTextures(int index, ITexture[] textures) public unsafe void SetTextures(int index, ITexture[] textures)
{ {
_renderer.New<TextureArraySetTexturesCommand>().Set(Ref(this), index, Ref(textures.ToArray())); _renderer.New<TextureArraySetTexturesCommand>()->Set(Ref(this), index, Ref(textures.ToArray()));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
} }

View file

@ -21,343 +21,343 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Barrier() public unsafe void Barrier()
{ {
_renderer.New<BarrierCommand>(); _renderer.New<BarrierCommand>();
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void BeginTransformFeedback(PrimitiveTopology topology) public unsafe void BeginTransformFeedback(PrimitiveTopology topology)
{ {
_renderer.New<BeginTransformFeedbackCommand>().Set(topology); _renderer.New<BeginTransformFeedbackCommand>()->Set(topology);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void ClearBuffer(BufferHandle destination, int offset, int size, uint value) public unsafe void ClearBuffer(BufferHandle destination, int offset, int size, uint value)
{ {
_renderer.New<ClearBufferCommand>().Set(destination, offset, size, value); _renderer.New<ClearBufferCommand>()->Set(destination, offset, size, value);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color) public unsafe void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color)
{ {
_renderer.New<ClearRenderTargetColorCommand>().Set(index, layer, layerCount, componentMask, color); _renderer.New<ClearRenderTargetColorCommand>()->Set(index, layer, layerCount, componentMask, color);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask) public unsafe void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask)
{ {
_renderer.New<ClearRenderTargetDepthStencilCommand>().Set(layer, layerCount, depthValue, depthMask, stencilValue, stencilMask); _renderer.New<ClearRenderTargetDepthStencilCommand>()->Set(layer, layerCount, depthValue, depthMask, stencilValue, stencilMask);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void CommandBufferBarrier() public unsafe void CommandBufferBarrier()
{ {
_renderer.New<CommandBufferBarrierCommand>(); _renderer.New<CommandBufferBarrierCommand>();
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size) public unsafe void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
{ {
_renderer.New<CopyBufferCommand>().Set(source, destination, srcOffset, dstOffset, size); _renderer.New<CopyBufferCommand>()->Set(source, destination, srcOffset, dstOffset, size);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void DispatchCompute(int groupsX, int groupsY, int groupsZ) public unsafe void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{ {
_renderer.New<DispatchComputeCommand>().Set(groupsX, groupsY, groupsZ); _renderer.New<DispatchComputeCommand>()->Set(groupsX, groupsY, groupsZ);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) public unsafe void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
{ {
_renderer.New<DrawCommand>().Set(vertexCount, instanceCount, firstVertex, firstInstance); _renderer.New<DrawCommand>()->Set(vertexCount, instanceCount, firstVertex, firstInstance);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance) public unsafe void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
{ {
_renderer.New<DrawIndexedCommand>().Set(indexCount, instanceCount, firstIndex, firstVertex, firstInstance); _renderer.New<DrawIndexedCommand>()->Set(indexCount, instanceCount, firstIndex, firstVertex, firstInstance);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void DrawIndexedIndirect(BufferRange indirectBuffer) public unsafe void DrawIndexedIndirect(BufferRange indirectBuffer)
{ {
_renderer.New<DrawIndexedIndirectCommand>().Set(indirectBuffer); _renderer.New<DrawIndexedIndirectCommand>()->Set(indirectBuffer);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) public unsafe void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
{ {
_renderer.New<DrawIndexedIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride); _renderer.New<DrawIndexedIndirectCountCommand>()->Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void DrawIndirect(BufferRange indirectBuffer) public unsafe void DrawIndirect(BufferRange indirectBuffer)
{ {
_renderer.New<DrawIndirectCommand>().Set(indirectBuffer); _renderer.New<DrawIndirectCommand>()->Set(indirectBuffer);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) public unsafe void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
{ {
_renderer.New<DrawIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride); _renderer.New<DrawIndirectCountCommand>()->Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion) public unsafe void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
{ {
_renderer.New<DrawTextureCommand>().Set(Ref(texture), Ref(sampler), srcRegion, dstRegion); _renderer.New<DrawTextureCommand>()->Set(Ref(texture), Ref(sampler), srcRegion, dstRegion);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void EndHostConditionalRendering() public unsafe void EndHostConditionalRendering()
{ {
_renderer.New<EndHostConditionalRenderingCommand>(); _renderer.New<EndHostConditionalRenderingCommand>();
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void EndTransformFeedback() public unsafe void EndTransformFeedback()
{ {
_renderer.New<EndTransformFeedbackCommand>(); _renderer.New<EndTransformFeedbackCommand>();
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetAlphaTest(bool enable, float reference, CompareOp op) public unsafe void SetAlphaTest(bool enable, float reference, CompareOp op)
{ {
_renderer.New<SetAlphaTestCommand>().Set(enable, reference, op); _renderer.New<SetAlphaTestCommand>()->Set(enable, reference, op);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetBlendState(AdvancedBlendDescriptor blend) public unsafe void SetBlendState(AdvancedBlendDescriptor blend)
{ {
_renderer.New<SetBlendStateAdvancedCommand>().Set(blend); _renderer.New<SetBlendStateAdvancedCommand>()->Set(blend);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetBlendState(int index, BlendDescriptor blend) public unsafe void SetBlendState(int index, BlendDescriptor blend)
{ {
_renderer.New<SetBlendStateCommand>().Set(index, blend); _renderer.New<SetBlendStateCommand>()->Set(index, blend);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp) public unsafe void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
{ {
_renderer.New<SetDepthBiasCommand>().Set(enables, factor, units, clamp); _renderer.New<SetDepthBiasCommand>()->Set(enables, factor, units, clamp);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetDepthClamp(bool clamp) public unsafe void SetDepthClamp(bool clamp)
{ {
_renderer.New<SetDepthClampCommand>().Set(clamp); _renderer.New<SetDepthClampCommand>()->Set(clamp);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetDepthMode(DepthMode mode) public unsafe void SetDepthMode(DepthMode mode)
{ {
_renderer.New<SetDepthModeCommand>().Set(mode); _renderer.New<SetDepthModeCommand>()->Set(mode);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetDepthTest(DepthTestDescriptor depthTest) public unsafe void SetDepthTest(DepthTestDescriptor depthTest)
{ {
_renderer.New<SetDepthTestCommand>().Set(depthTest); _renderer.New<SetDepthTestCommand>()->Set(depthTest);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetFaceCulling(bool enable, Face face) public unsafe void SetFaceCulling(bool enable, Face face)
{ {
_renderer.New<SetFaceCullingCommand>().Set(enable, face); _renderer.New<SetFaceCullingCommand>()->Set(enable, face);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetFrontFace(FrontFace frontFace) public unsafe void SetFrontFace(FrontFace frontFace)
{ {
_renderer.New<SetFrontFaceCommand>().Set(frontFace); _renderer.New<SetFrontFaceCommand>()->Set(frontFace);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImage(ShaderStage stage, int binding, ITexture texture) public unsafe void SetImage(ShaderStage stage, int binding, ITexture texture)
{ {
_renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture)); _renderer.New<SetImageCommand>()->Set(stage, binding, Ref(texture));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImageArray(ShaderStage stage, int binding, IImageArray array) public unsafe void SetImageArray(ShaderStage stage, int binding, IImageArray array)
{ {
_renderer.New<SetImageArrayCommand>().Set(stage, binding, Ref(array)); _renderer.New<SetImageArrayCommand>()->Set(stage, binding, Ref(array));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) public unsafe void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
{ {
_renderer.New<SetImageArraySeparateCommand>().Set(stage, setIndex, Ref(array)); _renderer.New<SetImageArraySeparateCommand>()->Set(stage, setIndex, Ref(array));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetIndexBuffer(BufferRange buffer, IndexType type) public unsafe void SetIndexBuffer(BufferRange buffer, IndexType type)
{ {
_renderer.New<SetIndexBufferCommand>().Set(buffer, type); _renderer.New<SetIndexBufferCommand>()->Set(buffer, type);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetLineParameters(float width, bool smooth) public unsafe void SetLineParameters(float width, bool smooth)
{ {
_renderer.New<SetLineParametersCommand>().Set(width, smooth); _renderer.New<SetLineParametersCommand>()->Set(width, smooth);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetLogicOpState(bool enable, LogicalOp op) public unsafe void SetLogicOpState(bool enable, LogicalOp op)
{ {
_renderer.New<SetLogicOpStateCommand>().Set(enable, op); _renderer.New<SetLogicOpStateCommand>()->Set(enable, op);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetMultisampleState(MultisampleDescriptor multisample) public unsafe void SetMultisampleState(MultisampleDescriptor multisample)
{ {
_renderer.New<SetMultisampleStateCommand>().Set(multisample); _renderer.New<SetMultisampleStateCommand>()->Set(multisample);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel) public unsafe void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel)
{ {
_renderer.New<SetPatchParametersCommand>().Set(vertices, defaultOuterLevel, defaultInnerLevel); _renderer.New<SetPatchParametersCommand>()->Set(vertices, defaultOuterLevel, defaultInnerLevel);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin) public unsafe void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
{ {
_renderer.New<SetPointParametersCommand>().Set(size, isProgramPointSize, enablePointSprite, origin); _renderer.New<SetPointParametersCommand>()->Set(size, isProgramPointSize, enablePointSprite, origin);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetPolygonMode(PolygonMode frontMode, PolygonMode backMode) public unsafe void SetPolygonMode(PolygonMode frontMode, PolygonMode backMode)
{ {
_renderer.New<SetPolygonModeCommand>().Set(frontMode, backMode); _renderer.New<SetPolygonModeCommand>()->Set(frontMode, backMode);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetPrimitiveRestart(bool enable, int index) public unsafe void SetPrimitiveRestart(bool enable, int index)
{ {
_renderer.New<SetPrimitiveRestartCommand>().Set(enable, index); _renderer.New<SetPrimitiveRestartCommand>()->Set(enable, index);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetPrimitiveTopology(PrimitiveTopology topology) public unsafe void SetPrimitiveTopology(PrimitiveTopology topology)
{ {
_renderer.New<SetPrimitiveTopologyCommand>().Set(topology); _renderer.New<SetPrimitiveTopologyCommand>()->Set(topology);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetProgram(IProgram program) public unsafe void SetProgram(IProgram program)
{ {
_renderer.New<SetProgramCommand>().Set(Ref(program)); _renderer.New<SetProgramCommand>()->Set(Ref(program));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetRasterizerDiscard(bool discard) public unsafe void SetRasterizerDiscard(bool discard)
{ {
_renderer.New<SetRasterizerDiscardCommand>().Set(discard); _renderer.New<SetRasterizerDiscardCommand>()->Set(discard);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask) public unsafe void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
{ {
_renderer.New<SetRenderTargetColorMasksCommand>().Set(_renderer.CopySpan(componentMask)); _renderer.New<SetRenderTargetColorMasksCommand>()->Set(_renderer.CopySpan(componentMask));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetRenderTargets(ITexture[] colors, ITexture depthStencil) public unsafe void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
{ {
_renderer.New<SetRenderTargetsCommand>().Set(Ref(colors.ToArray()), Ref(depthStencil)); _renderer.New<SetRenderTargetsCommand>()->Set(Ref(colors.ToArray()), Ref(depthStencil));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetScissors(ReadOnlySpan<Rectangle<int>> scissors) public unsafe void SetScissors(ReadOnlySpan<Rectangle<int>> scissors)
{ {
_renderer.New<SetScissorsCommand>().Set(_renderer.CopySpan(scissors)); _renderer.New<SetScissorsCommand>()->Set(_renderer.CopySpan(scissors));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetStencilTest(StencilTestDescriptor stencilTest) public unsafe void SetStencilTest(StencilTestDescriptor stencilTest)
{ {
_renderer.New<SetStencilTestCommand>().Set(stencilTest); _renderer.New<SetStencilTestCommand>()->Set(stencilTest);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers) public unsafe void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
_renderer.New<SetStorageBuffersCommand>().Set(_renderer.CopySpan(buffers)); _renderer.New<SetStorageBuffersCommand>()->Set(_renderer.CopySpan(buffers));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler) public unsafe void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{ {
_renderer.New<SetTextureAndSamplerCommand>().Set(stage, binding, Ref(texture), Ref(sampler)); _renderer.New<SetTextureAndSamplerCommand>()->Set(stage, binding, Ref(texture), Ref(sampler));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array) public unsafe void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
{ {
_renderer.New<SetTextureArrayCommand>().Set(stage, binding, Ref(array)); _renderer.New<SetTextureArrayCommand>()->Set(stage, binding, Ref(array));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) public unsafe void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
{ {
_renderer.New<SetTextureArraySeparateCommand>().Set(stage, setIndex, Ref(array)); _renderer.New<SetTextureArraySeparateCommand>()->Set(stage, setIndex, Ref(array));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers) public unsafe void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
{ {
_renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers)); _renderer.New<SetTransformFeedbackBuffersCommand>()->Set(_renderer.CopySpan(buffers));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers) public unsafe void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
_renderer.New<SetUniformBuffersCommand>().Set(_renderer.CopySpan(buffers)); _renderer.New<SetUniformBuffersCommand>()->Set(_renderer.CopySpan(buffers));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetUserClipDistance(int index, bool enableClip) public unsafe void SetUserClipDistance(int index, bool enableClip)
{ {
_renderer.New<SetUserClipDistanceCommand>().Set(index, enableClip); _renderer.New<SetUserClipDistanceCommand>()->Set(index, enableClip);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs) public unsafe void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
{ {
_renderer.New<SetVertexAttribsCommand>().Set(_renderer.CopySpan(vertexAttribs)); _renderer.New<SetVertexAttribsCommand>()->Set(_renderer.CopySpan(vertexAttribs));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers) public unsafe void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
{ {
_renderer.New<SetVertexBuffersCommand>().Set(_renderer.CopySpan(vertexBuffers)); _renderer.New<SetVertexBuffersCommand>()->Set(_renderer.CopySpan(vertexBuffers));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetViewports(ReadOnlySpan<Viewport> viewports) public unsafe void SetViewports(ReadOnlySpan<Viewport> viewports)
{ {
_renderer.New<SetViewportsCommand>().Set(_renderer.CopySpan(viewports)); _renderer.New<SetViewportsCommand>()->Set(_renderer.CopySpan(viewports));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void TextureBarrier() public unsafe void TextureBarrier()
{ {
_renderer.New<TextureBarrierCommand>(); _renderer.New<TextureBarrierCommand>();
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void TextureBarrierTiled() public unsafe void TextureBarrierTiled()
{ {
_renderer.New<TextureBarrierTiledCommand>(); _renderer.New<TextureBarrierTiledCommand>();
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) public unsafe bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual)
{ {
ThreadedCounterEvent evt = value as ThreadedCounterEvent; ThreadedCounterEvent evt = value as ThreadedCounterEvent;
if (evt != null) if (evt != null)
@ -369,20 +369,20 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return false; return false;
} }
_renderer.New<TryHostConditionalRenderingCommand>().Set(Ref(evt), compare, isEqual); _renderer.New<TryHostConditionalRenderingCommand>()->Set(Ref(evt), compare, isEqual);
_renderer.QueueCommand(); _renderer.QueueCommand();
return true; return true;
} }
} }
_renderer.New<TryHostConditionalRenderingFlushCommand>().Set(Ref(evt), Ref<ThreadedCounterEvent>(null), isEqual); _renderer.New<TryHostConditionalRenderingFlushCommand>()->Set(Ref(evt), Ref<ThreadedCounterEvent>(null), isEqual);
_renderer.QueueCommand(); _renderer.QueueCommand();
return false; return false;
} }
public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual) public unsafe bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
{ {
_renderer.New<TryHostConditionalRenderingFlushCommand>().Set(Ref(value as ThreadedCounterEvent), Ref(compare as ThreadedCounterEvent), isEqual); _renderer.New<TryHostConditionalRenderingFlushCommand>()->Set(Ref(value as ThreadedCounterEvent), Ref(compare as ThreadedCounterEvent), isEqual);
_renderer.QueueCommand(); _renderer.QueueCommand();
return false; return false;
} }

View file

@ -167,7 +167,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return new TableRef<T>(this, reference); return new TableRef<T>(this, reference);
} }
internal ref T New<T>() where T : struct internal unsafe T* New<T>() where T : unmanaged, IGALCommand
{ {
while (_producerPtr == (Volatile.Read(ref _consumerPtr) + QueueCount - 1) % QueueCount) while (_producerPtr == (Volatile.Read(ref _consumerPtr) + QueueCount - 1) % QueueCount)
{ {
@ -183,11 +183,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_producerPtr = (_producerPtr + 1) % QueueCount; _producerPtr = (_producerPtr + 1) % QueueCount;
Span<byte> memory = new(_commandQueue, taken * _elementSize, _elementSize); Span<byte> memory = new(_commandQueue, taken * _elementSize, _elementSize);
ref T result = ref Unsafe.As<byte, T>(ref MemoryMarshal.GetReference(memory)); T* result = (T*)Unsafe.AsPointer(ref memory.GetPinnableReference());
// ref T result = ref Unsafe.As<byte, T>(ref MemoryMarshal.GetReference(memory));
memory[^1] = (byte)((IGALCommand)result).CommandType; memory[^1] = (byte)(result)->CommandType;
return ref result; return result;
} }
internal int AddTableRef(object obj) internal int AddTableRef(object obj)
@ -251,12 +252,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return Thread.CurrentThread == _gpuThread; return Thread.CurrentThread == _gpuThread;
} }
public void BackgroundContextAction(Action action, bool alwaysBackground = false) public unsafe void BackgroundContextAction(Action action, bool alwaysBackground = false)
{ {
if (IsGpuThread() && !alwaysBackground) if (IsGpuThread() && !alwaysBackground)
{ {
// The action must be performed on the render thread. // The action must be performed on the render thread.
New<ActionCommand>().Set(Ref(action)); New<ActionCommand>()->Set(Ref(action));
InvokeCommand(); InvokeCommand();
} }
else else
@ -265,43 +266,43 @@ namespace Ryujinx.Graphics.GAL.Multithreading
} }
} }
public BufferHandle CreateBuffer(int size, BufferAccess access) public unsafe BufferHandle CreateBuffer(int size, BufferAccess access)
{ {
BufferHandle handle = Buffers.CreateBufferHandle(); BufferHandle handle = Buffers.CreateBufferHandle();
New<CreateBufferAccessCommand>().Set(handle, size, access); New<CreateBufferAccessCommand>()->Set(handle, size, access);
QueueCommand(); QueueCommand();
return handle; return handle;
} }
public BufferHandle CreateBuffer(nint pointer, int size) public unsafe BufferHandle CreateBuffer(nint pointer, int size)
{ {
BufferHandle handle = Buffers.CreateBufferHandle(); BufferHandle handle = Buffers.CreateBufferHandle();
New<CreateHostBufferCommand>().Set(handle, pointer, size); New<CreateHostBufferCommand>()->Set(handle, pointer, size);
QueueCommand(); QueueCommand();
return handle; return handle;
} }
public BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers) public unsafe BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers)
{ {
BufferHandle handle = Buffers.CreateBufferHandle(); BufferHandle handle = Buffers.CreateBufferHandle();
New<CreateBufferSparseCommand>().Set(handle, CopySpan(storageBuffers)); New<CreateBufferSparseCommand>()->Set(handle, CopySpan(storageBuffers));
QueueCommand(); QueueCommand();
return handle; return handle;
} }
public IImageArray CreateImageArray(int size, bool isBuffer) public unsafe IImageArray CreateImageArray(int size, bool isBuffer)
{ {
ThreadedImageArray imageArray = new(this); ThreadedImageArray imageArray = new(this);
New<CreateImageArrayCommand>().Set(Ref(imageArray), size, isBuffer); New<CreateImageArrayCommand>()->Set(Ref(imageArray), size, isBuffer);
QueueCommand(); QueueCommand();
return imageArray; return imageArray;
} }
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) public unsafe IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
{ {
ThreadedProgram program = new(this); ThreadedProgram program = new(this);
@ -311,34 +312,34 @@ namespace Ryujinx.Graphics.GAL.Multithreading
ProgramCount++; ProgramCount++;
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request)); New<CreateProgramCommand>()->Set(Ref((IProgramRequest)request));
QueueCommand(); QueueCommand();
return program; return program;
} }
public ISampler CreateSampler(SamplerCreateInfo info) public unsafe ISampler CreateSampler(SamplerCreateInfo info)
{ {
ThreadedSampler sampler = new(this); ThreadedSampler sampler = new(this);
New<CreateSamplerCommand>().Set(Ref(sampler), info); New<CreateSamplerCommand>()->Set(Ref(sampler), info);
QueueCommand(); QueueCommand();
return sampler; return sampler;
} }
public void CreateSync(ulong id, bool strict) public unsafe void CreateSync(ulong id, bool strict)
{ {
Sync.CreateSyncHandle(id); Sync.CreateSyncHandle(id);
New<CreateSyncCommand>().Set(id, strict); New<CreateSyncCommand>()->Set(id, strict);
QueueCommand(); QueueCommand();
} }
public ITexture CreateTexture(TextureCreateInfo info) public unsafe ITexture CreateTexture(TextureCreateInfo info)
{ {
if (IsGpuThread()) if (IsGpuThread())
{ {
ThreadedTexture texture = new(this, info); ThreadedTexture texture = new(this, info);
New<CreateTextureCommand>().Set(Ref(texture), info); New<CreateTextureCommand>()->Set(Ref(texture), info);
QueueCommand(); QueueCommand();
return texture; return texture;
@ -353,27 +354,27 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return texture; return texture;
} }
} }
public ITextureArray CreateTextureArray(int size, bool isBuffer) public unsafe ITextureArray CreateTextureArray(int size, bool isBuffer)
{ {
ThreadedTextureArray textureArray = new(this); ThreadedTextureArray textureArray = new(this);
New<CreateTextureArrayCommand>().Set(Ref(textureArray), size, isBuffer); New<CreateTextureArrayCommand>()->Set(Ref(textureArray), size, isBuffer);
QueueCommand(); QueueCommand();
return textureArray; return textureArray;
} }
public void DeleteBuffer(BufferHandle buffer) public unsafe void DeleteBuffer(BufferHandle buffer)
{ {
New<BufferDisposeCommand>().Set(buffer); New<BufferDisposeCommand>()->Set(buffer);
QueueCommand(); QueueCommand();
} }
public PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size) public unsafe PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
{ {
if (IsGpuThread()) if (IsGpuThread())
{ {
ResultBox<PinnedSpan<byte>> box = new(); ResultBox<PinnedSpan<byte>> box = new();
New<BufferGetDataCommand>().Set(buffer, offset, size, Ref(box)); New<BufferGetDataCommand>()->Set(buffer, offset, size, Ref(box));
InvokeCommand(); InvokeCommand();
return box.Result; return box.Result;
@ -384,10 +385,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
} }
} }
public Capabilities GetCapabilities() public unsafe Capabilities GetCapabilities()
{ {
ResultBox<Capabilities> box = new(); ResultBox<Capabilities> box = new();
New<GetCapabilitiesCommand>().Set(Ref(box)); New<GetCapabilitiesCommand>()->Set(Ref(box));
InvokeCommand(); InvokeCommand();
return box.Result; return box.Result;
@ -412,29 +413,29 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_baseRenderer.Initialize(logLevel); _baseRenderer.Initialize(logLevel);
} }
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info) public unsafe IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
{ {
ThreadedProgram program = new(this); ThreadedProgram program = new(this);
BinaryProgramRequest request = new(program, programBinary, hasFragmentShader, info); BinaryProgramRequest request = new(program, programBinary, hasFragmentShader, info);
Programs.Add(request); Programs.Add(request);
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request)); New<CreateProgramCommand>()->Set(Ref((IProgramRequest)request));
QueueCommand(); QueueCommand();
return program; return program;
} }
public void PreFrame() public unsafe void PreFrame()
{ {
New<PreFrameCommand>(); New<PreFrameCommand>();
QueueCommand(); QueueCommand();
} }
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved) public unsafe ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved)
{ {
ThreadedCounterEvent evt = new(this, type, _lastSampleCounterClear); ThreadedCounterEvent evt = new(this, type, _lastSampleCounterClear);
New<ReportCounterCommand>().Set(Ref(evt), type, Ref(resultHandler), divisor, hostReserved); New<ReportCounterCommand>()->Set(Ref(evt), type, Ref(resultHandler), divisor, hostReserved);
QueueCommand(); QueueCommand();
if (type == CounterType.SamplesPassed) if (type == CounterType.SamplesPassed)
@ -445,9 +446,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return evt; return evt;
} }
public void ResetCounter(CounterType type) public unsafe void ResetCounter(CounterType type)
{ {
New<ResetCounterCommand>().Set(type); New<ResetCounterCommand>()->Set(type);
QueueCommand(); QueueCommand();
_lastSampleCounterClear = true; _lastSampleCounterClear = true;
} }
@ -457,13 +458,13 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_baseRenderer.Screenshot(); _baseRenderer.Screenshot();
} }
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data) public unsafe void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
{ {
New<BufferSetDataCommand>().Set(buffer, offset, CopySpan(data)); New<BufferSetDataCommand>()->Set(buffer, offset, CopySpan(data));
QueueCommand(); QueueCommand();
} }
public void UpdateCounters() public unsafe void UpdateCounters()
{ {
New<UpdateCountersCommand>(); New<UpdateCountersCommand>();
QueueCommand(); QueueCommand();

View file

@ -17,13 +17,13 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_impl = impl; _impl = impl;
} }
public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback) public unsafe void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
{ {
// If there's already a frame in the pipeline, wait for it to be presented first. // If there's already a frame in the pipeline, wait for it to be presented first.
// This is a multithread rate limit - we can't be more than one frame behind the command queue. // This is a multithread rate limit - we can't be more than one frame behind the command queue.
_renderer.WaitForFrame(); _renderer.WaitForFrame();
_renderer.New<WindowPresentCommand>().Set(new TableRef<ThreadedTexture>(_renderer, texture as ThreadedTexture), crop, new TableRef<Action>(_renderer, swapBuffersCallback)); _renderer.New<WindowPresentCommand>()->Set(new TableRef<ThreadedTexture>(_renderer, texture as ThreadedTexture), crop, new TableRef<Action>(_renderer, swapBuffersCallback));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }

View file

@ -49,6 +49,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Cache of GPU counters. /// Cache of GPU counters.
/// </summary> /// </summary>
internal CounterCache CounterCache { get; } internal CounterCache CounterCache { get; }
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
private WriteCallback _write;
private WriteCallback _writeTrackedResource;
private WriteCallback _writeUntracked;
/// <summary> /// <summary>
/// Creates a new instance of the GPU memory manager. /// Creates a new instance of the GPU memory manager.
@ -58,6 +64,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
internal MemoryManager(PhysicalMemory physicalMemory, ulong cpuMemorySize) internal MemoryManager(PhysicalMemory physicalMemory, ulong cpuMemorySize)
{ {
Physical = physicalMemory; Physical = physicalMemory;
_write = physicalMemory.Write;
_writeTrackedResource = physicalMemory.WriteTrackedResource;
_writeUntracked = physicalMemory.WriteUntracked;
VirtualRangeCache = new VirtualRangeCache(this); VirtualRangeCache = new VirtualRangeCache(this);
CounterCache = new CounterCache(); CounterCache = new CounterCache();
_pageTable = new ulong[PtLvl0Size][]; _pageTable = new ulong[PtLvl0Size][];
@ -269,7 +278,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="data">The data to be written</param> /// <param name="data">The data to be written</param>
public void Write(ulong va, ReadOnlySpan<byte> data) public void Write(ulong va, ReadOnlySpan<byte> data)
{ {
WriteImpl(va, data, Physical.Write); WriteImpl(va, data, _write);
} }
/// <summary> /// <summary>
@ -279,7 +288,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="data">The data to be written</param> /// <param name="data">The data to be written</param>
public void WriteTrackedResource(ulong va, ReadOnlySpan<byte> data) public void WriteTrackedResource(ulong va, ReadOnlySpan<byte> data)
{ {
WriteImpl(va, data, Physical.WriteTrackedResource); WriteImpl(va, data, _writeTrackedResource);
} }
/// <summary> /// <summary>
@ -289,11 +298,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="data">The data to be written</param> /// <param name="data">The data to be written</param>
public void WriteUntracked(ulong va, ReadOnlySpan<byte> data) public void WriteUntracked(ulong va, ReadOnlySpan<byte> data)
{ {
WriteImpl(va, data, Physical.WriteUntracked); WriteImpl(va, data, _writeUntracked);
} }
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
/// <summary> /// <summary>
/// Writes data to possibly non-contiguous GPU mapped memory. /// Writes data to possibly non-contiguous GPU mapped memory.
/// </summary> /// </summary>

View file

@ -123,15 +123,15 @@ namespace Ryujinx.HLE.HOS.Services.Nv
return NvResult.InvalidSize; return NvResult.InvalidSize;
} }
byte[] outputData = new byte[outputDataSize]; if (!context.Memory.TryReadUnsafe(inputDataPosition, (int)inputDataSize, out arguments))
{
byte[] temp = new byte[inputDataSize]; arguments = new byte[inputDataSize];
context.Memory.Read(inputDataPosition, arguments);
context.Memory.Read(inputDataPosition, temp); }
else
Buffer.BlockCopy(temp, 0, outputData, 0, temp.Length); {
arguments = arguments.ToArray();
arguments = new Span<byte>(outputData); }
} }
else if (isWrite) else if (isWrite)
{ {
@ -470,12 +470,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv
(ulong inlineInBufferPosition, ulong inlineInBufferSize) = context.Request.GetBufferType0x21(1); (ulong inlineInBufferPosition, ulong inlineInBufferSize) = context.Request.GetBufferType0x21(1);
errorCode = GetIoctlArgument(context, ioctlCommand, out Span<byte> arguments); errorCode = GetIoctlArgument(context, ioctlCommand, out Span<byte> arguments);
byte[] temp = new byte[inlineInBufferSize]; if (!context.Memory.TryReadUnsafe(inlineInBufferPosition, (int)inlineInBufferSize, out Span<byte> inlineInBuffer))
{
context.Memory.Read(inlineInBufferPosition, temp); inlineInBuffer = new byte[inlineInBufferSize];
context.Memory.Read(inlineInBufferPosition, inlineInBuffer);
Span<byte> inlineInBuffer = new(temp); }
if (errorCode == NvResult.Success) if (errorCode == NvResult.Success)
{ {
@ -519,12 +519,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv
(ulong inlineOutBufferPosition, ulong inlineOutBufferSize) = context.Request.GetBufferType0x22(1); (ulong inlineOutBufferPosition, ulong inlineOutBufferSize) = context.Request.GetBufferType0x22(1);
errorCode = GetIoctlArgument(context, ioctlCommand, out Span<byte> arguments); errorCode = GetIoctlArgument(context, ioctlCommand, out Span<byte> arguments);
byte[] temp = new byte[inlineOutBufferSize]; if (!context.Memory.TryReadUnsafe(inlineOutBufferPosition, (int)inlineOutBufferSize, out Span<byte> inlineOutBuffer))
{
context.Memory.Read(inlineOutBufferPosition, temp); inlineOutBuffer = new byte[inlineOutBufferSize];
context.Memory.Read(inlineOutBufferPosition, inlineOutBuffer);
Span<byte> inlineOutBuffer = new(temp); }
if (errorCode == NvResult.Success) if (errorCode == NvResult.Success)
{ {

View file

@ -60,6 +60,15 @@ namespace Ryujinx.Memory
/// <param name="data">Span to store the data being read into</param> /// <param name="data">Span to store the data being read into</param>
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception> /// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
void Read(ulong va, Span<byte> data); void Read(ulong va, Span<byte> data);
/// <summary>
/// Gets a span of CPU mapped memory.
/// </summary>
/// <param name="va">Virtual address of the data in memory</param>
/// <param name="length">Length of the data in memory</param>
/// <param name="data">Span that references the data being read</param>
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
bool TryReadUnsafe(ulong va, int length, out Span<byte> data);
/// <summary> /// <summary>
/// Writes data to CPU mapped memory. /// Writes data to CPU mapped memory.

View file

@ -159,6 +159,13 @@ namespace Ryujinx.Memory
AssertValidAddressAndSize(va, data.Length); AssertValidAddressAndSize(va, data.Length);
if (IsContiguousAndMapped(va, data.Length))
{
nuint pa = TranslateVirtualAddressChecked(va);
GetPhysicalAddressSpan(pa, data.Length).CopyTo(data);
}
int offset = 0, size; int offset = 0, size;
if ((va & PageMask) != 0) if ((va & PageMask) != 0)
@ -182,6 +189,28 @@ namespace Ryujinx.Memory
} }
} }
public virtual bool TryReadUnsafe(ulong va, int length, out Span<byte> data)
{
if (!IsContiguousAndMapped(va, length))
{
data = default;
return false;
}
if (length == 0)
{
data = Span<byte>.Empty;
return true;
}
AssertValidAddressAndSize(va, length);
nuint pa = TranslateVirtualAddressChecked(va);
data = GetPhysicalAddressSpan(pa, length);
return true;
}
public virtual T ReadTracked<T>(ulong va) where T : unmanaged public virtual T ReadTracked<T>(ulong va) where T : unmanaged
{ {
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), false); SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), false);

View file

@ -42,6 +42,11 @@ namespace Ryujinx.Tests.Memory
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public bool TryReadUnsafe(ulong va, int lenfth, out Span<byte> data)
{
throw new NotImplementedException();
}
public void Write<T>(ulong va, T value) where T : unmanaged public void Write<T>(ulong va, T value) where T : unmanaged
{ {