mirror of
				https://github.com/ryujinx-mirror/ryujinx.git
				synced 2025-11-04 08:59:04 -06:00 
			
		
		
		
	Extend bindless elimination to catch a few more specific cases (#6921)
* Catch more cases on bindless elimination * Match blocks with the same comparison condition * Shader cache version bump
This commit is contained in:
		@@ -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";
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user