aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/HelperShader.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2022-11-16 14:53:04 -0300
committerGitHub <noreply@github.com>2022-11-16 14:53:04 -0300
commitf1d1670b0b1b5c08064df95dabd295f3cf5dcf7f (patch)
tree082139cb80ee9776f3ea9083991fb3ed6618f7f4 /Ryujinx.Graphics.Vulkan/HelperShader.cs
parentb8de72de8f25f0bb7f994bc07a0387c1c247b6fe (diff)
Implement HLE macro for DrawElementsIndirect (#3748)1.1.345
* Implement HLE macro for DrawElementsIndirect * Shader cache version bump * Use GL_ARB_shader_draw_parameters extension on OpenGL * Fix DrawIndexedIndirectCount on Vulkan when extension is not supported * Implement DrawIndex * Alignment * Fix some validation errors * Rename BaseIds to DrawParameters * Fix incorrect index buffer and vertex buffer size in some cases * Add HLE macros for DrawArraysInstanced and DrawElementsInstanced * Perform a regular draw when indirect data is not modified * Use non-indirect draw methods if indirect buffer was not GPU modified * Only check if draw parameters match if the shader actually uses them * Expose Macro HLE setting on GUI * Reset FirstVertex and FirstInstance after draw * Update shader cache version again since some people already tested this * PR feedback Co-authored-by: riperiperi <rhy3756547@hotmail.com>
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/HelperShader.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/HelperShader.cs159
1 files changed, 158 insertions, 1 deletions
diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs
index c842b922..1ef22dc2 100644
--- a/Ryujinx.Graphics.Vulkan/HelperShader.cs
+++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs
@@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Vulkan
{
class HelperShader : IDisposable
{
+ private const int UniformBufferAlignment = 256;
+
private readonly PipelineHelperShader _pipeline;
private readonly ISampler _samplerLinear;
private readonly ISampler _samplerNearest;
@@ -19,6 +21,8 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IProgram _programColorClear;
private readonly IProgram _programStrideChange;
private readonly IProgram _programColorCopyBetweenMsNonMs;
+ private readonly IProgram _programConvertIndexBuffer;
+ private readonly IProgram _programConvertIndirectData;
public HelperShader(VulkanRenderer gd, Device device)
{
@@ -88,6 +92,28 @@ namespace Ryujinx.Graphics.Vulkan
{
new SpecDescription((0, SpecConstType.Int32))
});
+
+ var convertIndexBufferBindings = new ShaderBindings(
+ new[] { 0 },
+ new[] { 1, 2 },
+ Array.Empty<int>(),
+ Array.Empty<int>());
+
+ _programConvertIndexBuffer = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ConvertIndexBufferShaderSource, convertIndexBufferBindings, ShaderStage.Compute, TargetLanguage.Spirv),
+ });
+
+ var convertIndirectDataBindings = new ShaderBindings(
+ new[] { 0 },
+ new[] { 1, 2, 3 },
+ Array.Empty<int>(),
+ Array.Empty<int>());
+
+ _programConvertIndirectData = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ConvertIndirectDataShaderSource, convertIndirectDataBindings, ShaderStage.Compute, TargetLanguage.Spirv),
+ });
}
public void Blit(
@@ -408,10 +434,12 @@ namespace Ryujinx.Graphics.Vulkan
int srcOffset,
int indexCount)
{
+ // TODO: Support conversion with primitive restart enabled.
+ // TODO: Convert with a compute shader?
+
int convertedCount = pattern.GetConvertedCount(indexCount);
int outputIndexSize = 4;
- // TODO: Do this with a compute shader?
var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, indexCount * indexSize).Value;
var dstBuffer = dst.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
@@ -671,6 +699,133 @@ namespace Ryujinx.Graphics.Vulkan
};
}
+ public void ConvertIndexBufferIndirect(
+ VulkanRenderer gd,
+ CommandBufferScoped cbs,
+ BufferHolder srcIndirectBuffer,
+ BufferHolder dstIndirectBuffer,
+ BufferRange drawCountBuffer,
+ BufferHolder srcIndexBuffer,
+ BufferHolder dstIndexBuffer,
+ IndexBufferPattern pattern,
+ int indexSize,
+ int srcIndexBufferOffset,
+ int srcIndexBufferSize,
+ int srcIndirectBufferOffset,
+ bool hasDrawCount,
+ int maxDrawCount,
+ int indirectDataStride)
+ {
+ // TODO: Support conversion with primitive restart enabled.
+
+ BufferRange drawCountBufferAligned = new BufferRange(
+ drawCountBuffer.Handle,
+ drawCountBuffer.Offset & ~(UniformBufferAlignment - 1),
+ UniformBufferAlignment);
+
+ int indirectDataSize = maxDrawCount * indirectDataStride;
+
+ int indexCount = srcIndexBufferSize / indexSize;
+ int primitivesCount = pattern.GetPrimitiveCount(indexCount);
+ int convertedCount = pattern.GetConvertedCount(indexCount);
+ int outputIndexSize = 4;
+
+ var srcBuffer = srcIndexBuffer.GetBuffer().Get(cbs, srcIndexBufferOffset, indexCount * indexSize).Value;
+ var dstBuffer = dstIndexBuffer.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
+
+ const int ParamsBufferSize = 24 * sizeof(int);
+ const int ParamsIndirectDispatchOffset = 16 * sizeof(int);
+ const int ParamsIndirectDispatchSize = 3 * sizeof(int);
+
+ Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
+
+ shaderParams[8] = pattern.PrimitiveVertices;
+ shaderParams[9] = pattern.PrimitiveVerticesOut;
+ shaderParams[10] = indexSize;
+ shaderParams[11] = outputIndexSize;
+ shaderParams[12] = pattern.BaseIndex;
+ shaderParams[13] = pattern.IndexStride;
+ shaderParams[14] = srcIndexBufferOffset;
+ shaderParams[15] = primitivesCount;
+ shaderParams[16] = 1;
+ shaderParams[17] = 1;
+ shaderParams[18] = 1;
+ shaderParams[19] = hasDrawCount ? 1 : 0;
+ shaderParams[20] = maxDrawCount;
+ shaderParams[21] = (drawCountBuffer.Offset & (UniformBufferAlignment - 1)) / 4;
+ shaderParams[22] = indirectDataStride / 4;
+ shaderParams[23] = srcIndirectBufferOffset / 4;
+
+ pattern.OffsetIndex.CopyTo(shaderParams.Slice(0, pattern.OffsetIndex.Length));
+
+ var patternBufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false, out var patternBuffer);
+ var patternBufferAuto = patternBuffer.GetBuffer();
+
+ gd.BufferManager.SetData<int>(patternBufferHandle, 0, shaderParams);
+
+ _pipeline.SetCommandBuffer(cbs);
+
+ BufferHolder.InsertBufferBarrier(
+ gd,
+ cbs.CommandBuffer,
+ srcIndirectBuffer.GetBuffer().Get(cbs, srcIndirectBufferOffset, indirectDataSize).Value,
+ BufferHolder.DefaultAccessFlags,
+ AccessFlags.AccessShaderReadBit,
+ PipelineStageFlags.PipelineStageAllCommandsBit,
+ PipelineStageFlags.PipelineStageComputeShaderBit,
+ srcIndirectBufferOffset,
+ indirectDataSize);
+
+ _pipeline.SetUniformBuffers(0, stackalloc[] { drawCountBufferAligned });
+ _pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer(), patternBuffer.GetBuffer() });
+
+ _pipeline.SetProgram(_programConvertIndirectData);
+ _pipeline.DispatchCompute(1, 1, 1);
+
+ BufferHolder.InsertBufferBarrier(
+ gd,
+ cbs.CommandBuffer,
+ patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
+ AccessFlags.AccessShaderWriteBit,
+ AccessFlags.AccessIndirectCommandReadBit,
+ PipelineStageFlags.PipelineStageComputeShaderBit,
+ PipelineStageFlags.PipelineStageDrawIndirectBit,
+ ParamsIndirectDispatchOffset,
+ ParamsIndirectDispatchSize);
+
+ BufferHolder.InsertBufferBarrier(
+ gd,
+ cbs.CommandBuffer,
+ dstBuffer,
+ BufferHolder.DefaultAccessFlags,
+ AccessFlags.AccessTransferWriteBit,
+ PipelineStageFlags.PipelineStageAllCommandsBit,
+ PipelineStageFlags.PipelineStageTransferBit,
+ 0,
+ convertedCount * outputIndexSize);
+
+ _pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(patternBufferHandle, 0, ParamsBufferSize) });
+ _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
+
+ _pipeline.SetProgram(_programConvertIndexBuffer);
+ _pipeline.DispatchComputeIndirect(patternBufferAuto, ParamsIndirectDispatchOffset);
+
+ BufferHolder.InsertBufferBarrier(
+ gd,
+ cbs.CommandBuffer,
+ dstBuffer,
+ AccessFlags.AccessTransferWriteBit,
+ BufferHolder.DefaultAccessFlags,
+ PipelineStageFlags.PipelineStageTransferBit,
+ PipelineStageFlags.PipelineStageAllCommandsBit,
+ 0,
+ convertedCount * outputIndexSize);
+
+ gd.BufferManager.Delete(patternBufferHandle);
+
+ _pipeline.Finish(gd, cbs);
+ }
+
protected virtual void Dispose(bool disposing)
{
if (disposing)
@@ -680,6 +835,8 @@ namespace Ryujinx.Graphics.Vulkan
_programColorClear.Dispose();
_programStrideChange.Dispose();
_programColorCopyBetweenMsNonMs.Dispose();
+ _programConvertIndexBuffer.Dispose();
+ _programConvertIndirectData.Dispose();
_samplerNearest.Dispose();
_samplerLinear.Dispose();
_pipeline.Dispose();