aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Translation
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation')
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs86
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs2
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs32
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs6
4 files changed, 115 insertions, 11 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)
{
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
index e9fe0b1e..890501c9 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
@@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly HashSet<int> _usedConstantBufferBindings;
- private readonly record struct TextureInfo(int CbufSlot, int Handle, int ArrayLength, SamplerType Type, TextureFormat Format);
+ private readonly record struct TextureInfo(int CbufSlot, int Handle, int ArrayLength, bool Separate, SamplerType Type, TextureFormat Format);
private struct TextureMeta
{
@@ -225,7 +225,8 @@ namespace Ryujinx.Graphics.Shader.Translation
TextureFlags flags,
int cbufSlot,
int handle,
- int arrayLength = 1)
+ int arrayLength = 1,
+ bool separate = false)
{
inst &= Instruction.Mask;
bool isImage = inst.IsImage();
@@ -239,7 +240,18 @@ namespace Ryujinx.Graphics.Shader.Translation
format = TextureFormat.Unknown;
}
- int binding = GetTextureOrImageBinding(cbufSlot, handle, arrayLength, type, format, isImage, intCoords, isWrite, accurateType, coherent);
+ int binding = GetTextureOrImageBinding(
+ cbufSlot,
+ handle,
+ arrayLength,
+ type,
+ format,
+ isImage,
+ intCoords,
+ isWrite,
+ accurateType,
+ coherent,
+ separate);
_gpuAccessor.RegisterTexture(handle, cbufSlot);
@@ -256,9 +268,10 @@ namespace Ryujinx.Graphics.Shader.Translation
bool intCoords,
bool write,
bool accurateType,
- bool coherent)
+ bool coherent,
+ bool separate)
{
- var dimensions = type.GetDimensions();
+ var dimensions = type == SamplerType.None ? 0 : type.GetDimensions();
var dict = isImage ? _usedImages : _usedTextures;
var usageFlags = TextureUsageFlags.None;
@@ -290,7 +303,7 @@ namespace Ryujinx.Graphics.Shader.Translation
// For array textures, we also want to use type as key,
// since we may have texture handles stores in the same buffer, but for textures with different types.
var keyType = arrayLength > 1 ? type : SamplerType.None;
- var info = new TextureInfo(cbufSlot, handle, arrayLength, keyType, format);
+ var info = new TextureInfo(cbufSlot, handle, arrayLength, separate, keyType, format);
var meta = new TextureMeta()
{
AccurateType = accurateType,
@@ -332,6 +345,10 @@ namespace Ryujinx.Graphics.Shader.Translation
? $"{prefix}_tcb_{handle:X}_{format.ToGlslFormat()}"
: $"{prefix}_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}";
}
+ else if (type == SamplerType.None)
+ {
+ nameSuffix = cbufSlot < 0 ? $"s_tcb_{handle:X}" : $"s_cb{cbufSlot}_{handle:X}";
+ }
else
{
nameSuffix = cbufSlot < 0 ? $"{prefix}_tcb_{handle:X}" : $"{prefix}_cb{cbufSlot}_{handle:X}";
@@ -341,6 +358,7 @@ namespace Ryujinx.Graphics.Shader.Translation
isImage ? 3 : 2,
binding,
arrayLength,
+ separate,
$"{_stagePrefix}_{nameSuffix}",
meta.Type,
info.Format,
@@ -495,6 +513,7 @@ namespace Ryujinx.Graphics.Shader.Translation
info.CbufSlot,
info.Handle,
info.ArrayLength,
+ info.Separate,
meta.UsageFlags));
}
@@ -514,6 +533,7 @@ namespace Ryujinx.Graphics.Shader.Translation
info.CbufSlot,
info.Handle,
info.ArrayLength,
+ info.Separate,
meta.UsageFlags));
}
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
index 581f4372..10653558 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
@@ -413,7 +413,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (Stage == ShaderStage.Vertex)
{
int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding;
- TextureDefinition indexBuffer = new(2, ibBinding, 1, "ib_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None);
+ TextureDefinition indexBuffer = new(2, ibBinding, "ib_data", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
int inputMap = _program.AttributeUsage.UsedInputAttributes;
@@ -422,7 +422,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
int location = BitOperations.TrailingZeroCount(inputMap);
int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location);
- TextureDefinition vaBuffer = new(2, binding, 1, $"vb_data{location}", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None);
+ TextureDefinition vaBuffer = new(2, binding, $"vb_data{location}", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
inputMap &= ~(1 << location);
@@ -431,7 +431,7 @@ namespace Ryujinx.Graphics.Shader.Translation
else if (Stage == ShaderStage.Geometry)
{
int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding;
- TextureDefinition remapBuffer = new(2, trbBinding, 1, "trb_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None);
+ TextureDefinition remapBuffer = new(2, trbBinding, "trb_data", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;