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/HelperShader.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/HelperShader.cs')
-rw-r--r-- | Ryujinx.Graphics.Vulkan/HelperShader.cs | 115 |
1 files changed, 91 insertions, 24 deletions
diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs index 8465c744..2eec92f0 100644 --- a/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan private readonly IProgram _programColorBlit; private readonly IProgram _programColorBlitClearAlpha; private readonly IProgram _programColorClear; + private readonly IProgram _programStrideChange; public HelperShader(VulkanRenderer gd, Device device) { @@ -39,14 +40,14 @@ namespace Ryujinx.Graphics.Vulkan _programColorBlit = gd.CreateProgramWithMinimalLayout(new[] { - new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl), - new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl), + new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); _programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[] { - new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl), - new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl), + new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); var fragmentBindings2 = new ShaderBindings( @@ -57,8 +58,19 @@ namespace Ryujinx.Graphics.Vulkan _programColorClear = gd.CreateProgramWithMinimalLayout(new[] { - new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl), - new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Glsl), + new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Spirv), + }); + + var strideChangeBindings = new ShaderBindings( + new[] { 0 }, + new[] { 1, 2 }, + Array.Empty<int>(), + Array.Empty<int>()); + + _programStrideChange = gd.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, strideChangeBindings, ShaderStage.Compute, TargetLanguage.Spirv), }); } @@ -163,7 +175,7 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetViewports(viewports, false); _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip); _pipeline.Draw(4, 1, 0, 0); - _pipeline.Finish(); + _pipeline.Finish(gd, cbs); gd.BufferManager.Delete(bufferHandle); } @@ -291,45 +303,100 @@ namespace Ryujinx.Graphics.Vulkan public unsafe void ConvertI8ToI16(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size) { - // TODO: Do this with a compute shader? - var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, size).Value; - var dstBuffer = dst.GetBuffer().Get(cbs, 0, size * 2).Value; + ChangeStride(gd, cbs, src, dst, srcOffset, size, 1, 2); + } - gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0); + public unsafe void ChangeStride(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size, int stride, int newStride) + { + bool supportsUint8 = gd.Capabilities.SupportsShaderInt8; - var bufferCopy = new BufferCopy[size]; + int elems = size / stride; + int newSize = elems * newStride; - for (ulong i = 0; i < (ulong)size; i++) - { - bufferCopy[i] = new BufferCopy((ulong)srcOffset + i, i * 2, 1); - } + var srcBufferAuto = src.GetBuffer(); + var dstBufferAuto = dst.GetBuffer(); + + var srcBuffer = srcBufferAuto.Get(cbs, srcOffset, size).Value; + var dstBuffer = dstBufferAuto.Get(cbs, 0, newSize).Value; + + var access = supportsUint8 ? AccessFlags.AccessShaderWriteBit : AccessFlags.AccessTransferWriteBit; + var stage = supportsUint8 ? PipelineStageFlags.PipelineStageComputeShaderBit : PipelineStageFlags.PipelineStageTransferBit; BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, dstBuffer, BufferHolder.DefaultAccessFlags, - AccessFlags.AccessTransferWriteBit, + access, PipelineStageFlags.PipelineStageAllCommandsBit, - PipelineStageFlags.PipelineStageTransferBit, + stage, 0, - size * 2); + newSize); - fixed (BufferCopy* pBufferCopy = bufferCopy) + if (supportsUint8) { - gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)size, pBufferCopy); + const int ParamsBufferSize = 16; + + Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)]; + + shaderParams[0] = stride; + shaderParams[1] = newStride; + shaderParams[2] = size; + shaderParams[3] = srcOffset; + + var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false); + + gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams); + + _pipeline.SetCommandBuffer(cbs); + + Span<BufferRange> cbRanges = stackalloc BufferRange[1]; + + cbRanges[0] = new BufferRange(bufferHandle, 0, ParamsBufferSize); + + _pipeline.SetUniformBuffers(0, cbRanges); + + Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2]; + + sbRanges[0] = srcBufferAuto; + sbRanges[1] = dstBufferAuto; + + _pipeline.SetStorageBuffers(1, sbRanges); + + _pipeline.SetProgram(_programStrideChange); + _pipeline.DispatchCompute(1, 1, 1); + + gd.BufferManager.Delete(bufferHandle); + + _pipeline.Finish(gd, cbs); + } + else + { + gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0); + + var bufferCopy = new BufferCopy[elems]; + + for (ulong i = 0; i < (ulong)elems; i++) + { + bufferCopy[i] = new BufferCopy((ulong)srcOffset + i * (ulong)stride, i * (ulong)newStride, (ulong)stride); + } + + fixed (BufferCopy* pBufferCopy = bufferCopy) + { + gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)elems, pBufferCopy); + } } BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, dstBuffer, - AccessFlags.AccessTransferWriteBit, + access, BufferHolder.DefaultAccessFlags, - PipelineStageFlags.PipelineStageTransferBit, + stage, PipelineStageFlags.PipelineStageAllCommandsBit, 0, - size * 2); + newSize); } protected virtual void Dispose(bool disposing) |