From 5795bb15282498b3824a5d15fe1ff78b85a18c23 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 27 May 2020 11:07:10 -0300 Subject: 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 --- .../Optimizations/BindlessElimination.cs | 50 ++++++++++++++++++++++ .../Translation/Optimizations/Optimizer.cs | 17 ++++++++ 2 files changed, 67 insertions(+) create mode 100644 Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs (limited to 'Ryujinx.Graphics.Shader/Translation/Optimizations') 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 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 node = blocks[blkIndex].Operations.First; + + while (node != null) + { + LinkedListNode nextNode = node.Next; + + if (IsUnused(node.Value)) + { + RemoveNode(blocks[blkIndex], node); + } + + node = nextNode; + } } } -- cgit v1.2.3