diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs index a2901baf0..d46222f83 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs @@ -99,7 +99,6 @@ namespace Ryujinx.Audio.Renderer.Server break; case CommandType.BiquadFilterFloatCoeff: throw new NotImplementedException(); - break; case CommandType.Mix: _mixCommandPool.Release((MixCommand)command); break; @@ -159,7 +158,6 @@ namespace Ryujinx.Audio.Renderer.Server break; case CommandType.MultiTapBiquadFilterFloatCoeff: throw new NotImplementedException(); - break; case CommandType.CaptureBuffer: _captureBufferCommandPool.Release((CaptureBufferCommand)command); break; @@ -171,25 +169,19 @@ namespace Ryujinx.Audio.Renderer.Server break; case CommandType.BiquadFilterAndMixFloatCoeff: throw new NotImplementedException(); - break; case CommandType.MultiTapBiquadFilterAndMix: _multiTapBiquadFilterAndMixCommandPool.Release((MultiTapBiquadFilterAndMixCommand)command); break; case CommandType.MultiTapBiquadFilterAndMixFloatCoef: throw new NotImplementedException(); - break; case CommandType.AuxiliaryBufferGrouped: throw new NotImplementedException(); - break; case CommandType.FillMixBuffer: throw new NotImplementedException(); - break; case CommandType.BiquadFilterCrossFade: throw new NotImplementedException(); - break; case CommandType.MultiTapBiquadFilterCrossFade: throw new NotImplementedException(); - break; case CommandType.FillBuffer: _fillBufferCommandPool.Release((FillBufferCommand)command); break; diff --git a/src/Ryujinx.Common/Pools/ObjectPool.cs b/src/Ryujinx.Common/Pools/ObjectPool.cs index ad56a04a2..de8534332 100644 --- a/src/Ryujinx.Common/Pools/ObjectPool.cs +++ b/src/Ryujinx.Common/Pools/ObjectPool.cs @@ -7,11 +7,11 @@ namespace Ryujinx.Common where T : class { private int _size = size; - private readonly ConcurrentStack _items = new(); + private readonly ConcurrentBag _items = new(); public T Allocate() { - bool success = _items.TryPop(out T instance); + bool success = _items.TryTake(out T instance); if (!success) { @@ -25,7 +25,7 @@ namespace Ryujinx.Common { if (_size < 0 || _items.Count < _size) { - _items.Push(obj); + _items.Add(obj); } } diff --git a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs index decb0e4e3..dd5547274 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs @@ -151,6 +151,11 @@ namespace Ryujinx.Cpu.AppleHv } } + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } + public override void Write(ulong va, ReadOnlySpan data) { try diff --git a/src/Ryujinx.Cpu/Jit/MemoryManager.cs b/src/Ryujinx.Cpu/Jit/MemoryManager.cs index 9e5d29cca..8cc786a83 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -174,6 +174,11 @@ namespace Ryujinx.Cpu.Jit } } } + + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } public override void Write(ulong va, ReadOnlySpan data) { diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index e27a2e173..e2d8f5efb 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -151,6 +151,11 @@ namespace Ryujinx.Cpu.Jit return default; } } + + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } public override T ReadTracked(ulong va) { diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs index 9ae4ca5a9..0ad96c6ae 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs @@ -227,6 +227,11 @@ namespace Ryujinx.Cpu.Jit } } } + + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) { diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedCounterEvent.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedCounterEvent.cs index 15db2b9fa..557c2ae04 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedCounterEvent.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedCounterEvent.cs @@ -29,9 +29,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources return new TableRef(_renderer, reference); } - public void Dispose() + public unsafe void Dispose() { - _renderer.New().Set(Ref(this)); + _renderer.New()->Set(Ref(this)); _renderer.QueueCommand(); } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs index 82587c189..a415dbbf0 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs @@ -21,15 +21,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources return new TableRef(_renderer, reference); } - public void Dispose() + public unsafe void Dispose() { - _renderer.New().Set(Ref(this)); + _renderer.New()->Set(Ref(this)); _renderer.QueueCommand(); } - public void SetImages(int index, ITexture[] images) + public unsafe void SetImages(int index, ITexture[] images) { - _renderer.New().Set(Ref(this), index, Ref(images)); + _renderer.New()->Set(Ref(this), index, Ref(images)); _renderer.QueueCommand(); } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedProgram.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedProgram.cs index d5a22f669..9573bbaac 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedProgram.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedProgram.cs @@ -21,25 +21,25 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources return new TableRef(_renderer, reference); } - public void Dispose() + public unsafe void Dispose() { - _renderer.New().Set(Ref(this)); + _renderer.New()->Set(Ref(this)); _renderer.QueueCommand(); } - public byte[] GetBinary() + public unsafe byte[] GetBinary() { ResultBox box = new(); - _renderer.New().Set(Ref(this), Ref(box)); + _renderer.New()->Set(Ref(this), Ref(box)); _renderer.InvokeCommand(); return box.Result; } - public ProgramLinkStatus CheckProgramLink(bool blocking) + public unsafe ProgramLinkStatus CheckProgramLink(bool blocking) { ResultBox box = new(); - _renderer.New().Set(Ref(this), blocking, Ref(box)); + _renderer.New()->Set(Ref(this), blocking, Ref(box)); _renderer.InvokeCommand(); return box.Result; diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedSampler.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedSampler.cs index ae3d993a3..8dc9647ab 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedSampler.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedSampler.cs @@ -13,9 +13,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources _renderer = renderer; } - public void Dispose() + public unsafe void Dispose() { - _renderer.New().Set(new TableRef(_renderer, this)); + _renderer.New()->Set(new TableRef(_renderer, this)); _renderer.QueueCommand(); } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs index fa71d20b3..e33b58745 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs @@ -28,25 +28,25 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources return new TableRef(_renderer, reference); } - public void CopyTo(ITexture destination, int firstLayer, int firstLevel) + public unsafe void CopyTo(ITexture destination, int firstLayer, int firstLevel) { - _renderer.New().Set(Ref(this), Ref((ThreadedTexture)destination), firstLayer, firstLevel); + _renderer.New()->Set(Ref(this), Ref((ThreadedTexture)destination), firstLayer, firstLevel); _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().Set(Ref(this), Ref((ThreadedTexture)destination), srcLayer, dstLayer, srcLevel, dstLevel); + _renderer.New()->Set(Ref(this), Ref((ThreadedTexture)destination), srcLayer, dstLayer, srcLevel, dstLevel); _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; if (_renderer.IsGpuThread()) { - _renderer.New().Set(Ref(this), Ref(dest), srcRegion, dstRegion, linearFilter); + _renderer.New()->Set(Ref(this), Ref(dest), srcRegion, dstRegion, linearFilter); _renderer.QueueCommand(); } 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); - _renderer.New().Set(Ref(this), Ref(newTex), info, firstLayer, firstLevel); + _renderer.New()->Set(Ref(this), Ref(newTex), info, firstLayer, firstLevel); _renderer.QueueCommand(); return newTex; } - public PinnedSpan GetData() + public unsafe PinnedSpan GetData() { if (_renderer.IsGpuThread()) { ResultBox> box = new(); - _renderer.New().Set(Ref(this), Ref(box)); + _renderer.New()->Set(Ref(this), Ref(box)); _renderer.InvokeCommand(); return box.Result; @@ -86,12 +86,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources } } - public PinnedSpan GetData(int layer, int level) + public unsafe PinnedSpan GetData(int layer, int level) { if (_renderer.IsGpuThread()) { ResultBox> box = new(); - _renderer.New().Set(Ref(this), Ref(box), layer, level); + _renderer.New()->Set(Ref(this), Ref(box), layer, level); _renderer.InvokeCommand(); 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().Set(Ref(this), range, layer, level, stride); + _renderer.New()->Set(Ref(this), range, layer, level, stride); _renderer.QueueCommand(); } /// - public void SetData(MemoryOwner data) + public unsafe void SetData(MemoryOwner data) { - _renderer.New().Set(Ref(this), Ref(data)); + _renderer.New()->Set(Ref(this), Ref(data)); _renderer.QueueCommand(); } /// - public void SetData(MemoryOwner data, int layer, int level) + public unsafe void SetData(MemoryOwner data, int layer, int level) { - _renderer.New().Set(Ref(this), Ref(data), layer, level); + _renderer.New()->Set(Ref(this), Ref(data), layer, level); _renderer.QueueCommand(); } /// - public void SetData(MemoryOwner data, int layer, int level, Rectangle region) + public unsafe void SetData(MemoryOwner data, int layer, int level, Rectangle region) { - _renderer.New().Set(Ref(this), Ref(data), layer, level, region); + _renderer.New()->Set(Ref(this), Ref(data), layer, level, region); _renderer.QueueCommand(); } - public void SetStorage(BufferRange buffer) + public unsafe void SetStorage(BufferRange buffer) { - _renderer.New().Set(Ref(this), buffer); + _renderer.New()->Set(Ref(this), buffer); _renderer.QueueCommand(); } - public void Release() + public unsafe void Release() { - _renderer.New().Set(Ref(this)); + _renderer.New()->Set(Ref(this)); _renderer.QueueCommand(); } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs index 4334c7048..56b0e0d34 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTextureArray.cs @@ -22,21 +22,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources return new TableRef(_renderer, reference); } - public void Dispose() + public unsafe void Dispose() { - _renderer.New().Set(Ref(this)); + _renderer.New()->Set(Ref(this)); _renderer.QueueCommand(); } - public void SetSamplers(int index, ISampler[] samplers) + public unsafe void SetSamplers(int index, ISampler[] samplers) { - _renderer.New().Set(Ref(this), index, Ref(samplers.ToArray())); + _renderer.New()->Set(Ref(this), index, Ref(samplers.ToArray())); _renderer.QueueCommand(); } - public void SetTextures(int index, ITexture[] textures) + public unsafe void SetTextures(int index, ITexture[] textures) { - _renderer.New().Set(Ref(this), index, Ref(textures.ToArray())); + _renderer.New()->Set(Ref(this), index, Ref(textures.ToArray())); _renderer.QueueCommand(); } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs index c999ad789..c0fb6361e 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs @@ -21,343 +21,343 @@ namespace Ryujinx.Graphics.GAL.Multithreading return new TableRef(_renderer, reference); } - public void Barrier() + public unsafe void Barrier() { _renderer.New(); _renderer.QueueCommand(); } - public void BeginTransformFeedback(PrimitiveTopology topology) + public unsafe void BeginTransformFeedback(PrimitiveTopology topology) { - _renderer.New().Set(topology); + _renderer.New()->Set(topology); _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().Set(destination, offset, size, value); + _renderer.New()->Set(destination, offset, size, value); _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().Set(index, layer, layerCount, componentMask, color); + _renderer.New()->Set(index, layer, layerCount, componentMask, color); _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().Set(layer, layerCount, depthValue, depthMask, stencilValue, stencilMask); + _renderer.New()->Set(layer, layerCount, depthValue, depthMask, stencilValue, stencilMask); _renderer.QueueCommand(); } - public void CommandBufferBarrier() + public unsafe void CommandBufferBarrier() { _renderer.New(); _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().Set(source, destination, srcOffset, dstOffset, size); + _renderer.New()->Set(source, destination, srcOffset, dstOffset, size); _renderer.QueueCommand(); } - public void DispatchCompute(int groupsX, int groupsY, int groupsZ) + public unsafe void DispatchCompute(int groupsX, int groupsY, int groupsZ) { - _renderer.New().Set(groupsX, groupsY, groupsZ); + _renderer.New()->Set(groupsX, groupsY, groupsZ); _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().Set(vertexCount, instanceCount, firstVertex, firstInstance); + _renderer.New()->Set(vertexCount, instanceCount, firstVertex, firstInstance); _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().Set(indexCount, instanceCount, firstIndex, firstVertex, firstInstance); + _renderer.New()->Set(indexCount, instanceCount, firstIndex, firstVertex, firstInstance); _renderer.QueueCommand(); } - public void DrawIndexedIndirect(BufferRange indirectBuffer) + public unsafe void DrawIndexedIndirect(BufferRange indirectBuffer) { - _renderer.New().Set(indirectBuffer); + _renderer.New()->Set(indirectBuffer); _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().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride); + _renderer.New()->Set(indirectBuffer, parameterBuffer, maxDrawCount, stride); _renderer.QueueCommand(); } - public void DrawIndirect(BufferRange indirectBuffer) + public unsafe void DrawIndirect(BufferRange indirectBuffer) { - _renderer.New().Set(indirectBuffer); + _renderer.New()->Set(indirectBuffer); _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().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride); + _renderer.New()->Set(indirectBuffer, parameterBuffer, maxDrawCount, stride); _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().Set(Ref(texture), Ref(sampler), srcRegion, dstRegion); + _renderer.New()->Set(Ref(texture), Ref(sampler), srcRegion, dstRegion); _renderer.QueueCommand(); } - public void EndHostConditionalRendering() + public unsafe void EndHostConditionalRendering() { _renderer.New(); _renderer.QueueCommand(); } - public void EndTransformFeedback() + public unsafe void EndTransformFeedback() { _renderer.New(); _renderer.QueueCommand(); } - public void SetAlphaTest(bool enable, float reference, CompareOp op) + public unsafe void SetAlphaTest(bool enable, float reference, CompareOp op) { - _renderer.New().Set(enable, reference, op); + _renderer.New()->Set(enable, reference, op); _renderer.QueueCommand(); } - public void SetBlendState(AdvancedBlendDescriptor blend) + public unsafe void SetBlendState(AdvancedBlendDescriptor blend) { - _renderer.New().Set(blend); + _renderer.New()->Set(blend); _renderer.QueueCommand(); } - public void SetBlendState(int index, BlendDescriptor blend) + public unsafe void SetBlendState(int index, BlendDescriptor blend) { - _renderer.New().Set(index, blend); + _renderer.New()->Set(index, blend); _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().Set(enables, factor, units, clamp); + _renderer.New()->Set(enables, factor, units, clamp); _renderer.QueueCommand(); } - public void SetDepthClamp(bool clamp) + public unsafe void SetDepthClamp(bool clamp) { - _renderer.New().Set(clamp); + _renderer.New()->Set(clamp); _renderer.QueueCommand(); } - public void SetDepthMode(DepthMode mode) + public unsafe void SetDepthMode(DepthMode mode) { - _renderer.New().Set(mode); + _renderer.New()->Set(mode); _renderer.QueueCommand(); } - public void SetDepthTest(DepthTestDescriptor depthTest) + public unsafe void SetDepthTest(DepthTestDescriptor depthTest) { - _renderer.New().Set(depthTest); + _renderer.New()->Set(depthTest); _renderer.QueueCommand(); } - public void SetFaceCulling(bool enable, Face face) + public unsafe void SetFaceCulling(bool enable, Face face) { - _renderer.New().Set(enable, face); + _renderer.New()->Set(enable, face); _renderer.QueueCommand(); } - public void SetFrontFace(FrontFace frontFace) + public unsafe void SetFrontFace(FrontFace frontFace) { - _renderer.New().Set(frontFace); + _renderer.New()->Set(frontFace); _renderer.QueueCommand(); } - public void SetImage(ShaderStage stage, int binding, ITexture texture) + public unsafe void SetImage(ShaderStage stage, int binding, ITexture texture) { - _renderer.New().Set(stage, binding, Ref(texture)); + _renderer.New()->Set(stage, binding, Ref(texture)); _renderer.QueueCommand(); } - public void SetImageArray(ShaderStage stage, int binding, IImageArray array) + public unsafe void SetImageArray(ShaderStage stage, int binding, IImageArray array) { - _renderer.New().Set(stage, binding, Ref(array)); + _renderer.New()->Set(stage, binding, Ref(array)); _renderer.QueueCommand(); } - public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) + public unsafe void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) { - _renderer.New().Set(stage, setIndex, Ref(array)); + _renderer.New()->Set(stage, setIndex, Ref(array)); _renderer.QueueCommand(); } - public void SetIndexBuffer(BufferRange buffer, IndexType type) + public unsafe void SetIndexBuffer(BufferRange buffer, IndexType type) { - _renderer.New().Set(buffer, type); + _renderer.New()->Set(buffer, type); _renderer.QueueCommand(); } - public void SetLineParameters(float width, bool smooth) + public unsafe void SetLineParameters(float width, bool smooth) { - _renderer.New().Set(width, smooth); + _renderer.New()->Set(width, smooth); _renderer.QueueCommand(); } - public void SetLogicOpState(bool enable, LogicalOp op) + public unsafe void SetLogicOpState(bool enable, LogicalOp op) { - _renderer.New().Set(enable, op); + _renderer.New()->Set(enable, op); _renderer.QueueCommand(); } - public void SetMultisampleState(MultisampleDescriptor multisample) + public unsafe void SetMultisampleState(MultisampleDescriptor multisample) { - _renderer.New().Set(multisample); + _renderer.New()->Set(multisample); _renderer.QueueCommand(); } - public void SetPatchParameters(int vertices, ReadOnlySpan defaultOuterLevel, ReadOnlySpan defaultInnerLevel) + public unsafe void SetPatchParameters(int vertices, ReadOnlySpan defaultOuterLevel, ReadOnlySpan defaultInnerLevel) { - _renderer.New().Set(vertices, defaultOuterLevel, defaultInnerLevel); + _renderer.New()->Set(vertices, defaultOuterLevel, defaultInnerLevel); _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().Set(size, isProgramPointSize, enablePointSprite, origin); + _renderer.New()->Set(size, isProgramPointSize, enablePointSprite, origin); _renderer.QueueCommand(); } - public void SetPolygonMode(PolygonMode frontMode, PolygonMode backMode) + public unsafe void SetPolygonMode(PolygonMode frontMode, PolygonMode backMode) { - _renderer.New().Set(frontMode, backMode); + _renderer.New()->Set(frontMode, backMode); _renderer.QueueCommand(); } - public void SetPrimitiveRestart(bool enable, int index) + public unsafe void SetPrimitiveRestart(bool enable, int index) { - _renderer.New().Set(enable, index); + _renderer.New()->Set(enable, index); _renderer.QueueCommand(); } - public void SetPrimitiveTopology(PrimitiveTopology topology) + public unsafe void SetPrimitiveTopology(PrimitiveTopology topology) { - _renderer.New().Set(topology); + _renderer.New()->Set(topology); _renderer.QueueCommand(); } - public void SetProgram(IProgram program) + public unsafe void SetProgram(IProgram program) { - _renderer.New().Set(Ref(program)); + _renderer.New()->Set(Ref(program)); _renderer.QueueCommand(); } - public void SetRasterizerDiscard(bool discard) + public unsafe void SetRasterizerDiscard(bool discard) { - _renderer.New().Set(discard); + _renderer.New()->Set(discard); _renderer.QueueCommand(); } - public void SetRenderTargetColorMasks(ReadOnlySpan componentMask) + public unsafe void SetRenderTargetColorMasks(ReadOnlySpan componentMask) { - _renderer.New().Set(_renderer.CopySpan(componentMask)); + _renderer.New()->Set(_renderer.CopySpan(componentMask)); _renderer.QueueCommand(); } - public void SetRenderTargets(ITexture[] colors, ITexture depthStencil) + public unsafe void SetRenderTargets(ITexture[] colors, ITexture depthStencil) { - _renderer.New().Set(Ref(colors.ToArray()), Ref(depthStencil)); + _renderer.New()->Set(Ref(colors.ToArray()), Ref(depthStencil)); _renderer.QueueCommand(); } - public void SetScissors(ReadOnlySpan> scissors) + public unsafe void SetScissors(ReadOnlySpan> scissors) { - _renderer.New().Set(_renderer.CopySpan(scissors)); + _renderer.New()->Set(_renderer.CopySpan(scissors)); _renderer.QueueCommand(); } - public void SetStencilTest(StencilTestDescriptor stencilTest) + public unsafe void SetStencilTest(StencilTestDescriptor stencilTest) { - _renderer.New().Set(stencilTest); + _renderer.New()->Set(stencilTest); _renderer.QueueCommand(); } - public void SetStorageBuffers(ReadOnlySpan buffers) + public unsafe void SetStorageBuffers(ReadOnlySpan buffers) { - _renderer.New().Set(_renderer.CopySpan(buffers)); + _renderer.New()->Set(_renderer.CopySpan(buffers)); _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().Set(stage, binding, Ref(texture), Ref(sampler)); + _renderer.New()->Set(stage, binding, Ref(texture), Ref(sampler)); _renderer.QueueCommand(); } - public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array) + public unsafe void SetTextureArray(ShaderStage stage, int binding, ITextureArray array) { - _renderer.New().Set(stage, binding, Ref(array)); + _renderer.New()->Set(stage, binding, Ref(array)); _renderer.QueueCommand(); } - public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) + public unsafe void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) { - _renderer.New().Set(stage, setIndex, Ref(array)); + _renderer.New()->Set(stage, setIndex, Ref(array)); _renderer.QueueCommand(); } - public void SetTransformFeedbackBuffers(ReadOnlySpan buffers) + public unsafe void SetTransformFeedbackBuffers(ReadOnlySpan buffers) { - _renderer.New().Set(_renderer.CopySpan(buffers)); + _renderer.New()->Set(_renderer.CopySpan(buffers)); _renderer.QueueCommand(); } - public void SetUniformBuffers(ReadOnlySpan buffers) + public unsafe void SetUniformBuffers(ReadOnlySpan buffers) { - _renderer.New().Set(_renderer.CopySpan(buffers)); + _renderer.New()->Set(_renderer.CopySpan(buffers)); _renderer.QueueCommand(); } - public void SetUserClipDistance(int index, bool enableClip) + public unsafe void SetUserClipDistance(int index, bool enableClip) { - _renderer.New().Set(index, enableClip); + _renderer.New()->Set(index, enableClip); _renderer.QueueCommand(); } - public void SetVertexAttribs(ReadOnlySpan vertexAttribs) + public unsafe void SetVertexAttribs(ReadOnlySpan vertexAttribs) { - _renderer.New().Set(_renderer.CopySpan(vertexAttribs)); + _renderer.New()->Set(_renderer.CopySpan(vertexAttribs)); _renderer.QueueCommand(); } - public void SetVertexBuffers(ReadOnlySpan vertexBuffers) + public unsafe void SetVertexBuffers(ReadOnlySpan vertexBuffers) { - _renderer.New().Set(_renderer.CopySpan(vertexBuffers)); + _renderer.New()->Set(_renderer.CopySpan(vertexBuffers)); _renderer.QueueCommand(); } - public void SetViewports(ReadOnlySpan viewports) + public unsafe void SetViewports(ReadOnlySpan viewports) { - _renderer.New().Set(_renderer.CopySpan(viewports)); + _renderer.New()->Set(_renderer.CopySpan(viewports)); _renderer.QueueCommand(); } - public void TextureBarrier() + public unsafe void TextureBarrier() { _renderer.New(); _renderer.QueueCommand(); } - public void TextureBarrierTiled() + public unsafe void TextureBarrierTiled() { _renderer.New(); _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; if (evt != null) @@ -369,20 +369,20 @@ namespace Ryujinx.Graphics.GAL.Multithreading return false; } - _renderer.New().Set(Ref(evt), compare, isEqual); + _renderer.New()->Set(Ref(evt), compare, isEqual); _renderer.QueueCommand(); return true; } } - _renderer.New().Set(Ref(evt), Ref(null), isEqual); + _renderer.New()->Set(Ref(evt), Ref(null), isEqual); _renderer.QueueCommand(); return false; } - public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual) + public unsafe bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual) { - _renderer.New().Set(Ref(value as ThreadedCounterEvent), Ref(compare as ThreadedCounterEvent), isEqual); + _renderer.New()->Set(Ref(value as ThreadedCounterEvent), Ref(compare as ThreadedCounterEvent), isEqual); _renderer.QueueCommand(); return false; } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs index 74a345ffa..3c179da36 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs @@ -167,7 +167,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading return new TableRef(this, reference); } - internal ref T New() where T : struct + internal unsafe T* New() where T : unmanaged, IGALCommand { while (_producerPtr == (Volatile.Read(ref _consumerPtr) + QueueCount - 1) % QueueCount) { @@ -183,11 +183,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading _producerPtr = (_producerPtr + 1) % QueueCount; Span memory = new(_commandQueue, taken * _elementSize, _elementSize); - ref T result = ref Unsafe.As(ref MemoryMarshal.GetReference(memory)); + T* result = (T*)Unsafe.AsPointer(ref memory.GetPinnableReference()); + // ref T result = ref Unsafe.As(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) @@ -251,12 +252,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading return Thread.CurrentThread == _gpuThread; } - public void BackgroundContextAction(Action action, bool alwaysBackground = false) + public unsafe void BackgroundContextAction(Action action, bool alwaysBackground = false) { if (IsGpuThread() && !alwaysBackground) { // The action must be performed on the render thread. - New().Set(Ref(action)); + New()->Set(Ref(action)); InvokeCommand(); } 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(); - New().Set(handle, size, access); + New()->Set(handle, size, access); QueueCommand(); return handle; } - public BufferHandle CreateBuffer(nint pointer, int size) + public unsafe BufferHandle CreateBuffer(nint pointer, int size) { BufferHandle handle = Buffers.CreateBufferHandle(); - New().Set(handle, pointer, size); + New()->Set(handle, pointer, size); QueueCommand(); return handle; } - public BufferHandle CreateBufferSparse(ReadOnlySpan storageBuffers) + public unsafe BufferHandle CreateBufferSparse(ReadOnlySpan storageBuffers) { BufferHandle handle = Buffers.CreateBufferHandle(); - New().Set(handle, CopySpan(storageBuffers)); + New()->Set(handle, CopySpan(storageBuffers)); QueueCommand(); return handle; } - public IImageArray CreateImageArray(int size, bool isBuffer) + public unsafe IImageArray CreateImageArray(int size, bool isBuffer) { ThreadedImageArray imageArray = new(this); - New().Set(Ref(imageArray), size, isBuffer); + New()->Set(Ref(imageArray), size, isBuffer); QueueCommand(); return imageArray; } - public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) + public unsafe IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) { ThreadedProgram program = new(this); @@ -311,34 +312,34 @@ namespace Ryujinx.Graphics.GAL.Multithreading ProgramCount++; - New().Set(Ref((IProgramRequest)request)); + New()->Set(Ref((IProgramRequest)request)); QueueCommand(); return program; } - public ISampler CreateSampler(SamplerCreateInfo info) + public unsafe ISampler CreateSampler(SamplerCreateInfo info) { ThreadedSampler sampler = new(this); - New().Set(Ref(sampler), info); + New()->Set(Ref(sampler), info); QueueCommand(); return sampler; } - public void CreateSync(ulong id, bool strict) + public unsafe void CreateSync(ulong id, bool strict) { Sync.CreateSyncHandle(id); - New().Set(id, strict); + New()->Set(id, strict); QueueCommand(); } - public ITexture CreateTexture(TextureCreateInfo info) + public unsafe ITexture CreateTexture(TextureCreateInfo info) { if (IsGpuThread()) { ThreadedTexture texture = new(this, info); - New().Set(Ref(texture), info); + New()->Set(Ref(texture), info); QueueCommand(); return texture; @@ -353,27 +354,27 @@ namespace Ryujinx.Graphics.GAL.Multithreading return texture; } } - public ITextureArray CreateTextureArray(int size, bool isBuffer) + public unsafe ITextureArray CreateTextureArray(int size, bool isBuffer) { ThreadedTextureArray textureArray = new(this); - New().Set(Ref(textureArray), size, isBuffer); + New()->Set(Ref(textureArray), size, isBuffer); QueueCommand(); return textureArray; } - public void DeleteBuffer(BufferHandle buffer) + public unsafe void DeleteBuffer(BufferHandle buffer) { - New().Set(buffer); + New()->Set(buffer); QueueCommand(); } - public PinnedSpan GetBufferData(BufferHandle buffer, int offset, int size) + public unsafe PinnedSpan GetBufferData(BufferHandle buffer, int offset, int size) { if (IsGpuThread()) { ResultBox> box = new(); - New().Set(buffer, offset, size, Ref(box)); + New()->Set(buffer, offset, size, Ref(box)); InvokeCommand(); return box.Result; @@ -384,10 +385,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading } } - public Capabilities GetCapabilities() + public unsafe Capabilities GetCapabilities() { ResultBox box = new(); - New().Set(Ref(box)); + New()->Set(Ref(box)); InvokeCommand(); return box.Result; @@ -412,29 +413,29 @@ namespace Ryujinx.Graphics.GAL.Multithreading _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); BinaryProgramRequest request = new(program, programBinary, hasFragmentShader, info); Programs.Add(request); - New().Set(Ref((IProgramRequest)request)); + New()->Set(Ref((IProgramRequest)request)); QueueCommand(); return program; } - public void PreFrame() + public unsafe void PreFrame() { New(); QueueCommand(); } - public ICounterEvent ReportCounter(CounterType type, EventHandler resultHandler, float divisor, bool hostReserved) + public unsafe ICounterEvent ReportCounter(CounterType type, EventHandler resultHandler, float divisor, bool hostReserved) { ThreadedCounterEvent evt = new(this, type, _lastSampleCounterClear); - New().Set(Ref(evt), type, Ref(resultHandler), divisor, hostReserved); + New()->Set(Ref(evt), type, Ref(resultHandler), divisor, hostReserved); QueueCommand(); if (type == CounterType.SamplesPassed) @@ -445,9 +446,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading return evt; } - public void ResetCounter(CounterType type) + public unsafe void ResetCounter(CounterType type) { - New().Set(type); + New()->Set(type); QueueCommand(); _lastSampleCounterClear = true; } @@ -457,13 +458,13 @@ namespace Ryujinx.Graphics.GAL.Multithreading _baseRenderer.Screenshot(); } - public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan data) + public unsafe void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan data) { - New().Set(buffer, offset, CopySpan(data)); + New()->Set(buffer, offset, CopySpan(data)); QueueCommand(); } - public void UpdateCounters() + public unsafe void UpdateCounters() { New(); QueueCommand(); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs index 7a4836982..78c39c493 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs @@ -17,13 +17,13 @@ namespace Ryujinx.Graphics.GAL.Multithreading _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. // This is a multithread rate limit - we can't be more than one frame behind the command queue. _renderer.WaitForFrame(); - _renderer.New().Set(new TableRef(_renderer, texture as ThreadedTexture), crop, new TableRef(_renderer, swapBuffersCallback)); + _renderer.New()->Set(new TableRef(_renderer, texture as ThreadedTexture), crop, new TableRef(_renderer, swapBuffersCallback)); _renderer.QueueCommand(); } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 95e43e341..9e1972f8e 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -49,6 +49,12 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Cache of GPU counters. /// internal CounterCache CounterCache { get; } + + private delegate void WriteCallback(ulong address, ReadOnlySpan data); + + private WriteCallback _write; + private WriteCallback _writeTrackedResource; + private WriteCallback _writeUntracked; /// /// Creates a new instance of the GPU memory manager. @@ -58,6 +64,9 @@ namespace Ryujinx.Graphics.Gpu.Memory internal MemoryManager(PhysicalMemory physicalMemory, ulong cpuMemorySize) { Physical = physicalMemory; + _write = physicalMemory.Write; + _writeTrackedResource = physicalMemory.WriteTrackedResource; + _writeUntracked = physicalMemory.WriteUntracked; VirtualRangeCache = new VirtualRangeCache(this); CounterCache = new CounterCache(); _pageTable = new ulong[PtLvl0Size][]; @@ -269,7 +278,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// The data to be written public void Write(ulong va, ReadOnlySpan data) { - WriteImpl(va, data, Physical.Write); + WriteImpl(va, data, _write); } /// @@ -279,7 +288,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// The data to be written public void WriteTrackedResource(ulong va, ReadOnlySpan data) { - WriteImpl(va, data, Physical.WriteTrackedResource); + WriteImpl(va, data, _writeTrackedResource); } /// @@ -289,11 +298,9 @@ namespace Ryujinx.Graphics.Gpu.Memory /// The data to be written public void WriteUntracked(ulong va, ReadOnlySpan data) { - WriteImpl(va, data, Physical.WriteUntracked); + WriteImpl(va, data, _writeUntracked); } - private delegate void WriteCallback(ulong address, ReadOnlySpan data); - /// /// Writes data to possibly non-contiguous GPU mapped memory. /// diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index fea09ef47..89ef76616 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -123,15 +123,15 @@ namespace Ryujinx.HLE.HOS.Services.Nv return NvResult.InvalidSize; } - byte[] outputData = new byte[outputDataSize]; - - byte[] temp = new byte[inputDataSize]; - - context.Memory.Read(inputDataPosition, temp); - - Buffer.BlockCopy(temp, 0, outputData, 0, temp.Length); - - arguments = new Span(outputData); + if (!context.Memory.TryReadUnsafe(inputDataPosition, (int)inputDataSize, out arguments)) + { + arguments = new byte[inputDataSize]; + context.Memory.Read(inputDataPosition, arguments); + } + else + { + arguments = arguments.ToArray(); + } } else if (isWrite) { @@ -470,12 +470,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv (ulong inlineInBufferPosition, ulong inlineInBufferSize) = context.Request.GetBufferType0x21(1); errorCode = GetIoctlArgument(context, ioctlCommand, out Span arguments); - - byte[] temp = new byte[inlineInBufferSize]; - - context.Memory.Read(inlineInBufferPosition, temp); - - Span inlineInBuffer = new(temp); + + if (!context.Memory.TryReadUnsafe(inlineInBufferPosition, (int)inlineInBufferSize, out Span inlineInBuffer)) + { + inlineInBuffer = new byte[inlineInBufferSize]; + context.Memory.Read(inlineInBufferPosition, inlineInBuffer); + } if (errorCode == NvResult.Success) { @@ -519,12 +519,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv (ulong inlineOutBufferPosition, ulong inlineOutBufferSize) = context.Request.GetBufferType0x22(1); errorCode = GetIoctlArgument(context, ioctlCommand, out Span arguments); - - byte[] temp = new byte[inlineOutBufferSize]; - - context.Memory.Read(inlineOutBufferPosition, temp); - - Span inlineOutBuffer = new(temp); + + if (!context.Memory.TryReadUnsafe(inlineOutBufferPosition, (int)inlineOutBufferSize, out Span inlineOutBuffer)) + { + inlineOutBuffer = new byte[inlineOutBufferSize]; + context.Memory.Read(inlineOutBufferPosition, inlineOutBuffer); + } if (errorCode == NvResult.Success) { diff --git a/src/Ryujinx.Memory/IVirtualMemoryManager.cs b/src/Ryujinx.Memory/IVirtualMemoryManager.cs index 1f8ca37aa..a417ede8c 100644 --- a/src/Ryujinx.Memory/IVirtualMemoryManager.cs +++ b/src/Ryujinx.Memory/IVirtualMemoryManager.cs @@ -60,6 +60,15 @@ namespace Ryujinx.Memory /// Span to store the data being read into /// Throw for unhandled invalid or unmapped memory accesses void Read(ulong va, Span data); + + /// + /// Gets a span of CPU mapped memory. + /// + /// Virtual address of the data in memory + /// Length of the data in memory + /// Span that references the data being read + /// Throw for unhandled invalid or unmapped memory accesses + bool TryReadUnsafe(ulong va, int length, out Span data); /// /// Writes data to CPU mapped memory. diff --git a/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs index 9c49286b9..cd50b4152 100644 --- a/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs +++ b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs @@ -159,6 +159,13 @@ namespace Ryujinx.Memory AssertValidAddressAndSize(va, data.Length); + if (IsContiguousAndMapped(va, data.Length)) + { + nuint pa = TranslateVirtualAddressChecked(va); + + GetPhysicalAddressSpan(pa, data.Length).CopyTo(data); + } + int offset = 0, size; if ((va & PageMask) != 0) @@ -182,6 +189,28 @@ namespace Ryujinx.Memory } } + public virtual bool TryReadUnsafe(ulong va, int length, out Span data) + { + if (!IsContiguousAndMapped(va, length)) + { + data = default; + return false; + } + + if (length == 0) + { + data = Span.Empty; + return true; + } + + AssertValidAddressAndSize(va, length); + + nuint pa = TranslateVirtualAddressChecked(va); + + data = GetPhysicalAddressSpan(pa, length); + return true; + } + public virtual T ReadTracked(ulong va) where T : unmanaged { SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), false); diff --git a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs index a01521c8f..9b1a8c995 100644 --- a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs +++ b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs @@ -42,6 +42,11 @@ namespace Ryujinx.Tests.Memory { throw new NotImplementedException(); } + + public bool TryReadUnsafe(ulong va, int lenfth, out Span data) + { + throw new NotImplementedException(); + } public void Write(ulong va, T value) where T : unmanaged {