aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-05-27 11:07:10 -0300
committerGitHub <noreply@github.com>2020-05-27 16:07:10 +0200
commit5795bb15282498b3824a5d15fe1ff78b85a18c23 (patch)
tree6d4ee54c218e81fc6efaad279a5b1ade3ca8ec59 /Ryujinx.Graphics.Shader/Translation
parent0b6d206daad7202d4e271118b631feb7dd363bbc (diff)
Support separate textures and samplers (#1216)
* Support separate textures and samplers * Add missing bindless flag, fix SNORM format on buffer textures * Add missing separation * Add comments about the new handles
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Lowering.cs65
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs50
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs17
3 files changed, 130 insertions, 2 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/Lowering.cs b/Ryujinx.Graphics.Shader/Translation/Lowering.cs
index 6f52ce96..6da25983 100644
--- a/Ryujinx.Graphics.Shader/Translation/Lowering.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Lowering.cs
@@ -1,6 +1,7 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
using static Ryujinx.Graphics.Shader.Translation.GlobalMemory;
@@ -27,9 +28,17 @@ namespace Ryujinx.Graphics.Shader.Translation
node = RewriteGlobalAccess(node, config);
}
- if (operation.Inst == Instruction.TextureSample)
+ if (operation is TextureOperation texOp)
{
- node = RewriteTextureSample(node, config);
+ if (texOp.Inst == Instruction.TextureSample)
+ {
+ node = RewriteTextureSample(node, config);
+ }
+
+ if (texOp.Type == SamplerType.TextureBuffer)
+ {
+ node = InsertSnormNormalization(node, config);
+ }
}
}
}
@@ -419,5 +428,57 @@ namespace Ryujinx.Graphics.Shader.Translation
return node;
}
+
+ private static LinkedListNode<INode> InsertSnormNormalization(LinkedListNode<INode> node, ShaderConfig config)
+ {
+ TextureOperation texOp = (TextureOperation)node.Value;
+
+ TextureFormat format = config.GpuAccessor.QueryTextureFormat(texOp.Handle);
+
+ int maxPositive = format switch
+ {
+ TextureFormat.R8Snorm => sbyte.MaxValue,
+ TextureFormat.R8G8Snorm => sbyte.MaxValue,
+ TextureFormat.R8G8B8A8Snorm => sbyte.MaxValue,
+ TextureFormat.R16Snorm => short.MaxValue,
+ TextureFormat.R16G16Snorm => short.MaxValue,
+ TextureFormat.R16G16B16A16Snorm => short.MaxValue,
+ _ => 0
+ };
+
+ // The value being 0 means that the format is not a SNORM format, so there's nothing to do here.
+ if (maxPositive == 0)
+ {
+ return node;
+ }
+
+ // Do normalization. We assume SINT formats are being used as replacement for SNORM (that is not supported).
+ INode[] uses = texOp.Dest.UseOps.ToArray();
+
+ Operation convOp = new Operation(Instruction.ConvertS32ToFP, Local(), texOp.Dest);
+ Operation normOp = new Operation(Instruction.FP32 | Instruction.Multiply, Local(), convOp.Dest, ConstF(1f / maxPositive));
+
+ node = node.List.AddAfter(node, convOp);
+ node = node.List.AddAfter(node, normOp);
+
+ foreach (INode useOp in uses)
+ {
+ if (!(useOp is Operation op))
+ {
+ continue;
+ }
+
+ // Replace all uses of the texture pixel value with the normalized value.
+ for (int index = 0; index < op.SourcesCount; index++)
+ {
+ if (op.GetSource(index) == texOp.Dest)
+ {
+ op.SetSource(index, normOp.Dest);
+ }
+ }
+ }
+
+ return node;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
new file mode 100644
index 00000000..9515c349
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -0,0 +1,50 @@
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Shader.Translation.Optimizations
+{
+ class BindlessElimination
+ {
+ public static void RunPass(BasicBlock block)
+ {
+ // We can turn a bindless into regular access by recognizing the pattern
+ // produced by the compiler for separate texture and sampler.
+ // We check for the following conditions:
+ // - The handle is the result of a bitwise OR logical operation.
+ // - Both sources of the OR operation comes from CB2 (used by NVN to hold texture handles).
+ for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
+ {
+ if (!(node.Value is TextureOperation texOp))
+ {
+ continue;
+ }
+
+ if ((texOp.Flags & TextureFlags.Bindless) == 0)
+ {
+ continue;
+ }
+
+ if (!(texOp.GetSource(0).AsgOp is Operation handleCombineOp))
+ {
+ continue;
+ }
+
+ if (handleCombineOp.Inst != Instruction.BitwiseOr)
+ {
+ continue;
+ }
+
+ Operand src0 = handleCombineOp.GetSource(0);
+ Operand src1 = handleCombineOp.GetSource(1);
+
+ if (src0.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != 2 ||
+ src1.Type != OperandType.ConstantBuffer || src1.GetCbufSlot() != 2)
+ {
+ continue;
+ }
+
+ texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16));
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index c5db4678..10a0e780 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -1,4 +1,5 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -88,6 +89,22 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
{
BindlessToIndexed.RunPass(blocks[blkIndex]);
+ BindlessElimination.RunPass(blocks[blkIndex]);
+
+ // Try to eliminate any operations that are now unused.
+ LinkedListNode<INode> node = blocks[blkIndex].Operations.First;
+
+ while (node != null)
+ {
+ LinkedListNode<INode> nextNode = node.Next;
+
+ if (IsUnused(node.Value))
+ {
+ RemoveNode(blocks[blkIndex], node);
+ }
+
+ node = nextNode;
+ }
}
}