aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2024-06-16 14:46:27 -0300
committerGitHub <noreply@github.com>2024-06-16 14:46:27 -0300
commit3193ef10833bc0d27e2701c7759ab02674d672d3 (patch)
tree8aae569f4943373450d181908f858cf03c0a0b42 /src
parent5a878ae9afe73d12bd344c139ee1b485335af3ff (diff)
Extend bindless elimination to catch a few more specific cases (#6921)1.1.1333
* Catch more cases on bindless elimination * Match blocks with the same comparison condition * Shader cache version bump
Diffstat (limited to 'src')
-rw-r--r--src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs2
-rw-r--r--src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs2
-rw-r--r--src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs20
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs8
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs8
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs21
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs30
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs76
8 files changed, 137 insertions, 30 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index fbf48f01..c4b5a138 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 = 6852;
+ private const uint CodeGenVersion = 6921;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs
index 630162ad..1d865125 100644
--- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs
+++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitPredicate.cs
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (op.BVal)
{
- context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0)));
+ context.Copy(dest, context.ConditionalSelect(res, ConstF(1), ConstF(0)));
}
else
{
diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
index 8703e660..273a38a5 100644
--- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
+++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
@@ -156,6 +156,26 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
return false;
}
+ public static bool IsComparison(this Instruction inst)
+ {
+ switch (inst & Instruction.Mask)
+ {
+ case Instruction.CompareEqual:
+ case Instruction.CompareGreater:
+ case Instruction.CompareGreaterOrEqual:
+ case Instruction.CompareGreaterOrEqualU32:
+ case Instruction.CompareGreaterU32:
+ case Instruction.CompareLess:
+ case Instruction.CompareLessOrEqual:
+ case Instruction.CompareLessOrEqualU32:
+ case Instruction.CompareLessU32:
+ case Instruction.CompareNotEqual:
+ return true;
+ }
+
+ return false;
+ }
+
public static bool IsTextureQuery(this Instruction inst)
{
inst &= Instruction.Mask;
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index 02a83fbe..1f2f79a2 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -141,16 +141,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return true;
}
- private static bool IsBindlessAccessAllowed(Operand nvHandle)
+ private static bool IsBindlessAccessAllowed(Operand bindlessHandle)
{
- if (nvHandle.Type == OperandType.ConstantBuffer)
+ if (bindlessHandle.Type == OperandType.ConstantBuffer)
{
// Bindless access with handles from constant buffer is allowed.
return true;
}
- if (nvHandle.AsgOp is not Operation handleOp ||
+ if (bindlessHandle.AsgOp is not Operation handleOp ||
handleOp.Inst != Instruction.Load ||
(handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
{
@@ -300,7 +300,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
resourceManager,
gpuAccessor,
texOp,
- TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType),
+ TextureHandle.PackOffsets(src0.GetCbufOffset(), (src1.Value >> 20) & 0xfff, handleType),
TextureHandle.PackSlots(src0.GetCbufSlot(), 0),
rewriteSamplerType,
isImage: false);
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
index 8eed139d..1e0b3b64 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
@@ -126,7 +126,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- if (texOp.GetSource(0).AsgOp is not Operation handleAsgOp)
+ Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
+
+ if (bindlessHandle.AsgOp is not Operation handleAsgOp)
{
continue;
}
@@ -137,8 +139,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
if (handleAsgOp.Inst == Instruction.BitwiseOr)
{
- Operand src0 = handleAsgOp.GetSource(0);
- Operand src1 = handleAsgOp.GetSource(1);
+ Operand src0 = Utils.FindLastOperation(handleAsgOp.GetSource(0), block);
+ Operand src1 = Utils.FindLastOperation(handleAsgOp.GetSource(1), block);
if (src0.Type == OperandType.ConstantBuffer && src1.AsgOp is Operation)
{
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index 49eb3a89..1be7c5c5 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -152,18 +152,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
// If all phi sources are the same, we can propagate it and remove the phi.
- Operand firstSrc = phi.GetSource(0);
-
- for (int index = 1; index < phi.SourcesCount; index++)
+ if (!Utils.AreAllSourcesTheSameOperand(phi))
{
- if (!IsSameOperand(firstSrc, phi.GetSource(index)))
- {
- return false;
- }
+ return false;
}
// All sources are equal, we can propagate the value.
+ Operand firstSrc = phi.GetSource(0);
Operand dest = phi.Dest;
INode[] uses = dest.UseOps.ToArray();
@@ -182,17 +178,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return true;
}
- private static bool IsSameOperand(Operand x, Operand y)
- {
- if (x.Type != y.Type || x.Value != y.Value)
- {
- return false;
- }
-
- // TODO: Handle Load operations with the same storage and the same constant parameters.
- return x.Type == OperandType.Constant || x.Type == OperandType.ConstantBuffer;
- }
-
private static bool PropagatePack(Operation packOp)
{
// Propagate pack source operands to uses by unpack
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs
index a509fcb4..097c8aa8 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs
@@ -31,6 +31,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
TryEliminateBitwiseOr(operation);
break;
+ case Instruction.CompareNotEqual:
+ TryEliminateCompareNotEqual(operation);
+ break;
+
case Instruction.ConditionalSelect:
TryEliminateConditionalSelect(operation);
break;
@@ -174,6 +178,32 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
}
}
+ private static void TryEliminateCompareNotEqual(Operation operation)
+ {
+ // Comparison instruction returns 0 if the result is false, and -1 if true.
+ // Doing a not equal zero comparison on the result is redundant, so we can just copy the first result in this case.
+
+ Operand lhs = operation.GetSource(0);
+ Operand rhs = operation.GetSource(1);
+
+ if (lhs.Type == OperandType.Constant)
+ {
+ (lhs, rhs) = (rhs, lhs);
+ }
+
+ if (rhs.Type != OperandType.Constant || rhs.Value != 0)
+ {
+ return;
+ }
+
+ if (lhs.AsgOp is not Operation compareOp || !compareOp.Inst.IsComparison())
+ {
+ return;
+ }
+
+ operation.TurnIntoCopy(lhs);
+ }
+
private static void TryEliminateConditionalSelect(Operation operation)
{
Operand cond = operation.GetSource(0);
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs
index 74a6d5a1..23180ff8 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs
@@ -34,6 +34,50 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return elemIndexSrc.Type == OperandType.Constant && elemIndexSrc.Value == elemIndex;
}
+ private static bool IsSameOperand(Operand x, Operand y)
+ {
+ if (x.Type != y.Type || x.Value != y.Value)
+ {
+ return false;
+ }
+
+ // TODO: Handle Load operations with the same storage and the same constant parameters.
+ return x == y || x.Type == OperandType.Constant || x.Type == OperandType.ConstantBuffer;
+ }
+
+ private static bool AreAllSourcesEqual(INode node, INode otherNode)
+ {
+ if (node.SourcesCount != otherNode.SourcesCount)
+ {
+ return false;
+ }
+
+ for (int index = 0; index < node.SourcesCount; index++)
+ {
+ if (!IsSameOperand(node.GetSource(index), otherNode.GetSource(index)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static bool AreAllSourcesTheSameOperand(INode node)
+ {
+ Operand firstSrc = node.GetSource(0);
+
+ for (int index = 1; index < node.SourcesCount; index++)
+ {
+ if (!IsSameOperand(firstSrc, node.GetSource(index)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private static Operation FindBranchSource(BasicBlock block)
{
foreach (BasicBlock sourceBlock in block.Predecessors)
@@ -55,6 +99,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return inst == Instruction.BranchIfFalse || inst == Instruction.BranchIfTrue;
}
+ private static bool IsSameCondition(Operand currentCondition, Operand queryCondition)
+ {
+ if (currentCondition == queryCondition)
+ {
+ return true;
+ }
+
+ return currentCondition.AsgOp is Operation currentOperation &&
+ queryCondition.AsgOp is Operation queryOperation &&
+ currentOperation.Inst == queryOperation.Inst &&
+ AreAllSourcesEqual(currentOperation, queryOperation);
+ }
+
private static bool BlockConditionsMatch(BasicBlock currentBlock, BasicBlock queryBlock)
{
// Check if all the conditions for the query block are satisfied by the current block.
@@ -70,10 +127,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return currentBranch != null && queryBranch != null &&
currentBranch.Inst == queryBranch.Inst &&
- currentCondition == queryCondition;
+ IsSameCondition(currentCondition, queryCondition);
}
- public static Operand FindLastOperation(Operand source, BasicBlock block)
+ public static Operand FindLastOperation(Operand source, BasicBlock block, bool recurse = true)
{
if (source.AsgOp is PhiNode phiNode)
{
@@ -84,10 +141,23 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
for (int i = phiNode.SourcesCount - 1; i >= 0; i--)
{
BasicBlock phiBlock = phiNode.GetBlock(i);
+ Operand phiSource = phiNode.GetSource(i);
if (BlockConditionsMatch(block, phiBlock))
{
- return phiNode.GetSource(i);
+ return phiSource;
+ }
+ else if (recurse && phiSource.AsgOp is PhiNode)
+ {
+ // Phi source is another phi.
+ // Let's check if that phi has a block that matches our condition.
+
+ Operand match = FindLastOperation(phiSource, block, false);
+
+ if (match != phiSource)
+ {
+ return match;
+ }
}
}
}