From 9f2c99fcfa250d8a0e2362e059829f97f74977ee Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Mon, 8 Jul 2024 13:55:46 +0100 Subject: [PATCH] Better vertex buffer management --- src/Ryujinx.Graphics.Metal/EncoderState.cs | 2 +- .../EncoderStateManager.cs | 41 +++++++------ .../VertexBufferState.cs | 60 +++++++++++++++++++ 3 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 src/Ryujinx.Graphics.Metal/VertexBufferState.cs diff --git a/src/Ryujinx.Graphics.Metal/EncoderState.cs b/src/Ryujinx.Graphics.Metal/EncoderState.cs index 5c82fb9cf..d7b9bb8c8 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderState.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderState.cs @@ -122,7 +122,7 @@ namespace Ryujinx.Graphics.Metal public Array8 StoredBlend; public ColorF BlendColor = new(); - public readonly VertexBufferDescriptor[] VertexBuffers = new VertexBufferDescriptor[Constants.MaxVertexBuffers]; + public readonly VertexBufferState[] VertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers]; public readonly VertexAttribDescriptor[] VertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttributes]; // Dirty flags public DirtyFlags Dirty = DirtyFlags.None; diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs index b29a472ce..e3ace6e9a 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs @@ -52,8 +52,6 @@ namespace Ryujinx.Graphics.Metal public readonly void Dispose() { - // State - _depthStencilCache.Dispose(); } @@ -676,7 +674,24 @@ namespace Ryujinx.Graphics.Metal public readonly void UpdateVertexBuffers(ReadOnlySpan vertexBuffers) { - vertexBuffers.CopyTo(_currentState.VertexBuffers); + for (int i = 0; i < Constants.MaxVertexBuffers; i++) + { + if (i < vertexBuffers.Length) + { + var vertexBuffer = vertexBuffers[i]; + + _currentState.VertexBuffers[i] = new VertexBufferState( + vertexBuffer.Buffer.Handle, + vertexBuffer.Buffer.Offset, + vertexBuffer.Buffer.Size, + vertexBuffer.Divisor, + vertexBuffer.Stride); + } + else + { + _currentState.VertexBuffers[i] = VertexBufferState.Null; + } + } // Update the buffers on the pipeline UpdatePipelineVertexState(_currentState.VertexBuffers, _currentState.VertexAttribs); @@ -855,7 +870,7 @@ namespace Ryujinx.Graphics.Metal } } - private readonly void UpdatePipelineVertexState(VertexBufferDescriptor[] bufferDescriptors, VertexAttribDescriptor[] attribDescriptors) + private readonly void UpdatePipelineVertexState(VertexBufferState[] bufferDescriptors, VertexAttribDescriptor[] attribDescriptors) { ref PipelineState pipeline = ref _currentState.Pipeline; uint indexMask = 0; @@ -932,24 +947,16 @@ namespace Ryujinx.Graphics.Metal pipeline.VertexBindingDescriptionsCount = Constants.ZeroBufferIndex + 1; // TODO: move this out? } - private readonly void SetVertexBuffers(MTLRenderCommandEncoder renderCommandEncoder, VertexBufferDescriptor[] bufferDescriptors) + private readonly void SetVertexBuffers(MTLRenderCommandEncoder renderCommandEncoder, VertexBufferState[] bufferStates) { - for (int i = 0; i < bufferDescriptors.Length; i++) + for (int i = 0; i < bufferStates.Length; i++) { - Auto autoBuffer = bufferDescriptors[i].Buffer.Handle == BufferHandle.Null - ? null - : _bufferManager.GetBuffer(bufferDescriptors[i].Buffer.Handle, bufferDescriptors[i].Buffer.Write); + (MTLBuffer mtlBuffer, int offset) = bufferStates[i].GetVertexBuffer(_bufferManager, _pipeline.Cbs); - var range = bufferDescriptors[i].Buffer; - var offset = range.Offset; - - if (autoBuffer == null) + if (mtlBuffer.NativePtr != IntPtr.Zero) { - continue; + renderCommandEncoder.SetVertexBuffer(mtlBuffer, (ulong)offset, (ulong)i); } - - var mtlBuffer = autoBuffer.Get(_pipeline.Cbs, offset, range.Size, range.Write).Value; - renderCommandEncoder.SetVertexBuffer(mtlBuffer, (ulong)offset, (ulong)i); } Auto autoZeroBuffer = _zeroBuffer == BufferHandle.Null diff --git a/src/Ryujinx.Graphics.Metal/VertexBufferState.cs b/src/Ryujinx.Graphics.Metal/VertexBufferState.cs new file mode 100644 index 000000000..277366b89 --- /dev/null +++ b/src/Ryujinx.Graphics.Metal/VertexBufferState.cs @@ -0,0 +1,60 @@ +using Ryujinx.Graphics.GAL; +using SharpMetal.Metal; +using System; +using System.Runtime.Versioning; + +namespace Ryujinx.Graphics.Metal +{ + [SupportedOSPlatform("macos")] + internal struct VertexBufferState + { + public static VertexBufferState Null => new(BufferHandle.Null, 0, 0, 0); + + private readonly BufferHandle _handle; + private readonly int _offset; + private readonly int _size; + + public readonly int Stride; + public readonly int Divisor; + + public VertexBufferState(BufferHandle handle, int offset, int size, int divisor, int stride = 0) + { + _handle = handle; + _offset = offset; + _size = size; + + Stride = stride; + Divisor = divisor; + } + + public (MTLBuffer, int) GetVertexBuffer(BufferManager bufferManager, CommandBufferScoped cbs) + { + Auto autoBuffer = null; + + if (_handle != BufferHandle.Null) + { + // TODO: Handle restride if necessary + + autoBuffer = bufferManager.GetBuffer(_handle, false, out int size); + + // The original stride must be reapplied in case it was rewritten. + // TODO: Handle restride if necessary + + if (_offset >= size) + { + autoBuffer = null; + } + } + + if (autoBuffer != null) + { + int offset = _offset; + var buffer = autoBuffer.Get(cbs, offset, _size).Value; + + return (buffer, offset); + } + + return (new MTLBuffer(IntPtr.Zero), 0); + } + } +}