diff options
author | riperiperi <rhy3756547@hotmail.com> | 2022-09-09 00:30:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-08 20:30:19 -0300 |
commit | c6d82209abeacd2336cde99e5a02b4596e70da83 (patch) | |
tree | 8dc8e1055f402c07e6ed9e4ff247ca420729808c /Ryujinx.Graphics.Vulkan/PipelineBase.cs | |
parent | ee1825219b8ccca13df7198d4e9ffb966e44c883 (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.cs | 122 |
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); |