From 3005c38a63eaca5486786f129299639ea18a093d Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Sun, 1 Sep 2024 23:25:38 +0200 Subject: [PATCH 1/2] Use compute shader for non indirect index buffer conversion --- src/Ryujinx.Graphics.Vulkan/HelperShader.cs | 64 ++++++++----------- .../IndexBufferPattern.cs | 22 ------- 2 files changed, 26 insertions(+), 60 deletions(-) diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs index 73aa95c74..05a6c7c43 100644 --- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -896,57 +896,42 @@ namespace Ryujinx.Graphics.Vulkan public unsafe void ConvertIndexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, - BufferHolder src, - BufferHolder dst, + BufferHolder srcIndexBuffer, + BufferHolder dstIndexBuffer, IndexBufferPattern pattern, int indexSize, int srcOffset, int indexCount) { // TODO: Support conversion with primitive restart enabled. - // TODO: Convert with a compute shader? + int primitiveCount = pattern.GetPrimitiveCount(indexCount); int convertedCount = pattern.GetConvertedCount(indexCount); int outputIndexSize = 4; - var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, indexCount * indexSize).Value; - var dstBuffer = dst.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value; + var dstBuffer = dstIndexBuffer.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value; - gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0); + const int ParamsBufferSize = 16 * sizeof(int); - var bufferCopy = new List(); - int outputOffset = 0; + Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)]; - // Try to merge copies of adjacent indices to reduce copy count. - int sequenceStart = 0; - int sequenceLength = 0; + shaderParams[8] = pattern.PrimitiveVertices; + shaderParams[9] = pattern.PrimitiveVerticesOut; + shaderParams[10] = indexSize; + shaderParams[11] = outputIndexSize; + shaderParams[12] = pattern.BaseIndex; + shaderParams[13] = pattern.IndexStride; + shaderParams[14] = srcOffset; + shaderParams[15] = primitiveCount; - foreach (var index in pattern.GetIndexMapping(indexCount)) - { - if (sequenceLength > 0) - { - if (index == sequenceStart + sequenceLength && indexSize == outputIndexSize) - { - sequenceLength++; - continue; - } + pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]); - // Commit the copy so far. - bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength))); - outputOffset += outputIndexSize * sequenceLength; - } + using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); + var patternBuffer = patternScoped.Holder; - sequenceStart = index; - sequenceLength = 1; - } + patternBuffer.SetDataUnchecked(patternScoped.Offset, shaderParams); - if (sequenceLength > 0) - { - // Commit final pending copy. - bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength))); - } - - var bufferCopyArray = bufferCopy.ToArray(); + _pipeline.SetCommandBuffer(cbs); BufferHolder.InsertBufferBarrier( gd, @@ -959,10 +944,11 @@ namespace Ryujinx.Graphics.Vulkan 0, convertedCount * outputIndexSize); - fixed (BufferCopy* pBufferCopy = bufferCopyArray) - { - gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)bufferCopyArray.Length, pBufferCopy); - } + _pipeline.SetUniformBuffers([new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize))]); + _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() }); + + _pipeline.SetProgram(_programConvertIndexBuffer); + _pipeline.DispatchCompute(1, 1, 1); BufferHolder.InsertBufferBarrier( gd, @@ -974,6 +960,8 @@ namespace Ryujinx.Graphics.Vulkan PipelineStageFlags.AllCommandsBit, 0, convertedCount * outputIndexSize); + + _pipeline.Finish(gd, cbs); } public void CopyIncompatibleFormats( diff --git a/src/Ryujinx.Graphics.Vulkan/IndexBufferPattern.cs b/src/Ryujinx.Graphics.Vulkan/IndexBufferPattern.cs index 7b01dd4ca..9054b2e71 100644 --- a/src/Ryujinx.Graphics.Vulkan/IndexBufferPattern.cs +++ b/src/Ryujinx.Graphics.Vulkan/IndexBufferPattern.cs @@ -47,28 +47,6 @@ namespace Ryujinx.Graphics.Vulkan return primitiveCount * OffsetIndex.Length; } - public IEnumerable GetIndexMapping(int indexCount) - { - int primitiveCount = GetPrimitiveCount(indexCount); - int index = BaseIndex; - - for (int i = 0; i < primitiveCount; i++) - { - if (RepeatStart) - { - // Used for triangle fan - yield return 0; - } - - for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++) - { - yield return index + OffsetIndex[j]; - } - - index += IndexStride; - } - } - public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount) { int primitiveCount = GetPrimitiveCount(vertexCount); From e994e7826b95c765e17ce3fb3c732649ee420aed Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Mon, 2 Sep 2024 10:23:27 +0200 Subject: [PATCH 2/2] Fix >16 primitives --- src/Ryujinx.Graphics.Vulkan/HelperShader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs index 05a6c7c43..4e89603d8 100644 --- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -948,7 +948,7 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() }); _pipeline.SetProgram(_programConvertIndexBuffer); - _pipeline.DispatchCompute(1, 1, 1); + _pipeline.DispatchCompute(BitUtils.DivRoundUp(primitiveCount, 16), 1, 1); BufferHolder.InsertBufferBarrier( gd,