Better index buffer management

This commit is contained in:
Isaac Marovitz 2024-07-08 12:02:42 +01:00 committed by Isaac Marovitz
parent 18a1741348
commit 655823ecc7
5 changed files with 108 additions and 34 deletions

View file

@ -135,6 +135,18 @@ namespace Ryujinx.Graphics.Metal
return null;
}
public Auto<DisposableBuffer> 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<DisposableBuffer> GetBuffer(BufferHandle handle, int offset, int size, bool isWrite)
{
if (TryGetBuffer(handle, out var holder))

View file

@ -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<DisposableBuffer> 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;

View file

@ -23,9 +23,7 @@ namespace Ryujinx.Graphics.Metal
private readonly EncoderState _mainState = new();
private EncoderState _currentState;
public readonly Auto<DisposableBuffer> 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;
}
}

View file

@ -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<DisposableBuffer> 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);
}
}
}

View file

@ -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)