Use compute shader for non indirect index buffer conversion
This commit is contained in:
parent
398fa1c238
commit
3005c38a63
2 changed files with 26 additions and 60 deletions
|
@ -896,57 +896,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,
|
||||||
|
@ -959,10 +944,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(1, 1, 1);
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
|
@ -974,6 +960,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);
|
||||||
|
|
Loading…
Reference in a new issue