Better vertex buffer management

This commit is contained in:
Isaac Marovitz 2024-07-08 13:55:46 +01:00 committed by Isaac Marovitz
parent a6f5f2f82b
commit 9f2c99fcfa
3 changed files with 85 additions and 18 deletions

View file

@ -122,7 +122,7 @@ namespace Ryujinx.Graphics.Metal
public Array8<ColorBlendStateUid> StoredBlend; public Array8<ColorBlendStateUid> StoredBlend;
public ColorF BlendColor = new(); 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]; public readonly VertexAttribDescriptor[] VertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttributes];
// Dirty flags // Dirty flags
public DirtyFlags Dirty = DirtyFlags.None; public DirtyFlags Dirty = DirtyFlags.None;

View file

@ -52,8 +52,6 @@ namespace Ryujinx.Graphics.Metal
public readonly void Dispose() public readonly void Dispose()
{ {
// State
_depthStencilCache.Dispose(); _depthStencilCache.Dispose();
} }
@ -676,7 +674,24 @@ namespace Ryujinx.Graphics.Metal
public readonly void UpdateVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers) public readonly void UpdateVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> 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 // Update the buffers on the pipeline
UpdatePipelineVertexState(_currentState.VertexBuffers, _currentState.VertexAttribs); 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; ref PipelineState pipeline = ref _currentState.Pipeline;
uint indexMask = 0; uint indexMask = 0;
@ -932,24 +947,16 @@ namespace Ryujinx.Graphics.Metal
pipeline.VertexBindingDescriptionsCount = Constants.ZeroBufferIndex + 1; // TODO: move this out? 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<DisposableBuffer> autoBuffer = bufferDescriptors[i].Buffer.Handle == BufferHandle.Null (MTLBuffer mtlBuffer, int offset) = bufferStates[i].GetVertexBuffer(_bufferManager, _pipeline.Cbs);
? null
: _bufferManager.GetBuffer(bufferDescriptors[i].Buffer.Handle, bufferDescriptors[i].Buffer.Write);
var range = bufferDescriptors[i].Buffer; if (mtlBuffer.NativePtr != IntPtr.Zero)
var offset = range.Offset;
if (autoBuffer == null)
{ {
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<DisposableBuffer> autoZeroBuffer = _zeroBuffer == BufferHandle.Null Auto<DisposableBuffer> autoZeroBuffer = _zeroBuffer == BufferHandle.Null

View file

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