diff options
| -rw-r--r-- | Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs | 3 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Shader/Translation/Lowering.cs | 118 |
2 files changed, 73 insertions, 48 deletions
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs index c276959a..0482c35e 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs @@ -140,8 +140,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr { // TODO: Return correct type depending on source index, // that can improve the decompiler output. - if ( - inst == Instruction.ImageLoad || + if (inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.Lod || inst == Instruction.TextureSample) diff --git a/Ryujinx.Graphics.Shader/Translation/Lowering.cs b/Ryujinx.Graphics.Shader/Translation/Lowering.cs index 1cd1df37..46884bc9 100644 --- a/Ryujinx.Graphics.Shader/Translation/Lowering.cs +++ b/Ryujinx.Graphics.Shader/Translation/Lowering.cs @@ -126,6 +126,15 @@ namespace Ryujinx.Graphics.Shader.Translation private static LinkedListNode<INode> RewriteTextureSample(LinkedListNode<INode> node) { + // Technically, non-constant texture offsets are not allowed (according to the spec), + // however some GPUs does support that. + // For GPUs where it is not supported, we can replace the instruction with the following: + // For texture*Offset, we replace it by texture*, and add the offset to the P coords. + // The offset can be calculated as offset / textureSize(lod), where lod = textureQueryLod(coords). + // For texelFetchOffset, we replace it by texelFetch and add the offset to the P coords directly. + // For textureGatherOffset, we take advantage of the fact that the operation is already broken down + // to read the 4 pixels separately, and just replace it with 4 textureGather with a different offset + // for each pixel. TextureOperation texOp = (TextureOperation)node.Value; bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0; @@ -139,6 +148,7 @@ namespace Ryujinx.Graphics.Shader.Translation bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isGather = (texOp.Flags & TextureFlags.Gather) != 0; bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0; + bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0; bool hasLodBias = (texOp.Flags & TextureFlags.LodBias) != 0; bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0; @@ -228,74 +238,90 @@ namespace Ryujinx.Graphics.Shader.Translation sources[dstIndex++] = texOp.GetSource(srcIndex++); } - Operand Int(Operand value) + int coordsIndex = isBindless || isIndexed ? 1 : 0; + + if (intCoords) { - Operand res = Local(); + for (int index = 0; index < coordsCount; index++) + { + Operand source = sources[coordsIndex + index]; - node.List.AddBefore(node, new Operation(Instruction.ConvertFPToS32, res, value)); + Operand coordPlusOffset = Local(); - return res; - } + node.List.AddBefore(node, new Operation(Instruction.Add, coordPlusOffset, source, offsets[index])); - Operand Float(Operand value) + sources[coordsIndex + index] = coordPlusOffset; + } + } + else { - Operand res = Local(); + Operand lod = Local(); - node.List.AddBefore(node, new Operation(Instruction.ConvertS32ToFP, res, value)); - - return res; - } + node.List.AddBefore(node, new TextureOperation( + Instruction.Lod, + texOp.Type, + texOp.Flags, + texOp.Handle, + 1, + lod, + lodSources)); - Operand lod = Local(); + Operand Int(Operand value) + { + Operand res = Local(); - node.List.AddBefore(node, new TextureOperation( - Instruction.Lod, - texOp.Type, - texOp.Flags, - texOp.Handle, - 1, - lod, - lodSources)); + node.List.AddBefore(node, new Operation(Instruction.ConvertFPToS32, res, value)); - int coordsIndex = isBindless || isIndexed ? 1 : 0; + return res; + } - for (int index = 0; index < coordsCount; index++) - { - Operand coordSize = Local(); + Operand Float(Operand value) + { + Operand res = Local(); - Operand[] texSizeSources; + node.List.AddBefore(node, new Operation(Instruction.ConvertS32ToFP, res, value)); - if (isBindless || isIndexed) - { - texSizeSources = new Operand[] { sources[0], Int(lod) }; + return res; } - else + + for (int index = 0; index < coordsCount; index++) { - texSizeSources = new Operand[] { Int(lod) }; - } + Operand coordSize = Local(); - node.List.AddBefore(node, new TextureOperation( - Instruction.TextureSize, - texOp.Type, - texOp.Flags, - texOp.Handle, - index, - coordSize, - texSizeSources)); + Operand[] texSizeSources; + + if (isBindless || isIndexed) + { + texSizeSources = new Operand[] { sources[0], Int(lod) }; + } + else + { + texSizeSources = new Operand[] { Int(lod) }; + } - Operand offset = Local(); + node.List.AddBefore(node, new TextureOperation( + Instruction.TextureSize, + texOp.Type, + texOp.Flags, + texOp.Handle, + index, + coordSize, + texSizeSources)); - Operand intOffset = offsets[index + (hasOffsets ? texOp.Index * coordsCount : 0)]; + Operand offset = Local(); - node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Divide, offset, Float(intOffset), Float(coordSize))); + Operand intOffset = offsets[index + (hasOffsets ? texOp.Index * coordsCount : 0)]; - Operand source = sources[coordsIndex + index]; + node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Divide, offset, Float(intOffset), Float(coordSize))); - Operand coordPlusOffset = Local(); + Operand source = sources[coordsIndex + index]; - node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Add, coordPlusOffset, source, offset)); + Operand coordPlusOffset = Local(); - sources[coordsIndex + index] = coordPlusOffset; + node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Add, coordPlusOffset, source, offset)); + + sources[coordsIndex + index] = coordPlusOffset; + } } int componentIndex; |
