From a1df758958048294bb78f035bcca9d5b5ac3998d Mon Sep 17 00:00:00 2001 From: Thog Date: Mon, 3 Dec 2018 19:31:57 +0100 Subject: [PATCH] Implement TLD4 and TLD4S --- Ryujinx.Graphics/Gal/Shader/GlslDecl.cs | 5 +- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 40 +++- .../Gal/Shader/ShaderDecodeMem.cs | 209 +++++++++++++++++- Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs | 1 + .../Gal/Shader/ShaderIrMetaTex.cs | 1 + .../Gal/Shader/ShaderOpCodeTable.cs | 2 + .../Texture/TextureInstructionSuffix.cs | 7 +- 7 files changed, 256 insertions(+), 9 deletions(-) diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index e769d6d206..fe3c18ecba 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -226,6 +226,7 @@ namespace Ryujinx.Graphics.Gal.Shader if (Op.Inst == ShaderIrInst.Texq || Op.Inst == ShaderIrInst.Texs || + Op.Inst == ShaderIrInst.Tld4 || Op.Inst == ShaderIrInst.Txlf) { int Handle = ((ShaderIrOperImm)Op.OperandC).Value; @@ -241,14 +242,14 @@ namespace Ryujinx.Graphics.Gal.Shader // TODO: non 2d texture type for TEXQ? if (Op.Inst == ShaderIrInst.Texq) { - TextureType = TextureType.TwoD; + TextureType = TextureType.TwoD; TextureInstructionSuffix = TextureInstructionSuffix.None; } else { ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData); - TextureType = Meta.TextureType; + TextureType = Meta.TextureType; TextureInstructionSuffix = Meta.TextureInstructionSuffix; } diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index d5ffa0f0ec..5e950d39db 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -105,6 +105,7 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrInst.Texb, GetTexbExpr }, { ShaderIrInst.Texq, GetTexqExpr }, { ShaderIrInst.Texs, GetTexsExpr }, + { ShaderIrInst.Tld4, GetTld4Expr }, { ShaderIrInst.Trunc, GetTruncExpr }, { ShaderIrInst.Txlf, GetTxlfExpr }, { ShaderIrInst.Utof, GetUtofExpr }, @@ -837,6 +838,7 @@ namespace Ryujinx.Graphics.Gal.Shader case ShaderIrInst.Ipa: case ShaderIrInst.Texq: case ShaderIrInst.Texs: + case ShaderIrInst.Tld4: case ShaderIrInst.Txlf: return false; } @@ -1219,6 +1221,19 @@ namespace Ryujinx.Graphics.Gal.Shader return GetTextureOperation(Op, Sampler, Coords, Ch); } + private string GetTld4Expr(ShaderIrOp Op) + { + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + string Sampler = GetTexSamplerName(Op); + + string Coords = GetTexSamplerCoords(Op); + + string Ch = "rgba".Substring(Meta.Elem, 1); + + return GetTextureGatherOperation(Op, Sampler, Coords, Ch); + } + private string GetTxlfExpr(ShaderIrOp Op) { // TODO: DC AND MZ @@ -1346,7 +1361,7 @@ namespace Ryujinx.Graphics.Gal.Shader string DepthArgument = ""; int VecSize = Coords; - if (HasDepth) + if (HasDepth && Op.Inst != ShaderIrInst.Tld4) { VecSize++; DepthArgument = $", {GetOperExpr(Op, Meta.DepthCompare)}"; @@ -1406,6 +1421,29 @@ namespace Ryujinx.Graphics.Gal.Shader } } + private string GetTextureGatherOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch) + { + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + + string ChString = "." + Ch; + + string Comp = Meta.Component.ToString(); + + if ((Suffix & TextureInstructionSuffix.DC) != 0) + { + Comp = GetOperExpr(Op, Meta.DepthCompare); + } + + // TODO + if ((Suffix & TextureInstructionSuffix.AOFFI) != 0) + { + throw new NotSupportedException(); + } + return "textureGather(" + Sampler + ", " + Coords + ", " + Comp + ")" + ChString; + } + private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch) { ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index 10a9bd4858..329a99ecb3 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -279,9 +279,7 @@ namespace Ryujinx.Graphics.Gal.Shader TextureInstructionSuffix |= TextureInstructionSuffix.DC; } - ShaderIrOperGpr[] Coords = null; - - Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)]; + ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)]; int IndexExtraCoord = 0; @@ -453,6 +451,63 @@ namespace Ryujinx.Graphics.Gal.Shader EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureType, GetSuffix()); } + public static void Tld4(ShaderIrBlock Block, long OpCode, int Position) + { + TextureInstructionSuffix GetSuffix() + { + int RawSuffix = OpCode.Read(0x34, 0x38); + + switch (RawSuffix) + { + case 0: + return TextureInstructionSuffix.None; + case 0x4: + return TextureInstructionSuffix.AOFFI; + case 0x8: + return TextureInstructionSuffix.PTP; + default: + throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {RawSuffix}"); + } + } + + bool IsShadow = OpCode.Read(0x32); + + bool IsArray = OpCode.HasArray(); + int ChMask = OpCode.Read(31, 0xf); + + TextureType TextureType = TexToTextureType(OpCode.Read(28, 6), IsArray); + + TextureInstructionSuffix Suffix = GetSuffix(); + + if (IsShadow) + { + Suffix |= TextureInstructionSuffix.DC; + } + + EmitTld4(Block, OpCode, TextureType, Suffix, ChMask, OpCode.Read(0x38, 0x3), false); + } + + public static void Tld4s(ShaderIrBlock Block, long OpCode, int Position) + { + TextureInstructionSuffix Suffix = TextureInstructionSuffix.None; + + bool IsOffset = OpCode.Read(0x33); + bool IsShadow = OpCode.Read(0x32); + + if (IsOffset) + { + Suffix |= TextureInstructionSuffix.AOFFI; + } + + if (IsShadow) + { + Suffix |= TextureInstructionSuffix.DC; + } + + // TLD4S seems to only support 2D textures with RGBA mask? + EmitTld4(Block, OpCode, TextureType.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true); + } + private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix) { if (Inst == ShaderIrInst.Txlf && TextureType == TextureType.CubeArray) @@ -640,6 +695,154 @@ namespace Ryujinx.Graphics.Gal.Shader } } + private static void EmitTld4(ShaderIrBlock Block, long OpCode, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, int ChMask, int Component, bool Scalar) + { + ShaderIrOperGpr OperA = OpCode.Gpr8(); + ShaderIrOperGpr OperB = OpCode.Gpr20(); + ShaderIrOperImm OperC = OpCode.Imm13_36(); + + ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)]; + + ShaderIrOperGpr Offset = null; + ShaderIrOperGpr DepthCompare = null; + + bool IsArray = ImageUtils.IsArray(TextureType); + + int OperBIndex = 0; + + if (Scalar) + { + int CoordStartIndex = 0; + + if (IsArray) + { + CoordStartIndex++; + Coords[Coords.Length - 1] = OperB; + } + + switch (Coords.Length - CoordStartIndex) + { + case 1: + Coords[0] = OpCode.Gpr8(); + + break; + case 2: + Coords[0] = OpCode.Gpr8(); + Coords[0].Index += CoordStartIndex; + + break; + case 3: + Coords[0] = OpCode.Gpr8(); + Coords[0].Index += CoordStartIndex; + + Coords[1] = OpCode.Gpr8(); + Coords[1].Index += 1 + CoordStartIndex; + + break; + default: + throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TLD4S"); + } + + if (Coords.Length - CoordStartIndex != 1) + { + Coords[Coords.Length - CoordStartIndex - 1] = OperB; + OperBIndex++; + } + + if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureType == TextureType.TwoD) + { + Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8(); + Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1; + OperBIndex--; + } + } + else + { + int IndexExtraCoord = 0; + + if (IsArray) + { + IndexExtraCoord++; + + Coords[Coords.Length - 1] = OpCode.Gpr8(); + } + + for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++) + { + Coords[Index] = OpCode.Gpr8(); + + Coords[Index].Index += Index; + + Coords[Index].Index += IndexExtraCoord; + + if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex) + { + Coords[Index].Index = ShaderIrOperGpr.ZRIndex; + } + } + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.AOFFI) != 0) + { + Offset = OpCode.Gpr20(); + Offset.Index += OperBIndex; + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + { + DepthCompare = OpCode.Gpr20(); + DepthCompare.Index += OperBIndex; + OperBIndex++; + } + + + for (int Ch = 0; Ch < 4; Ch++) + { + // Avoid usuless variable creation + if (!IsChannelUsed(ChMask, Ch)) + { + continue; + } + + ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); + + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords) + { + Component = Component, + Offset = Offset, + DepthCompare = DepthCompare + }; + + ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Tld4, OperA, OperB, OperC, Meta); + + Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); + } + + int RegInc = 0; + + for (int Ch = 0; Ch < 4; Ch++) + { + if (!IsChannelUsed(ChMask, Ch)) + { + continue; + } + + ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch); + + ShaderIrOperGpr Dst = OpCode.Gpr0(); + + Dst.Index += RegInc++; + + if (Dst.Index >= ShaderIrOperGpr.ZRIndex) + { + continue; + } + + Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Src))); + } + } + private static bool IsChannelUsed(int ChMask, int Ch) { return (ChMask & (1 << Ch)) != 0; diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs index 35dea61216..68ff214e4e 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs @@ -49,6 +49,7 @@ namespace Ryujinx.Graphics.Gal.Shader Ipa, Texb, Texs, + Tld4, Trunc, F_End, diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs index d200fc504b..a80e1280de 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs @@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Gal.Shader public ShaderIrOperGpr LevelOfDetail; public ShaderIrOperGpr Offset; public ShaderIrOperGpr DepthCompare; + public int Component; // for TLD4(S) public ShaderIrMetaTex(int Elem, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates) { diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index 177e36c3e1..d2bbd38c6b 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -122,6 +122,8 @@ namespace Ryujinx.Graphics.Gal.Shader Set("1101111101001x", ShaderDecode.Texq); Set("1101x00xxxxxxx", ShaderDecode.Texs); Set("1101101xxxxxxx", ShaderDecode.Tlds); + Set("110010xxxx111x", ShaderDecode.Tld4); + Set("1101111100xxxx", ShaderDecode.Tld4s); Set("01011111xxxxxx", ShaderDecode.Vmad); Set("0100111xxxxxxx", ShaderDecode.Xmad_CR); Set("0011011x00xxxx", ShaderDecode.Xmad_I); diff --git a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs index 5fcafe385a..9ef7b617ff 100644 --- a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs +++ b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs @@ -9,10 +9,11 @@ namespace Ryujinx.Graphics.Texture LZ = 0x02, // Load LOD Zero LB = 0x08, // Load Bias LL = 0x10, // Load LOD - LBA = 0x20, // Load Bias with OperA? - LLA = 0x40, // Load LOD with OperA? + LBA = 0x20, // Load Bias with OperA? Auto? + LLA = 0x40, // Load LOD with OperA? Auto? DC = 0x80, // Depth Compare AOFFI = 0x100, // Offset - MZ = 0x200 // Multisample Zero? + MZ = 0x200, // Multisample Zero? + PTP = 0x400 // ??? } }