Use compute shader for non-indirect index buffer conversion

* Fix >16 primitives
This commit is contained in:
Isaac Marovitz
2025-03-24 22:01:28 -05:00
committed by KeatonTheBot
parent f825413b0d
commit 8f55589124
2 changed files with 26 additions and 60 deletions
+26 -38
View File
@@ -873,57 +873,42 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe void ConvertIndexBuffer(VulkanRenderer gd, public unsafe void ConvertIndexBuffer(VulkanRenderer gd,
CommandBufferScoped cbs, CommandBufferScoped cbs,
BufferHolder src, BufferHolder srcIndexBuffer,
BufferHolder dst, BufferHolder dstIndexBuffer,
IndexBufferPattern pattern, IndexBufferPattern pattern,
int indexSize, int indexSize,
int srcOffset, int srcOffset,
int indexCount) int indexCount)
{ {
// TODO: Support conversion with primitive restart enabled. // TODO: Support conversion with primitive restart enabled.
// TODO: Convert with a compute shader?
int primitiveCount = pattern.GetPrimitiveCount(indexCount);
int convertedCount = pattern.GetConvertedCount(indexCount); int convertedCount = pattern.GetConvertedCount(indexCount);
int outputIndexSize = 4; int outputIndexSize = 4;
var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, indexCount * indexSize).Value; var dstBuffer = dstIndexBuffer.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
var dstBuffer = dst.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<BufferCopy>(); Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
int outputOffset = 0;
// Try to merge copies of adjacent indices to reduce copy count. shaderParams[8] = pattern.PrimitiveVertices;
int sequenceStart = 0; shaderParams[9] = pattern.PrimitiveVerticesOut;
int sequenceLength = 0; 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)) pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
{
if (sequenceLength > 0)
{
if (index == sequenceStart + sequenceLength && indexSize == outputIndexSize)
{
sequenceLength++;
continue;
}
// Commit the copy so far. using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength))); var patternBuffer = patternScoped.Holder;
outputOffset += outputIndexSize * sequenceLength;
}
sequenceStart = index; patternBuffer.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
sequenceLength = 1;
}
if (sequenceLength > 0) _pipeline.SetCommandBuffer(cbs);
{
// Commit final pending copy.
bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength)));
}
var bufferCopyArray = bufferCopy.ToArray();
BufferHolder.InsertBufferBarrier( BufferHolder.InsertBufferBarrier(
gd, gd,
@@ -936,10 +921,11 @@ namespace Ryujinx.Graphics.Vulkan
0, 0,
convertedCount * outputIndexSize); convertedCount * outputIndexSize);
fixed (BufferCopy* pBufferCopy = bufferCopyArray) _pipeline.SetUniformBuffers([new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize))]);
{ _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)bufferCopyArray.Length, pBufferCopy);
} _pipeline.SetProgram(_programConvertIndexBuffer);
_pipeline.DispatchCompute(BitUtils.DivRoundUp(primitiveCount, 16), 1, 1);
BufferHolder.InsertBufferBarrier( BufferHolder.InsertBufferBarrier(
gd, gd,
@@ -951,6 +937,8 @@ namespace Ryujinx.Graphics.Vulkan
PipelineStageFlags.AllCommandsBit, PipelineStageFlags.AllCommandsBit,
0, 0,
convertedCount * outputIndexSize); convertedCount * outputIndexSize);
_pipeline.Finish(gd, cbs);
} }
public void CopyIncompatibleFormats( public void CopyIncompatibleFormats(
@@ -47,28 +47,6 @@ namespace Ryujinx.Graphics.Vulkan
return primitiveCount * OffsetIndex.Length; return primitiveCount * OffsetIndex.Length;
} }
public IEnumerable<int> 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) public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount)
{ {
int primitiveCount = GetPrimitiveCount(vertexCount); int primitiveCount = GetPrimitiveCount(vertexCount);