aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Translation/Optimizations
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2024-04-22 15:05:55 -0300
committerGitHub <noreply@github.com>2024-04-22 15:05:55 -0300
commitc6f8bfed904e30f7c5d890a2f0ef531eb9e298e5 (patch)
treee1c048d390867e8c9403904498184e3a64277e49 /src/Ryujinx.Graphics.Shader/Translation/Optimizations
parent9b94662b4bb2ebf846e1baf45ba8097fcd7da684 (diff)
Add support for bindless textures from shader input (vertex buffer) on Vulkan (#6577)
* Add support for bindless textures from shader input (vertex buffer) * Shader cache version bump * Format whitespace * Remove cache entries on pool removal, disable for OpenGL * PR feedback
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/Optimizations')
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs86
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs2
2 files changed, 86 insertions, 2 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index ad955278..22321543 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -1,6 +1,7 @@
using Ryujinx.Graphics.Shader.Instructions;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
@@ -31,7 +32,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- if (!TryConvertBindless(block, resourceManager, gpuAccessor, texOp))
+ if (!TryConvertBindless(block, resourceManager, gpuAccessor, texOp) &&
+ !GenerateBindlessAccess(block, resourceManager, gpuAccessor, texOp, node))
{
// If we can't do bindless elimination, remove the texture operation.
// Set any destination variables to zero.
@@ -46,6 +48,88 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
}
}
+ private static bool GenerateBindlessAccess(
+ BasicBlock block,
+ ResourceManager resourceManager,
+ IGpuAccessor gpuAccessor,
+ TextureOperation texOp,
+ LinkedListNode<INode> node)
+ {
+ if (!gpuAccessor.QueryHostSupportsSeparateSampler())
+ {
+ // We depend on combining samplers and textures in the shader being supported for this.
+
+ return false;
+ }
+
+ Operand nvHandle = texOp.GetSource(0);
+
+ if (nvHandle.AsgOp is not Operation handleOp ||
+ handleOp.Inst != Instruction.Load ||
+ handleOp.StorageKind != StorageKind.Input)
+ {
+ // Right now, we only allow bindless access when the handle comes from a shader input.
+ // This is an artificial limitation to prevent it from being used in cases where it
+ // would have a large performance impact of loading all textures in the pool.
+ // It might be removed in the future, if we can mitigate the performance impact.
+
+ return false;
+ }
+
+ Operand textureHandle = OperandHelper.Local();
+ Operand samplerHandle = OperandHelper.Local();
+ Operand textureIndex = OperandHelper.Local();
+
+ block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, nvHandle, OperandHelper.Const(0xfffff)));
+ block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, nvHandle, OperandHelper.Const(20)));
+
+ int texturePoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromPool());
+
+ block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, textureIndex, textureHandle, OperandHelper.Const(texturePoolLength - 1)));
+
+ texOp.SetSource(0, textureIndex);
+
+ bool hasSampler = !texOp.Inst.IsImage();
+
+ int textureBinding = resourceManager.GetTextureOrImageBinding(
+ texOp.Inst,
+ texOp.Type,
+ texOp.Format,
+ texOp.Flags & ~TextureFlags.Bindless,
+ 0,
+ TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
+ texturePoolLength,
+ hasSampler);
+
+ if (hasSampler)
+ {
+ Operand samplerIndex = OperandHelper.Local();
+
+ int samplerPoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QuerySamplerArrayLengthFromPool());
+
+ block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, samplerIndex, samplerHandle, OperandHelper.Const(samplerPoolLength - 1)));
+
+ texOp.InsertSource(1, samplerIndex);
+
+ int samplerBinding = resourceManager.GetTextureOrImageBinding(
+ texOp.Inst,
+ SamplerType.None,
+ texOp.Format,
+ TextureFlags.None,
+ 0,
+ TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
+ samplerPoolLength);
+
+ texOp.TurnIntoArray(textureBinding, samplerBinding);
+ }
+ else
+ {
+ texOp.TurnIntoArray(textureBinding);
+ }
+
+ return true;
+ }
+
private static bool TryConvertBindless(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor, TextureOperation texOp)
{
if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery())
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
index 7543d1c2..f2be7975 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
private const int HardcodedArrayLengthOgl = 4;
// 1 and 0 elements are not considered arrays anymore.
- private const int MinimumArrayLength = 2;
+ public const int MinimumArrayLength = 2;
public static void RunPassOgl(BasicBlock block, ResourceManager resourceManager)
{