From 225a863f689cadd2150359d9e979ed1aa843ee04 Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Mon, 8 Jul 2024 12:02:42 +0100 Subject: [PATCH] Better index buffer management --- src/Ryujinx.Graphics.Metal/BufferManager.cs | 12 +++ src/Ryujinx.Graphics.Metal/EncoderState.cs | 6 +- .../EncoderStateManager.cs | 21 ++---- .../IndexBufferState.cs | 74 +++++++++++++++++++ src/Ryujinx.Graphics.Metal/Pipeline.cs | 29 ++++---- 5 files changed, 108 insertions(+), 34 deletions(-) create mode 100644 src/Ryujinx.Graphics.Metal/IndexBufferState.cs diff --git a/src/Ryujinx.Graphics.Metal/BufferManager.cs b/src/Ryujinx.Graphics.Metal/BufferManager.cs index 1bc7d458e..71620f424 100644 --- a/src/Ryujinx.Graphics.Metal/BufferManager.cs +++ b/src/Ryujinx.Graphics.Metal/BufferManager.cs @@ -135,6 +135,18 @@ namespace Ryujinx.Graphics.Metal return null; } + public Auto GetBuffer(BufferHandle handle, bool isWrite, out int size) + { + if (TryGetBuffer(handle, out var holder)) + { + size = holder.Size; + return holder.GetBuffer(isWrite); + } + + size = 0; + return null; + } + public Auto GetBuffer(BufferHandle handle, int offset, int size, bool isWrite) { if (TryGetBuffer(handle, out var holder)) diff --git a/src/Ryujinx.Graphics.Metal/EncoderState.cs b/src/Ryujinx.Graphics.Metal/EncoderState.cs index bd60e90e4..5c82fb9cf 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderState.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderState.cs @@ -93,9 +93,7 @@ namespace Ryujinx.Graphics.Metal public readonly BufferRef[] StorageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings]; public readonly TextureRef[] TextureRefs = new TextureRef[Constants.MaxTextureBindings]; - public Auto IndexBuffer = default; - public MTLIndexType IndexType = MTLIndexType.UInt16; - public ulong IndexBufferOffset = 0; + public IndexBufferState IndexBuffer = default; public MTLDepthClipMode DepthClipMode = MTLDepthClipMode.Clip; @@ -115,7 +113,7 @@ namespace Ryujinx.Graphics.Metal public MTLScissorRect[] Scissors = new MTLScissorRect[Constants.MaxViewports]; // Changes to attachments take recreation! - public Texture DepthStencil = default; + public Texture DepthStencil; public Texture[] RenderTargets = new Texture[Constants.MaxColorAttachments]; public ITexture PreMaskDepthStencil = default; public ITexture[] PreMaskRenderTargets; diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs index 83e1835a3..b29a472ce 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs @@ -23,9 +23,7 @@ namespace Ryujinx.Graphics.Metal private readonly EncoderState _mainState = new(); private EncoderState _currentState; - public readonly Auto IndexBuffer => _currentState.IndexBuffer; - public readonly MTLIndexType IndexType => _currentState.IndexType; - public readonly ulong IndexBufferOffset => _currentState.IndexBufferOffset; + public readonly IndexBufferState IndexBuffer => _currentState.IndexBuffer; public readonly PrimitiveTopology Topology => _currentState.Topology; public readonly Texture[] RenderTargets => _currentState.RenderTargets; public readonly Texture DepthStencil => _currentState.DepthStencil; @@ -305,18 +303,11 @@ namespace Ryujinx.Graphics.Metal { if (buffer.Handle != BufferHandle.Null) { - if (type == GAL.IndexType.UByte) - { - _currentState.IndexType = MTLIndexType.UInt16; - _currentState.IndexBufferOffset = 0; - _currentState.IndexBuffer = _bufferManager.GetBufferI8ToI16(_pipeline.Cbs, buffer.Handle, buffer.Offset, buffer.Size); - } - else - { - _currentState.IndexType = type.Convert(); - _currentState.IndexBufferOffset = (ulong)buffer.Offset; - _currentState.IndexBuffer = _bufferManager.GetBuffer(buffer.Handle, false); - } + _currentState.IndexBuffer = new IndexBufferState(buffer.Handle, buffer.Offset, buffer.Size, type); + } + else + { + _currentState.IndexBuffer = IndexBufferState.Null; } } diff --git a/src/Ryujinx.Graphics.Metal/IndexBufferState.cs b/src/Ryujinx.Graphics.Metal/IndexBufferState.cs new file mode 100644 index 000000000..9eaaf9a19 --- /dev/null +++ b/src/Ryujinx.Graphics.Metal/IndexBufferState.cs @@ -0,0 +1,74 @@ +using Ryujinx.Graphics.GAL; +using SharpMetal.Metal; +using System; +using System.Runtime.Versioning; + +namespace Ryujinx.Graphics.Metal +{ + [SupportedOSPlatform("macos")] + internal struct IndexBufferState + { + public static IndexBufferState Null => new(BufferHandle.Null, 0, 0); + + private readonly int _offset; + private readonly int _size; + private readonly IndexType _type; + + private readonly BufferHandle _handle; + + public IndexBufferState(BufferHandle handle, int offset, int size, IndexType type) + { + _handle = handle; + _offset = offset; + _size = size; + _type = type; + } + + public IndexBufferState(BufferHandle handle, int offset, int size) + { + _handle = handle; + _offset = offset; + _size = size; + _type = IndexType.UInt; + } + + public (MTLBuffer, int, MTLIndexType) GetIndexBuffer(MetalRenderer renderer, CommandBufferScoped cbs) + { + Auto autoBuffer; + int offset, size; + MTLIndexType type; + + if (_type == IndexType.UByte) + { + // Index type is not supported. Convert to I16. + autoBuffer = renderer.BufferManager.GetBufferI8ToI16(cbs, _handle, _offset, _size); + + type = MTLIndexType.UInt16; + offset = 0; + size = _size * 2; + } + else + { + autoBuffer = renderer.BufferManager.GetBuffer(_handle, false, out int bufferSize); + + if (_offset >= bufferSize) + { + autoBuffer = null; + } + + type = _type.Convert(); + offset = _offset; + size = _size; + } + + if (autoBuffer != null) + { + DisposableBuffer buffer = autoBuffer.Get(cbs, offset, size); + + return (buffer.Value, offset, type); + } + + return (new MTLBuffer(IntPtr.Zero), 0, MTLIndexType.UInt16); + } + } +} diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs index 5e4e55ea3..d5c04884a 100644 --- a/src/Ryujinx.Graphics.Metal/Pipeline.cs +++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs @@ -377,8 +377,6 @@ namespace Ryujinx.Graphics.Metal return; } - var renderCommandEncoder = GetOrCreateRenderEncoder(true); - // TODO: Reindex unsupported topologies if (TopologyUnsupported(_encoderStateManager.Topology)) { @@ -387,21 +385,22 @@ namespace Ryujinx.Graphics.Metal var primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert(); - var indexBuffer = _encoderStateManager.IndexBuffer; + (MTLBuffer mtlBuffer, int offset, MTLIndexType type) = _encoderStateManager.IndexBuffer.GetIndexBuffer(_renderer, Cbs); - ulong offset = _encoderStateManager.IndexBufferOffset; - MTLIndexType type = _encoderStateManager.IndexType; - int indexSize = type == MTLIndexType.UInt32 ? sizeof(int) : sizeof(short); + if (mtlBuffer.NativePtr != IntPtr.Zero) + { + var renderCommandEncoder = GetOrCreateRenderEncoder(true); - renderCommandEncoder.DrawIndexedPrimitives( - primitiveType, - (ulong)indexCount, - type, - indexBuffer.Get(Cbs, (int)offset, indexCount * indexSize).Value, - offset, - (ulong)instanceCount, - firstVertex, - (ulong)firstInstance); + renderCommandEncoder.DrawIndexedPrimitives( + primitiveType, + (ulong)indexCount, + type, + mtlBuffer, + (ulong)offset, + (ulong)instanceCount, + firstVertex, + (ulong)firstInstance); + } } public void DrawIndexedIndirect(BufferRange indirectBuffer)