diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2020-05-27 11:07:10 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-27 16:07:10 +0200 |
| commit | 5795bb15282498b3824a5d15fe1ff78b85a18c23 (patch) | |
| tree | 6d4ee54c218e81fc6efaad279a5b1ade3ca8ec59 /Ryujinx.Graphics.Shader/Translation | |
| parent | 0b6d206daad7202d4e271118b631feb7dd363bbc (diff) | |
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
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation')
3 files changed, 130 insertions, 2 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/Lowering.cs b/Ryujinx.Graphics.Shader/Translation/Lowering.cs index 6f52ce96..6da25983 100644 --- a/Ryujinx.Graphics.Shader/Translation/Lowering.cs +++ b/Ryujinx.Graphics.Shader/Translation/Lowering.cs @@ -1,6 +1,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; using static Ryujinx.Graphics.Shader.Translation.GlobalMemory; @@ -27,9 +28,17 @@ namespace Ryujinx.Graphics.Shader.Translation node = RewriteGlobalAccess(node, config); } - if (operation.Inst == Instruction.TextureSample) + if (operation is TextureOperation texOp) { - node = RewriteTextureSample(node, config); + if (texOp.Inst == Instruction.TextureSample) + { + node = RewriteTextureSample(node, config); + } + + if (texOp.Type == SamplerType.TextureBuffer) + { + node = InsertSnormNormalization(node, config); + } } } } @@ -419,5 +428,57 @@ namespace Ryujinx.Graphics.Shader.Translation return node; } + + private static LinkedListNode<INode> InsertSnormNormalization(LinkedListNode<INode> node, ShaderConfig config) + { + TextureOperation texOp = (TextureOperation)node.Value; + + TextureFormat format = config.GpuAccessor.QueryTextureFormat(texOp.Handle); + + int maxPositive = format switch + { + TextureFormat.R8Snorm => sbyte.MaxValue, + TextureFormat.R8G8Snorm => sbyte.MaxValue, + TextureFormat.R8G8B8A8Snorm => sbyte.MaxValue, + TextureFormat.R16Snorm => short.MaxValue, + TextureFormat.R16G16Snorm => short.MaxValue, + TextureFormat.R16G16B16A16Snorm => short.MaxValue, + _ => 0 + }; + + // The value being 0 means that the format is not a SNORM format, so there's nothing to do here. + if (maxPositive == 0) + { + return node; + } + + // Do normalization. We assume SINT formats are being used as replacement for SNORM (that is not supported). + INode[] uses = texOp.Dest.UseOps.ToArray(); + + Operation convOp = new Operation(Instruction.ConvertS32ToFP, Local(), texOp.Dest); + Operation normOp = new Operation(Instruction.FP32 | Instruction.Multiply, Local(), convOp.Dest, ConstF(1f / maxPositive)); + + node = node.List.AddAfter(node, convOp); + node = node.List.AddAfter(node, normOp); + + foreach (INode useOp in uses) + { + if (!(useOp is Operation op)) + { + continue; + } + + // Replace all uses of the texture pixel value with the normalized value. + for (int index = 0; index < op.SourcesCount; index++) + { + if (op.GetSource(index) == texOp.Dest) + { + op.SetSource(index, normOp.Dest); + } + } + } + + return node; + } } }
\ No newline at end of file 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<INode> 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<INode> node = blocks[blkIndex].Operations.First; + + while (node != null) + { + LinkedListNode<INode> nextNode = node.Next; + + if (IsUnused(node.Value)) + { + RemoveNode(blocks[blkIndex], node); + } + + node = nextNode; + } } } |
