diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index e9a6279a2e..28e66eb714 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -1164,7 +1164,7 @@ namespace Ryujinx.Graphics.Gal.Shader string Ch = "rgba".Substring(Meta.Elem, 1); - return "texture(" + DeclInfo.Name + ", " + Coords + ")." + Ch; + return GetTextureOperation(Op, DeclInfo.Name, Coords, Ch); } private string GetTexqExpr(ShaderIrOp Op) @@ -1197,20 +1197,35 @@ namespace Ryujinx.Graphics.Gal.Shader string Ch = "rgba".Substring(Meta.Elem, 1); - return "texture(" + Sampler + ", " + Coords + ")." + Ch; + return GetTextureOperation(Op, Sampler, Coords, Ch); } private string GetTxlfExpr(ShaderIrOp Op) { + // TODO: DC AND MZ ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + string Sampler = GetTexSamplerName(Op); string Coords = GetITexSamplerCoords(Op); string Ch = "rgba".Substring(Meta.Elem, 1); - return "texelFetch(" + Sampler + ", " + Coords + ", 0)." + Ch; + string Lod = "0"; + + if (Meta.LevelOfDetail != null) + { + Lod = GetOperExpr(Op, Meta.LevelOfDetail); + } + + if ((Suffix & TextureInstructionSuffix.AOFFI) != 0) + { + return "texelFetchOffset(" + Sampler + ", " + Coords + ", " + Lod + ", " + GetOperExpr(Op, Meta.Offset) + ")." + Ch; + } + + return "texelFetch(" + Sampler + ", " + Coords + ", " + Lod + ")." + Ch; } private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc"); @@ -1288,27 +1303,146 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; - switch (Meta.TextureType) + int Coords = ImageUtils.GetCoordsCountTextureType(Meta.TextureType); + + bool IsArray = ImageUtils.IsArray(Meta.TextureType); + + string GetLastArgument(ShaderIrNode Node) { - case TextureType.OneD: - return GetOperExpr(Op, Meta.Coordinates[0]); - case TextureType.ThreeD: - case TextureType.TwoDArray: - case TextureType.CubeMap: - return "vec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ")"; - case TextureType.CubeArray: - return "vec4(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ", " + GetOperExpr(Op, Meta.Coordinates[3]) + ")"; - case TextureType.TwoD: - default: - return "vec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ")"; + string Result = GetOperExpr(Op, Node); + + // array index is actually an integer so we need to pass it correctly + if (IsArray) + { + Result = "float(floatBitsToInt(" + Result + "))"; + } + + return Result; } + string LastArgument; + + switch (Coords) + { + case 1: + return GetOperExpr(Op, Meta.Coordinates[0]); + case 2: + LastArgument = GetLastArgument(Meta.Coordinates[1]); + + return "vec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + LastArgument + ")"; + case 3: + LastArgument = GetLastArgument(Meta.Coordinates[2]); + + return "vec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + LastArgument + ")"; + case 4: + LastArgument = GetLastArgument(Meta.Coordinates[3]); + + return "vec4(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ", " + LastArgument + ")"; + default: + throw new InvalidOperationException(); + } + + } + + private string GetTextureOffset(ShaderIrMetaTex Meta, string Oper) + { + string GetOffset(string Operation, int index) + { + return "(" + Operation + " >> " + index * 4 + ") & 0xF"; + } + + int Coords = ImageUtils.GetCoordsCountTextureType(Meta.TextureType); + + if (ImageUtils.IsArray(Meta.TextureType)) + Coords -= 1; + + // FIXME: DC not supported + switch (Coords) + { + case 1: + return GetOffset(Oper, 0); + case 2: + return "ivec2(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ")"; + case 3: + return "ivec3(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ")"; + case 4: + return "ivec4(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ", " + GetOffset(Oper, 3) + ")"; + default: + throw new InvalidOperationException(); + } + } + + private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch) + { + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + + // TODO: support LBA and LLA and DC + if ((Suffix & TextureInstructionSuffix.LZ) != 0) + { + if ((Suffix & TextureInstructionSuffix.AOFFI) != 0) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureLodOffset(" + Sampler + ", " + Coords + ", 0.0, " + Offset + ")." + Ch; + } + + return "textureLod(" + Sampler + ", " + Coords + ", 0.0)." + Ch; + } + else if ((Suffix & TextureInstructionSuffix.LB) != 0) + { + if ((Suffix & TextureInstructionSuffix.AOFFI) != 0) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch; + } + + return "texture(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch; + } + else if ((Suffix & TextureInstructionSuffix.LL) != 0) + { + if ((Suffix & TextureInstructionSuffix.AOFFI) != 0) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureLodOffset(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ", " + Offset + ")." + Ch; + } + + return "textureLod(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch; + } + else if (Suffix == TextureInstructionSuffix.AOFFI) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ")." + Ch; + } + else if (Suffix == TextureInstructionSuffix.None || Suffix == TextureInstructionSuffix.DC) + { + // FIXME: implement DC + // Load Standard + return "texture(" + Sampler + ", " + Coords + ")." + Ch; + } + throw new NotImplementedException($"Texture Suffix {Meta.TextureInstructionSuffix} is not implemented"); + } private string GetITexSamplerCoords(ShaderIrOp Op) { - return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ")"; + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + switch (ImageUtils.GetCoordsCountTextureType(Meta.TextureType)) + { + case 1: + return GetOperExpr(Op, Meta.Coordinates[0]); + case 2: + return "ivec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ")"; + case 3: + return "ivec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ")"; + default: + throw new InvalidOperationException(); + } } private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper) @@ -1347,22 +1481,6 @@ namespace Ryujinx.Graphics.Gal.Shader } break; } - - case ShaderIrOperImm Imm: - { - //For integer immediates being used as float, - //it's better (for readability) to just return the float value. - if (DstType == OperType.F32) - { - float Value = BitConverter.Int32BitsToSingle(Imm.Value); - - if (!float.IsNaN(Value) && !float.IsInfinity(Value)) - { - return GetFloatConst(Value); - } - } - break; - } } switch (DstType) diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index 7013aac98b..b8e3054304 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -30,40 +30,25 @@ namespace Ryujinx.Graphics.Gal.Shader { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } }; - private static TextureType TexToTextureType(int TexType) + private static TextureType TexToTextureType(int TexType, bool IsArray) { switch (TexType) { + case 0: + return IsArray ? TextureType.OneDArray : TextureType.OneD; case 2: - return TextureType.TwoD; + return IsArray ? TextureType.TwoDArray : TextureType.TwoD; case 4: + if (IsArray) + throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!"); return TextureType.ThreeD; case 6: - return TextureType.CubeMap; + return IsArray ? TextureType.CubeArray : TextureType.CubeMap; default: throw new InvalidOperationException(); } } - private static int GetCoordsCountTextureType(TextureType TextureType) - { - switch (TextureType) - { - case TextureType.OneD: - return 1; - case TextureType.OneDArray: - case TextureType.TwoD: - case TextureType.TwoDNoMipMap: - return 2; - case TextureType.ThreeD: - case TextureType.TwoDArray: - case TextureType.CubeMap: - return 3; - default: - throw new NotImplementedException($"TEX of TextureTpe.{TextureType} not implemented"); - } - } - private static TextureType TexsToTextureType(int TexType) { switch (TexType) @@ -86,7 +71,28 @@ namespace Ryujinx.Graphics.Gal.Shader return TextureType.ThreeD; case 0x18: case 0x1a: - return TextureType.CubeArray; + return TextureType.CubeMap; + default: + throw new InvalidOperationException(); + } + } + + public static TextureType TldsToTextureType(int TexType) + { + switch (TexType) + { + case 0: + case 2: + return TextureType.OneD; + case 4: + case 8: + case 0xa: + case 0xc: + return TextureType.TwoD; + case 0x10: + return TextureType.TwoDArray; + case 0xe: + return TextureType.ThreeD; default: throw new InvalidOperationException(); } @@ -195,29 +201,109 @@ namespace Ryujinx.Graphics.Gal.Shader public static void Tex(ShaderIrBlock Block, long OpCode, int Position) { - EmitTex(Block, OpCode, GprHandle: false); + TextureInstructionSuffix GetSuffix() + { + int Suffix = OpCode.Read(0x34, 0x38); + + switch (Suffix) + { + case 0: + return TextureInstructionSuffix.None; + case 0x8: + return TextureInstructionSuffix.LZ; + case 0x10: + return TextureInstructionSuffix.LB; + case 0x18: + return TextureInstructionSuffix.LL; + case 0x30: + return TextureInstructionSuffix.LBA; + case 0x38: + return TextureInstructionSuffix.LLA; + default: + throw new InvalidOperationException($"Invalid Suffix for TEX instruction {Suffix}"); + } + } + + TextureInstructionSuffix InstructionSuffix = GetSuffix(); + bool IsOffset = OpCode.Read(0x36); + + if (IsOffset) + InstructionSuffix |= TextureInstructionSuffix.AOFFI; + + EmitTex(Block, OpCode, InstructionSuffix, GprHandle: false); } public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position) { - EmitTex(Block, OpCode, GprHandle: true); + TextureInstructionSuffix GetSuffix() + { + int Suffix = OpCode.Read(0x24, 0xe); + switch (Suffix) + { + case 0: + return TextureInstructionSuffix.None; + case 0x2: + return TextureInstructionSuffix.LZ; + case 0x4: + return TextureInstructionSuffix.LB; + case 0x6: + return TextureInstructionSuffix.LL; + case 0xC: + return TextureInstructionSuffix.LBA; + case 0xE: + return TextureInstructionSuffix.LLA; + default: + throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {Suffix}"); + } + } + + TextureInstructionSuffix InstructionSuffix = GetSuffix(); + bool IsOffset = OpCode.Read(0x23); + + if (IsOffset) + InstructionSuffix |= TextureInstructionSuffix.AOFFI; + + EmitTex(Block, OpCode, InstructionSuffix, GprHandle: true); } - private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle) + private static void EmitTex(ShaderIrBlock Block, long OpCode, TextureInstructionSuffix TextureInstructionSuffix, bool GprHandle) { - // TODO: Support array textures - TextureType TextureType = TexToTextureType(OpCode.Read(28, 6)); + bool IsArray = OpCode.HasArray(); + + TextureType TextureType = TexToTextureType(OpCode.Read(28, 6), IsArray); Block.AddNode(new ShaderIrCmnt($"TextureType: {TextureType}")); + Block.AddNode(new ShaderIrCmnt($"TextureInstructionSuffix: {TextureInstructionSuffix}")); + Block.AddNode(new ShaderIrCmnt($"Array: {IsArray}")); - // FIXME: check if this is right - ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[GetCoordsCountTextureType(TextureType)]; + bool HasDepthCompare = OpCode.Read(0x32); - for (int Index = 0; Index < Coords.Length; Index++) + if (HasDepthCompare) + { + TextureInstructionSuffix |= TextureInstructionSuffix.DC; + } + + ShaderIrOperGpr[] Coords = null; + + Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)]; + + int IndexExtraCoord = 0; + + if (IsArray) + { + IndexExtraCoord++; + + Coords[Coords.Length - 1] = OpCode.Gpr8(); + } + + + for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++) { ShaderIrOperGpr CoordReg = OpCode.Gpr8(); CoordReg.Index += Index; + Coords[Index].Index += IndexExtraCoord; + if (!CoordReg.IsValidRegister) { CoordReg.Index = ShaderIrOperGpr.ZRIndex; @@ -230,6 +316,41 @@ namespace Ryujinx.Graphics.Gal.Shader int ChMask = OpCode.Read(31, 0xf); + ShaderIrOperGpr LevelOfDetail = null; + ShaderIrOperGpr Offset = null; + ShaderIrOperGpr DepthCompare = null; + + // TODO: determine first argument when TEX.B is used + int OperBIndex = GprHandle ? 1 : 0; + + if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0 || + (TextureInstructionSuffix & TextureInstructionSuffix.LB) != 0 || + (TextureInstructionSuffix & TextureInstructionSuffix.LBA) != 0 || + (TextureInstructionSuffix & TextureInstructionSuffix.LLA) != 0) + { + LevelOfDetail = OpCode.Gpr20(); + LevelOfDetail.Index += OperBIndex; + + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.AOFFI) != 0) + { + Offset = OpCode.Gpr20(); + Offset.Index += OperBIndex; + + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + { + DepthCompare = OpCode.Gpr20(); + DepthCompare.Index += OperBIndex; + + OperBIndex++; + } + + // ??? ShaderIrNode OperC = GprHandle ? (ShaderIrNode)OpCode.Gpr20() : (ShaderIrNode)OpCode.Imm13_36(); @@ -254,9 +375,14 @@ namespace Ryujinx.Graphics.Gal.Shader continue; } - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, Coords); + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords) + { + LevelOfDetail = LevelOfDetail, + Offset = Offset, + DepthCompare = DepthCompare + }; - ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta); + ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords.Length > 1 ? Coords[1] : null, OperC, Meta); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); } @@ -264,82 +390,176 @@ namespace Ryujinx.Graphics.Gal.Shader public static void Texs(ShaderIrBlock Block, long OpCode, int Position) { - EmitTexs(Block, OpCode, ShaderIrInst.Texs); + TextureInstructionSuffix GetSuffix() + { + int Suffix = OpCode.Read(0x34, 0x1e); + switch (Suffix) + { + case 0: + case 0x4: + case 0x10: + case 0x16: + return TextureInstructionSuffix.LZ; + case 0x6: + case 0x1a: + return TextureInstructionSuffix.LL; + case 0x8: + return TextureInstructionSuffix.DC; + case 0x2: + case 0xe: + case 0x14: + case 0x18: + return TextureInstructionSuffix.None; + case 0xa: + return TextureInstructionSuffix.LL | TextureInstructionSuffix.DC; + case 0xc: + case 0x12: + return TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC; + default: + throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {Suffix}"); + } + } + + TextureType TextureType = TexsToTextureType(OpCode.Read(52, 0x1e)); + + EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureType, GetSuffix()); } public static void Tlds(ShaderIrBlock Block, long OpCode, int Position) { - EmitTexs(Block, OpCode, ShaderIrInst.Txlf); - } - - private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) - { - TextureType TextureType = TexsToTextureType(OpCode.Read(52, 0x1e)); - Block.AddNode(new ShaderIrCmnt($"TextureType: {TextureType}")); - - if (Inst == ShaderIrInst.Txlf && TextureType == TextureType.CubeArray) + TextureInstructionSuffix GetSuffix() { - throw new InvalidOperationException("TXLF instructions cannot use CUBE modifier!"); - } - - //TODO: Support other formats. - ShaderIrOperGpr OperA = OpCode.Gpr8(); - ShaderIrOperGpr OperB = OpCode.Gpr20(); - - ShaderIrOperGpr[] GetCoordinates() - { - ShaderIrOperGpr X; - ShaderIrOperGpr Y; - ShaderIrOperGpr Z; - ShaderIrOperGpr Index; - - switch (TextureType) + int Suffix = OpCode.Read(0x34, 0x1e); + switch (Suffix) { - case TextureType.OneD: - X = OperA; - - return CoordsRegistersToTempRegisters(Block, X); - case TextureType.TwoDArray: - Index = OperA; - - X = OpCode.Gpr8(); - X.Index++; - - Y = OperB; - - return CoordsRegistersToTempRegisters(Block, X, Y, Index); - case TextureType.ThreeD: - case TextureType.CubeMap: - X = OperA; - - Y = OpCode.Gpr8(); - Y.Index += 1; - - Z = OperB; - - return CoordsRegistersToTempRegisters(Block, X, Y, Z); - case TextureType.CubeArray: - Index = OperA; - - X = OpCode.Gpr8(); - X.Index += 1; - - Y = OpCode.Gpr8(); - Y.Index += 2; - - Z = OperB; - - return CoordsRegistersToTempRegisters(Block, X, Y, Z, Index); - case TextureType.TwoD: - X = OperA; - Y = OperB; - - return new ShaderIrOperGpr[] { X, Y }; + case 0: + case 0x4: + case 0x8: + return TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOFFI; + case 0xc: + return TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ; + case 0xe: + case 0x10: + return TextureInstructionSuffix.LZ; + case 0x2: + case 0xa: + return TextureInstructionSuffix.LL; + case 0x18: + return TextureInstructionSuffix.LL | TextureInstructionSuffix.AOFFI; default: - throw new NotImplementedException($"TEXS of TextureType.{TextureType} not supported!"); + throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {Suffix}"); } } + TextureType TextureType = TldsToTextureType(OpCode.Read(52, 0x1e)); + + EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureType, GetSuffix()); + } + + private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix) + { + Block.AddNode(new ShaderIrCmnt($"TextureType: {TextureType}")); + Block.AddNode(new ShaderIrCmnt($"TextureInstructionSuffix: {TextureInstructionSuffix}")); + + if (Inst == ShaderIrInst.Txlf && TextureType == TextureType.CubeArray) + { + throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!"); + } + + // This is the only array type that is known to be usable with TEXS + bool IsArray = ImageUtils.IsArray(TextureType); + + ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)]; + + if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + { + // TODO + //throw new NotImplementedException($"TEXS.DC isn't implemented yet"); + } + + + ShaderIrOperGpr OperA = OpCode.Gpr8(); + ShaderIrOperGpr OperB = OpCode.Gpr20(); + + ShaderIrOperGpr SuffixExtra = OpCode.Gpr20(); + SuffixExtra.Index += 1; + + 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 TEXS"); + } + + int OperBIndex = 0; + + ShaderIrOperGpr LevelOfDetail = null; + ShaderIrOperGpr Offset = null; + ShaderIrOperGpr DepthCompare = null; + + // OperB is always the last value + // Not applicable to 1d textures + if (Coords.Length - CoordStartIndex != 1) + { + Coords[Coords.Length - CoordStartIndex - 1] = OperB; + OperBIndex++; + } + + // Encoding of TEXS/TLDS is a bit special and change for 2d textures + // NOTE: OperA seems to hold at best two args. + // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB. + 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--; + } + + // TODO: Find what MZ do and what change about the encoding (Maybe Multisample?) + if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0) + { + LevelOfDetail = OpCode.Gpr20(); + LevelOfDetail.Index += OperBIndex; + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.AOFFI) != 0) + { + Offset = OpCode.Gpr20(); + Offset.Index += OperBIndex; + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + { + DepthCompare = OpCode.Gpr20(); + DepthCompare.Index += OperBIndex; + OperBIndex++; + } int LutIndex; @@ -417,8 +637,12 @@ namespace Ryujinx.Graphics.Gal.Shader continue; } - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, GetCoordinates()); - + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords) + { + LevelOfDetail = LevelOfDetail, + Offset = Offset, + DepthCompare = DepthCompare + }; ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); ShaderIrOperGpr Dst = GetDst(); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs index f0f92148e6..e241e1ca58 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs @@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gal.Shader return ((int)(OpCode >> 20) << 8) >> 8; } + private static bool HasArray(this long OpCode) + { + return OpCode.Read(0x1c); + } + private static ShaderIrOperAbuf[] Abuf20(this long OpCode) { int Abuf = OpCode.Read(20, 0x3ff); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs index 27f67961b4..d200fc504b 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs @@ -4,15 +4,20 @@ namespace Ryujinx.Graphics.Gal.Shader { class ShaderIrMetaTex : ShaderIrMeta { - public int Elem { get; private set; } - public TextureType TextureType { get; private set; } - public ShaderIrNode[] Coordinates { get; private set; } + public int Elem { get; private set; } + public TextureType TextureType { get; private set; } + public ShaderIrNode[] Coordinates { get; private set; } + public TextureInstructionSuffix TextureInstructionSuffix { get; private set; } + public ShaderIrOperGpr LevelOfDetail; + public ShaderIrOperGpr Offset; + public ShaderIrOperGpr DepthCompare; - public ShaderIrMetaTex(int Elem, TextureType TextureType, params ShaderIrNode[] Coordinates) + public ShaderIrMetaTex(int Elem, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates) { - this.Elem = Elem; - this.TextureType = TextureType; - this.Coordinates = Coordinates; + this.Elem = Elem; + this.TextureType = TextureType; + this.TextureInstructionSuffix = TextureInstructionSuffix; + this.Coordinates = Coordinates; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs index 46ee1a725f..74f0fdad2c 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs @@ -469,5 +469,39 @@ namespace Ryujinx.Graphics.Texture throw new NotSupportedException($"Texture type {TextureType} currently not supported!"); } } + + public static bool IsArray(TextureType TextureType) + { + switch (TextureType) + { + case TextureType.OneDArray: + case TextureType.TwoDArray: + case TextureType.CubeArray: + return true; + default: + return false; + } + } + + public static int GetCoordsCountTextureType(TextureType TextureType) + { + switch (TextureType) + { + case TextureType.OneD: + return 1; + case TextureType.OneDArray: + case TextureType.TwoD: + case TextureType.TwoDNoMipMap: + return 2; + case TextureType.ThreeD: + case TextureType.TwoDArray: + case TextureType.CubeMap: + return 3; + case TextureType.CubeArray: + return 4; + default: + throw new NotImplementedException($"TextureTpe.{TextureType} not implemented yet"); + } + } } } diff --git a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs new file mode 100644 index 0000000000..fd3c6877c9 --- /dev/null +++ b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs @@ -0,0 +1,18 @@ +using System; + +namespace Ryujinx.Graphics.Texture +{ + [Flags] + enum TextureInstructionSuffix + { + None = 0x00, // No Modifier + 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? + DC = 0x80, // Depth Compare + AOFFI = 0x100, // Offset + MZ = 0x200 // Multisample Zero? + } +}