aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/PipelineBase.cs
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2022-09-09 00:30:19 +0100
committerGitHub <noreply@github.com>2022-09-08 20:30:19 -0300
commitc6d82209abeacd2336cde99e5a02b4596e70da83 (patch)
tree8dc8e1055f402c07e6ed9e4ff247ca420729808c /Ryujinx.Graphics.Vulkan/PipelineBase.cs
parentee1825219b8ccca13df7198d4e9ffb966e44c883 (diff)
Restride vertex buffer when stride causes attributes to misalign in Vulkan. (#3679)1.1.254
* Vertex Buffer Alignment part 1 * Update CacheByRange * Add Stride Change compute shader, fix storage buffers in helpers * An AMD exclusive * Reword * Change rules - stride conversion when attrs misalign * Fix stupid mistake * Fix background pipeline compile * Improve a few things. * Fix some feedback * Address Feedback (the shader binary didn't change when i changed the source to use the subgroup size) * Fix bug where rewritten buffer would be disposed instantly.
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/PipelineBase.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/PipelineBase.cs122
1 files changed, 97 insertions, 25 deletions
diff --git a/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/Ryujinx.Graphics.Vulkan/PipelineBase.cs
index 30eeafb8..769d4594 100644
--- a/Ryujinx.Graphics.Vulkan/PipelineBase.cs
+++ b/Ryujinx.Graphics.Vulkan/PipelineBase.cs
@@ -2,6 +2,7 @@
using Ryujinx.Graphics.Shader;
using Silk.NET.Vulkan;
using System;
+using System.Numerics;
namespace Ryujinx.Graphics.Vulkan
{
@@ -50,14 +51,14 @@ namespace Ryujinx.Graphics.Vulkan
private BufferState _indexBuffer;
private readonly BufferState[] _transformFeedbackBuffers;
- private readonly BufferState[] _vertexBuffers;
+ private readonly VertexBufferState[] _vertexBuffers;
+ private ulong _vertexBuffersDirty;
protected Rectangle<int> ClearScissor;
public SupportBufferUpdater SupportBufferUpdater;
private bool _needsIndexBufferRebind;
private bool _needsTransformFeedbackBuffersRebind;
- private bool _needsVertexBuffersRebind;
private bool _tfEnabled;
private bool _tfActive;
@@ -79,14 +80,14 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater = new DescriptorSetUpdater(gd, this);
_transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers];
- _vertexBuffers = new BufferState[Constants.MaxVertexBuffers + 1];
+ _vertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers + 1];
const int EmptyVbSize = 16;
using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
emptyVb.SetData(0, new byte[EmptyVbSize]);
- _vertexBuffers[0] = new BufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0UL);
- _needsVertexBuffersRebind = true;
+ _vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0);
+ _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
@@ -229,6 +230,17 @@ namespace Ryujinx.Graphics.Vulkan
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
}
+ public void DirtyVertexBuffer(Auto<DisposableBuffer> buffer)
+ {
+ for (int i = 0; i < _vertexBuffers.Length; i++)
+ {
+ if (_vertexBuffers[i].BoundEquals(buffer))
+ {
+ _vertexBuffersDirty |= 1UL << i;
+ }
+ }
+ }
+
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{
if (!_program.IsLinked)
@@ -345,6 +357,11 @@ namespace Ryujinx.Graphics.Vulkan
_tfEnabled = false;
}
+ public bool IsCommandBufferActive(CommandBuffer cb)
+ {
+ return CommandBuffer.Handle == cb.Handle;
+ }
+
public void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
{
if (!Gd.Capabilities.SupportsIndirectParameters)
@@ -689,6 +706,11 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
}
+ public void SetStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
+ {
+ _descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
+ }
+
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{
_descriptorSetUpdater.SetTextureAndSampler(Cbs, stage, binding, texture, sampler);
@@ -732,12 +754,22 @@ namespace Ryujinx.Graphics.Vulkan
{
var formatCapabilities = Gd.FormatCapabilities;
+ Span<int> newVbScalarSizes = stackalloc int[Constants.MaxVertexBuffers];
+
int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
+ uint dirtyVbSizes = 0;
for (int i = 0; i < count; i++)
{
var attribute = vertexAttribs[i];
- var bufferIndex = attribute.IsZero ? 0 : attribute.BufferIndex + 1;
+ var rawIndex = attribute.BufferIndex;
+ var bufferIndex = attribute.IsZero ? 0 : rawIndex + 1;
+
+ if (!attribute.IsZero)
+ {
+ newVbScalarSizes[rawIndex] = Math.Max(newVbScalarSizes[rawIndex], attribute.Format.GetScalarSize());
+ dirtyVbSizes |= 1u << rawIndex;
+ }
_newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
(uint)i,
@@ -746,6 +778,21 @@ namespace Ryujinx.Graphics.Vulkan
(uint)attribute.Offset);
}
+ while (dirtyVbSizes != 0)
+ {
+ int dirtyBit = BitOperations.TrailingZeroCount(dirtyVbSizes);
+
+ ref var buffer = ref _vertexBuffers[dirtyBit + 1];
+
+ if (buffer.AttributeScalarAlignment != newVbScalarSizes[dirtyBit])
+ {
+ _vertexBuffersDirty |= 1UL << (dirtyBit + 1);
+ buffer.AttributeScalarAlignment = newVbScalarSizes[dirtyBit];
+ }
+
+ dirtyVbSizes &= ~(1u << dirtyBit);
+ }
+
_newState.VertexAttributeDescriptionsCount = (uint)count;
SignalStateChange();
}
@@ -792,14 +839,37 @@ namespace Ryujinx.Graphics.Vulkan
}
}
- _vertexBuffers[binding].Dispose();
- _vertexBuffers[binding] = new BufferState(
- vb,
- vertexBuffer.Buffer.Offset,
- vbSize,
- (ulong)vertexBuffer.Stride);
+ ref var buffer = ref _vertexBuffers[binding];
+ int oldScalarAlign = buffer.AttributeScalarAlignment;
+
+ buffer.Dispose();
+
+ if ((vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0)
+ {
+ buffer = new VertexBufferState(
+ vb,
+ descriptorIndex,
+ vertexBuffer.Buffer.Offset,
+ vbSize,
+ vertexBuffer.Stride);
+
+ buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState);
+ }
+ else
+ {
+ // May need to be rewritten. Bind this buffer before draw.
+
+ buffer = new VertexBufferState(
+ vertexBuffer.Buffer.Handle,
+ descriptorIndex,
+ vertexBuffer.Buffer.Offset,
+ vbSize,
+ vertexBuffer.Stride);
+
+ _vertexBuffersDirty |= 1UL << binding;
+ }
- _vertexBuffers[binding].BindVertexBuffer(Gd, Cbs, (uint)binding);
+ buffer.AttributeScalarAlignment = oldScalarAlign;
}
}
}
@@ -907,7 +977,7 @@ namespace Ryujinx.Graphics.Vulkan
{
_needsIndexBufferRebind = true;
_needsTransformFeedbackBuffersRebind = true;
- _needsVertexBuffersRebind = true;
+ _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
_descriptorSetUpdater.SignalCommandBufferChange();
_dynamicState.ForceAllDirty();
@@ -1053,13 +1123,6 @@ namespace Ryujinx.Graphics.Vulkan
// Commit changes to the support buffer before drawing.
SupportBufferUpdater.Commit();
- if (_stateDirty || Pbp != pbp)
- {
- CreatePipeline(pbp);
- _stateDirty = false;
- Pbp = pbp;
- }
-
if (_needsIndexBufferRebind)
{
_indexBuffer.BindIndexBuffer(Gd.Api, Cbs);
@@ -1078,14 +1141,23 @@ namespace Ryujinx.Graphics.Vulkan
_needsTransformFeedbackBuffersRebind = false;
}
- if (_needsVertexBuffersRebind)
+ if (_vertexBuffersDirty != 0)
{
- for (int i = 0; i < Constants.MaxVertexBuffers + 1; i++)
+ while (_vertexBuffersDirty != 0)
{
- _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i);
+ int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty);
+
+ _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState);
+
+ _vertexBuffersDirty &= ~(1u << i);
}
+ }
- _needsVertexBuffersRebind = false;
+ if (_stateDirty || Pbp != pbp)
+ {
+ CreatePipeline(pbp);
+ _stateDirty = false;
+ Pbp = pbp;
}
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, pbp);