forked from Mirror/Ryujinx
Traverse PhiNodes for Bindless Elimination (#2089)
This allows bindless handles to be found for image/texture instructions with predicates, when the assignment of the texture handle is within the same predicate. This seems to cover the remaining bindless handles that compilers seem to be creating due to optimizations. Will affect newer UE4 games, and games by NdCube (Super Mario Party, Clubhouse Games)
This commit is contained in:
parent
1623ab524f
commit
ede26556f2
1 changed files with 64 additions and 4 deletions
|
@ -5,6 +5,66 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
{
|
||||
class BindlessElimination
|
||||
{
|
||||
private static Operation FindBranchSource(BasicBlock block)
|
||||
{
|
||||
foreach (BasicBlock sourceBlock in block.Predecessors)
|
||||
{
|
||||
if (sourceBlock.Operations.Count > 0)
|
||||
{
|
||||
Operation lastOp = sourceBlock.Operations.Last.Value as Operation;
|
||||
|
||||
if (lastOp != null &&
|
||||
((sourceBlock.Next == block && lastOp.Inst == Instruction.BranchIfFalse) ||
|
||||
(sourceBlock.Branch == block && lastOp.Inst == Instruction.BranchIfTrue)))
|
||||
{
|
||||
return lastOp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool BlockConditionsMatch(BasicBlock currentBlock, BasicBlock queryBlock)
|
||||
{
|
||||
// Check if all the conditions for the query block are satisfied by the current block.
|
||||
// Just checks the top-most conditional for now.
|
||||
|
||||
Operation currentBranch = FindBranchSource(currentBlock);
|
||||
Operation queryBranch = FindBranchSource(queryBlock);
|
||||
|
||||
Operand currentCondition = currentBranch?.GetSource(0);
|
||||
Operand queryCondition = queryBranch?.GetSource(0);
|
||||
|
||||
// The condition should be the same operand instance.
|
||||
|
||||
return currentBranch != null && queryBranch != null &&
|
||||
currentBranch.Inst == queryBranch.Inst &&
|
||||
currentCondition == queryCondition;
|
||||
}
|
||||
|
||||
private static Operand FindLastOperation(Operand source, BasicBlock block)
|
||||
{
|
||||
if (source.AsgOp is PhiNode phiNode)
|
||||
{
|
||||
// This source can have a different value depending on a previous branch.
|
||||
// Ensure that conditions met for that branch are also met for the current one.
|
||||
// Prefer the latest sources for the phi node.
|
||||
|
||||
for (int i = phiNode.SourcesCount - 1; i >= 0; i--)
|
||||
{
|
||||
BasicBlock phiBlock = phiNode.GetBlock(i);
|
||||
|
||||
if (BlockConditionsMatch(block, phiBlock))
|
||||
{
|
||||
return phiNode.GetSource(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
public static void RunPass(BasicBlock block, ShaderConfig config)
|
||||
{
|
||||
// We can turn a bindless into regular access by recognizing the pattern
|
||||
|
@ -29,7 +89,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
texOp.Inst == Instruction.TextureSample ||
|
||||
texOp.Inst == Instruction.TextureSize)
|
||||
{
|
||||
Operand bindlessHandle = texOp.GetSource(0);
|
||||
Operand bindlessHandle = FindLastOperation(texOp.GetSource(0), block);
|
||||
|
||||
if (bindlessHandle.Type == OperandType.ConstantBuffer)
|
||||
{
|
||||
|
@ -47,8 +107,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
continue;
|
||||
}
|
||||
|
||||
Operand src0 = handleCombineOp.GetSource(0);
|
||||
Operand src1 = handleCombineOp.GetSource(1);
|
||||
Operand src0 = FindLastOperation(handleCombineOp.GetSource(0), block);
|
||||
Operand src1 = FindLastOperation(handleCombineOp.GetSource(1), block);
|
||||
|
||||
if (src0.Type != OperandType.ConstantBuffer ||
|
||||
src1.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != src1.GetCbufSlot())
|
||||
|
@ -60,7 +120,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||
}
|
||||
else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
|
||||
{
|
||||
Operand src0 = texOp.GetSource(0);
|
||||
Operand src0 = FindLastOperation(texOp.GetSource(0), block);
|
||||
|
||||
if (src0.Type == OperandType.ConstantBuffer)
|
||||
{
|
||||
|
|
Reference in a new issue