aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Ryujinx.Graphics.Vulkan/PipelineBase.cs43
-rw-r--r--src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs39
-rw-r--r--src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs84
3 files changed, 124 insertions, 42 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++)
{
diff --git a/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs b/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs
index c4856019..2118bfae 100644
--- a/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs
+++ b/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Vulkan
AttributeScalarAlignment = 1;
}
- public void BindVertexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, uint binding, ref PipelineState state)
+ public void BindVertexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, uint binding, ref PipelineState state, VertexBufferUpdater updater)
{
var autoBuffer = _buffer;
@@ -65,21 +65,7 @@ namespace Ryujinx.Graphics.Vulkan
var buffer = autoBuffer.Get(cbs, 0, newSize).Value;
- if (gd.Capabilities.SupportsExtendedDynamicState)
- {
- gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
- cbs.CommandBuffer,
- binding,
- 1,
- buffer,
- 0,
- (ulong)newSize,
- (ulong)stride);
- }
- else
- {
- gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
- }
+ updater.BindVertexBuffer(cbs, binding, buffer, 0, (ulong)newSize, (ulong)stride);
_buffer = autoBuffer;
@@ -106,21 +92,7 @@ namespace Ryujinx.Graphics.Vulkan
{
var buffer = autoBuffer.Get(cbs, _offset, _size).Value;
- if (gd.Capabilities.SupportsExtendedDynamicState)
- {
- gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
- cbs.CommandBuffer,
- binding,
- 1,
- buffer,
- (ulong)_offset,
- (ulong)_size,
- (ulong)_stride);
- }
- else
- {
- gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, (ulong)_offset);
- }
+ updater.BindVertexBuffer(cbs, binding, buffer, (ulong)_offset, (ulong)_size, (ulong)_stride);
}
}
@@ -129,6 +101,11 @@ namespace Ryujinx.Graphics.Vulkan
return _buffer == buffer;
}
+ public bool Matches(Auto<DisposableBuffer> buffer, int descriptorIndex, int offset, int size, int stride = 0)
+ {
+ return _buffer == buffer && DescriptorIndex == descriptorIndex && _offset == offset && _size == size && _stride == stride;
+ }
+
public void Swap(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
{
if (_buffer == from)
diff --git a/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs
new file mode 100644
index 00000000..bceaeb8c
--- /dev/null
+++ b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs
@@ -0,0 +1,84 @@
+using Silk.NET.Vulkan;
+using System;
+
+using VkBuffer = Silk.NET.Vulkan.Buffer;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ internal class VertexBufferUpdater : IDisposable
+ {
+ private VulkanRenderer _gd;
+
+ private uint _baseBinding;
+ private uint _count;
+
+ private NativeArray<VkBuffer> _buffers;
+ private NativeArray<ulong> _offsets;
+ private NativeArray<ulong> _sizes;
+ private NativeArray<ulong> _strides;
+
+ public VertexBufferUpdater(VulkanRenderer gd)
+ {
+ _gd = gd;
+
+ _buffers = new NativeArray<VkBuffer>(Constants.MaxVertexBuffers);
+ _offsets = new NativeArray<ulong>(Constants.MaxVertexBuffers);
+ _sizes = new NativeArray<ulong>(Constants.MaxVertexBuffers);
+ _strides = new NativeArray<ulong>(Constants.MaxVertexBuffers);
+ }
+
+ public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, VkBuffer buffer, ulong offset, ulong size, ulong stride)
+ {
+ if (_count == 0)
+ {
+ _baseBinding = binding;
+ }
+ else if (_baseBinding + _count != binding)
+ {
+ Commit(cbs);
+ _baseBinding = binding;
+ }
+
+ int index = (int)_count;
+
+ _buffers[index] = buffer;
+ _offsets[index] = offset;
+ _sizes[index] = size;
+ _strides[index] = stride;
+
+ _count++;
+ }
+
+ public unsafe void Commit(CommandBufferScoped cbs)
+ {
+ if (_count != 0)
+ {
+ if (_gd.Capabilities.SupportsExtendedDynamicState)
+ {
+ _gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
+ cbs.CommandBuffer,
+ _baseBinding,
+ _count,
+ _buffers.Pointer,
+ _offsets.Pointer,
+ _sizes.Pointer,
+ _strides.Pointer);
+ }
+ else
+ {
+ _gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, _baseBinding, _count, _buffers.Pointer, _offsets.Pointer);
+ }
+
+ _count = 0;
+ }
+ }
+
+ public void Dispose()
+ {
+ _buffers.Dispose();
+ _offsets.Dispose();
+ _sizes.Dispose();
+ _strides.Dispose();
+ }
+ }
+}