diff options
author | riperiperi <rhy3756547@hotmail.com> | 2023-05-08 09:59:26 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-08 10:59:26 +0200 |
commit | 895d9b53bc37507fed6829a7f91a1b8e3237ab0b (patch) | |
tree | 3e3449370616705ffa76bc209e3dd960b87de3e0 /src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | |
parent | 0e06aace458109f70dc5f36535f77117465ea707 (diff) |
Vulkan: Batch vertex buffer updates (#4843)1.1.769
* Vulkan: Batch vertex buffer updates
Some games can bind a large number of vertex buffers for draws. This PR allows for vertex buffers to be updated with one call rather than one per buffer.
This mostly affects the AMD Mesa driver, the testing platform was Steam Deck with Super Mario Odyssey. It was taking about 12% before, should be greatly reduced now.
A small optimization has been added to avoid looking up the same buffer multiple times, as a common pattern is for the same buffer to be bound many times in a row with different ranges.
* Only rebind vertex buffers if they have changed
* Address feedback
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/PipelineBase.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index cf31a7f8..4aec0dbc 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -66,6 +66,8 @@ namespace Ryujinx.Graphics.Vulkan private ulong _vertexBuffersDirty; protected Rectangle<int> ClearScissor; + private readonly VertexBufferUpdater _vertexBufferUpdater; + public SupportBufferUpdater SupportBufferUpdater; public IndexBufferPattern QuadsToTrisPattern; public IndexBufferPattern TriFanToTrisPattern; @@ -96,6 +98,7 @@ namespace Ryujinx.Graphics.Vulkan gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError(); _descriptorSetUpdater = new DescriptorSetUpdater(gd, this); + _vertexBufferUpdater = new VertexBufferUpdater(gd); _transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers]; _vertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers + 1]; @@ -1185,6 +1188,9 @@ namespace Ryujinx.Graphics.Vulkan int validCount = 1; + BufferHandle lastHandle = default; + Auto<DisposableBuffer> lastBuffer = default; + for (int i = 0; i < count; i++) { var vertexBuffer = vertexBuffers[i]; @@ -1194,7 +1200,12 @@ namespace Ryujinx.Graphics.Vulkan if (vertexBuffer.Buffer.Handle != BufferHandle.Null) { - var vb = Gd.BufferManager.GetBuffer(CommandBuffer, vertexBuffer.Buffer.Handle, false); + Auto<DisposableBuffer> vb = (vertexBuffer.Buffer.Handle == lastHandle) ? lastBuffer : + Gd.BufferManager.GetBuffer(CommandBuffer, vertexBuffer.Buffer.Handle, false); + + lastHandle = vertexBuffer.Buffer.Handle; + lastBuffer = vb; + if (vb != null) { int binding = i + 1; @@ -1222,24 +1233,29 @@ namespace Ryujinx.Graphics.Vulkan ref var buffer = ref _vertexBuffers[binding]; int oldScalarAlign = buffer.AttributeScalarAlignment; - buffer.Dispose(); - if (Gd.Capabilities.VertexBufferAlignment < 2 && (vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0) { - buffer = new VertexBufferState( - vb, - descriptorIndex, - vertexBuffer.Buffer.Offset, - vbSize, - vertexBuffer.Stride); + if (!buffer.Matches(vb, descriptorIndex, vertexBuffer.Buffer.Offset, vbSize, vertexBuffer.Stride)) + { + buffer.Dispose(); + + buffer = new VertexBufferState( + vb, + descriptorIndex, + vertexBuffer.Buffer.Offset, + vbSize, + vertexBuffer.Stride); - buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState); + buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState, _vertexBufferUpdater); + } } else { // May need to be rewritten. Bind this buffer before draw. + buffer.Dispose(); + buffer = new VertexBufferState( vertexBuffer.Buffer.Handle, descriptorIndex, @@ -1255,6 +1271,8 @@ namespace Ryujinx.Graphics.Vulkan } } + _vertexBufferUpdater.Commit(Cbs); + _newState.VertexBindingDescriptionsCount = (uint)validCount; SignalStateChange(); } @@ -1596,10 +1614,12 @@ namespace Ryujinx.Graphics.Vulkan { int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty); - _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState); + _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState, _vertexBufferUpdater); _vertexBuffersDirty &= ~(1UL << i); } + + _vertexBufferUpdater.Commit(Cbs); } if (_stateDirty || Pbp != pbp) @@ -1712,6 +1732,7 @@ namespace Ryujinx.Graphics.Vulkan _framebuffer?.Dispose(); _newState.Dispose(); _descriptorSetUpdater.Dispose(); + _vertexBufferUpdater.Dispose(); for (int i = 0; i < _vertexBuffers.Length; i++) { |