diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2019-12-11 03:54:18 -0300 |
|---|---|---|
| committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
| commit | f2c85c5d58a0aeda5d5fe2d7a980cc7284330288 (patch) | |
| tree | e9a3b2100de28120cd52239b5af9615b750ec352 /Ryujinx.Graphics.Shader/Translation | |
| parent | 3323a3a042c85ce88926771159fc041b5576de60 (diff) | |
Support non-constant texture offsets on non-NVIDIA gpus
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation')
| -rw-r--r-- | Ryujinx.Graphics.Shader/Translation/Lowering.cs | 222 |
1 files changed, 220 insertions, 2 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/Lowering.cs b/Ryujinx.Graphics.Shader/Translation/Lowering.cs index 9a17dd83..1cd1df37 100644 --- a/Ryujinx.Graphics.Shader/Translation/Lowering.cs +++ b/Ryujinx.Graphics.Shader/Translation/Lowering.cs @@ -1,5 +1,6 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation; using System.Collections.Generic; +using System.Diagnostics; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; using static Ryujinx.Graphics.Shader.Translation.GlobalMemory; @@ -23,13 +24,18 @@ namespace Ryujinx.Graphics.Shader.Translation if (UsesGlobalMemory(operation.Inst)) { - node = LowerGlobal(node, config); + node = RewriteGlobalAccess(node, config); + } + + if (!config.Capabilities.SupportsNonConstantTextureOffset && operation.Inst == Instruction.TextureSample) + { + node = RewriteTextureSample(node); } } } } - private static LinkedListNode<INode> LowerGlobal(LinkedListNode<INode> node, ShaderConfig config) + private static LinkedListNode<INode> RewriteGlobalAccess(LinkedListNode<INode> node, ShaderConfig config) { Operation operation = (Operation)node.Value; @@ -117,5 +123,217 @@ namespace Ryujinx.Graphics.Shader.Translation return node; } + + private static LinkedListNode<INode> RewriteTextureSample(LinkedListNode<INode> node) + { + TextureOperation texOp = (TextureOperation)node.Value; + + bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0; + bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0; + + if (!(hasOffset || hasOffsets)) + { + return node; + } + + bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + bool isGather = (texOp.Flags & TextureFlags.Gather) != 0; + bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0; + bool hasLodBias = (texOp.Flags & TextureFlags.LodBias) != 0; + bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0; + + bool isArray = (texOp.Type & SamplerType.Array) != 0; + bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; + bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0; + bool isShadow = (texOp.Type & SamplerType.Shadow) != 0; + + int coordsCount = texOp.Type.GetDimensions(); + + int offsetsCount = coordsCount * (hasOffsets ? 4 : 1); + + Operand[] offsets = new Operand[offsetsCount]; + Operand[] sources = new Operand[texOp.SourcesCount - offsetsCount]; + + int srcIndex = 0; + int dstIndex = 0; + + int copyCount = 0; + + if (isBindless || isIndexed) + { + copyCount++; + } + + Operand[] lodSources = new Operand[copyCount + coordsCount]; + + for (int index = 0; index < lodSources.Length; index++) + { + lodSources[index] = texOp.GetSource(index); + } + + copyCount += coordsCount; + + if (isArray) + { + copyCount++; + } + + if (isShadow) + { + copyCount++; + } + + if (hasDerivatives) + { + copyCount += coordsCount * 2; + } + + if (isMultisample) + { + copyCount++; + } + else if (hasLodLevel) + { + copyCount++; + } + + for (int index = 0; index < copyCount; index++) + { + sources[dstIndex++] = texOp.GetSource(srcIndex++); + } + + bool areAllOffsetsConstant = true; + + for (int index = 0; index < offsetsCount; index++) + { + Operand offset = texOp.GetSource(srcIndex++); + + areAllOffsetsConstant &= offset.Type == OperandType.Constant; + + offsets[index] = offset; + } + + if (areAllOffsetsConstant) + { + return node; + } + + if (hasLodBias) + { + sources[dstIndex++] = texOp.GetSource(srcIndex++); + } + + if (isGather && !isShadow) + { + sources[dstIndex++] = texOp.GetSource(srcIndex++); + } + + Operand Int(Operand value) + { + Operand res = Local(); + + node.List.AddBefore(node, new Operation(Instruction.ConvertFPToS32, res, value)); + + return res; + } + + Operand Float(Operand value) + { + Operand res = Local(); + + node.List.AddBefore(node, new Operation(Instruction.ConvertS32ToFP, res, value)); + + return res; + } + + Operand lod = Local(); + + node.List.AddBefore(node, new TextureOperation( + Instruction.Lod, + texOp.Type, + texOp.Flags, + texOp.Handle, + 1, + lod, + lodSources)); + + int coordsIndex = isBindless || isIndexed ? 1 : 0; + + for (int index = 0; index < coordsCount; index++) + { + Operand coordSize = Local(); + + Operand[] texSizeSources; + + if (isBindless || isIndexed) + { + texSizeSources = new Operand[] { sources[0], Int(lod) }; + } + else + { + texSizeSources = new Operand[] { Int(lod) }; + } + + node.List.AddBefore(node, new TextureOperation( + Instruction.TextureSize, + texOp.Type, + texOp.Flags, + texOp.Handle, + index, + coordSize, + texSizeSources)); + + Operand offset = Local(); + + Operand intOffset = offsets[index + (hasOffsets ? texOp.Index * coordsCount : 0)]; + + node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Divide, offset, Float(intOffset), Float(coordSize))); + + Operand source = sources[coordsIndex + index]; + + Operand coordPlusOffset = Local(); + + node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Add, coordPlusOffset, source, offset)); + + sources[coordsIndex + index] = coordPlusOffset; + } + + int componentIndex; + + if (isGather && !isShadow) + { + Operand gatherComponent = sources[dstIndex - 1]; + + Debug.Assert(gatherComponent.Type == OperandType.Constant); + + componentIndex = gatherComponent.Value; + } + else + { + componentIndex = texOp.Index; + } + + TextureOperation newTexOp = new TextureOperation( + Instruction.TextureSample, + texOp.Type, + texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets), + texOp.Handle, + componentIndex, + texOp.Dest, + sources); + + for (int index = 0; index < texOp.SourcesCount; index++) + { + texOp.SetSource(index, null); + } + + LinkedListNode<INode> oldNode = node; + + node = node.List.AddBefore(node, newTexOp); + + node.List.Remove(oldNode); + + return node; + } } }
\ No newline at end of file |
