Better vertex buffer management
This commit is contained in:
parent
a6f5f2f82b
commit
9f2c99fcfa
3 changed files with 85 additions and 18 deletions
|
@ -122,7 +122,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
public Array8<ColorBlendStateUid> 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;
|
||||
|
|
|
@ -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<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
|
||||
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<DisposableBuffer> 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<DisposableBuffer> autoZeroBuffer = _zeroBuffer == BufferHandle.Null
|
||||
|
|
60
src/Ryujinx.Graphics.Metal/VertexBufferState.cs
Normal file
60
src/Ryujinx.Graphics.Metal/VertexBufferState.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue