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