Restride vertex buffer when stride causes attributes to misalign in Vulkan. (#3679)
* 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.
This commit is contained in:
parent
ee1825219b
commit
c6d82209ab
18 changed files with 1069 additions and 120 deletions
|
@ -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;
|
||||
|
||||
_vertexBuffers[binding].BindVertexBuffer(Gd, Cbs, (uint)binding);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
_needsVertexBuffersRebind = false;
|
||||
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState);
|
||||
|
||||
_vertexBuffersDirty &= ~(1u << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (_stateDirty || Pbp != pbp)
|
||||
{
|
||||
CreatePipeline(pbp);
|
||||
_stateDirty = false;
|
||||
Pbp = pbp;
|
||||
}
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, pbp);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue