aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-05-19 11:52:31 -0300
committerGitHub <noreply@github.com>2023-05-19 11:52:31 -0300
commitfc26189fe1338ffcba12d83a922da9c706738902 (patch)
tree7dea976db639a73d81793d8b9ee8b9803cdce1c4
parenta40c90e7dd0c37ae6fb7be84ad720cbf88fd8d28 (diff)
Eliminate redundant multiplications by gl_FragCoord.w on the shader (#4578)1.1.807
* Eliminate redundant multiplications by gl_FragCoord.w on the shader * Shader cache version bump
-rw-r--r--src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs2
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs75
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs29
3 files changed, 105 insertions, 1 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index 71098efa..ee771452 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
- private const uint CodeGenVersion = 4892;
+ private const uint CodeGenVersion = 4578;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index 16848bdc..b41e47e4 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -20,6 +20,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask, ref ubeUseMask);
BindlessToIndexed.RunPass(blocks[blkIndex], config);
BindlessElimination.RunPass(blocks[blkIndex], config);
+
+ // FragmentCoord only exists on fragment shaders, so we don't need to check other stages.
+ if (config.Stage == ShaderStage.Fragment)
+ {
+ EliminateMultiplyByFragmentCoordW(blocks[blkIndex]);
+ }
}
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
@@ -281,6 +287,75 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return modified;
}
+ private static void EliminateMultiplyByFragmentCoordW(BasicBlock block)
+ {
+ foreach (INode node in block.Operations)
+ {
+ if (node is Operation operation)
+ {
+ EliminateMultiplyByFragmentCoordW(operation);
+ }
+ }
+ }
+
+ private static void EliminateMultiplyByFragmentCoordW(Operation operation)
+ {
+ // We're looking for the pattern:
+ // y = x * gl_FragCoord.w
+ // v = y * (1.0 / gl_FragCoord.w)
+ // Then we transform it into:
+ // v = x
+ // This pattern is common on fragment shaders due to the way how perspective correction is done.
+
+ // We are expecting a multiplication by the reciprocal of gl_FragCoord.w.
+ if (operation.Inst != (Instruction.FP32 | Instruction.Multiply))
+ {
+ return;
+ }
+
+ Operand lhs = operation.GetSource(0);
+ Operand rhs = operation.GetSource(1);
+
+ // Check LHS of the the main multiplication operation. We expect an input being multiplied by gl_FragCoord.w.
+ if (!(lhs.AsgOp is Operation attrMulOp) || attrMulOp.Inst != (Instruction.FP32 | Instruction.Multiply))
+ {
+ return;
+ }
+
+ Operand attrMulLhs = attrMulOp.GetSource(0);
+ Operand attrMulRhs = attrMulOp.GetSource(1);
+
+ // LHS should be any input, RHS should be exactly gl_FragCoord.w.
+ if (!Utils.IsInputLoad(attrMulLhs.AsgOp) || !Utils.IsInputLoad(attrMulRhs.AsgOp, IoVariable.FragmentCoord, 3))
+ {
+ return;
+ }
+
+ // RHS of the main multiplication should be a reciprocal operation (1.0 / x).
+ if (!(rhs.AsgOp is Operation reciprocalOp) || reciprocalOp.Inst != (Instruction.FP32 | Instruction.Divide))
+ {
+ return;
+ }
+
+ Operand reciprocalLhs = reciprocalOp.GetSource(0);
+ Operand reciprocalRhs = reciprocalOp.GetSource(1);
+
+ // Check if the divisor is a constant equal to 1.0.
+ if (reciprocalLhs.Type != OperandType.Constant || reciprocalLhs.AsFloat() != 1.0f)
+ {
+ return;
+ }
+
+ // Check if the dividend is gl_FragCoord.w.
+ if (!Utils.IsInputLoad(reciprocalRhs.AsgOp, IoVariable.FragmentCoord, 3))
+ {
+ return;
+ }
+
+ // If everything matches, we can replace the operation with the input load result.
+ operation.TurnIntoCopy(attrMulLhs);
+ }
+
private static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode)
{
// Remove a node from the nodes list, and also remove itself
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs
index 4ca6d687..a0d58d07 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs
@@ -4,6 +4,35 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
static class Utils
{
+ public static bool IsInputLoad(INode node)
+ {
+ return (node is Operation operation) &&
+ operation.Inst == Instruction.Load &&
+ operation.StorageKind == StorageKind.Input;
+ }
+
+ public static bool IsInputLoad(INode node, IoVariable ioVariable, int elemIndex)
+ {
+ if (!(node is Operation operation) ||
+ operation.Inst != Instruction.Load ||
+ operation.StorageKind != StorageKind.Input ||
+ operation.SourcesCount != 2)
+ {
+ return false;
+ }
+
+ Operand ioVariableSrc = operation.GetSource(0);
+
+ if (ioVariableSrc.Type != OperandType.Constant || (IoVariable)ioVariableSrc.Value != ioVariable)
+ {
+ return false;
+ }
+
+ Operand elemIndexSrc = operation.GetSource(1);
+
+ return elemIndexSrc.Type == OperandType.Constant && elemIndexSrc.Value == elemIndex;
+ }
+
private static Operation FindBranchSource(BasicBlock block)
{
foreach (BasicBlock sourceBlock in block.Predecessors)