diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index 64090285e2..a6c3b88b1c 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -4,6 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader { class GlslDecl { + public const int VertexIdAttr = 0x2fc; + private const int AttrStartIndex = 8; private const int TexStartIndex = 8; @@ -130,6 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader case ShaderIrOperAbuf Abuf: { + //This is a built-in input variable. + if (Abuf.Offs == VertexIdAttr) + { + break; + } + int Index = Abuf.Offs >> 4; int Elem = (Abuf.Offs >> 2) & 3; diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 2048dde5a1..80090137a0 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -12,6 +12,13 @@ namespace Ryujinx.Graphics.Gal.Shader private Dictionary InstsExpr; + private enum OperType + { + Bool, + F32, + I32 + } + private const string IdentationStr = " "; private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" }; @@ -24,6 +31,8 @@ namespace Ryujinx.Graphics.Gal.Shader { InstsExpr = new Dictionary() { + { ShaderIrInst.And, GetAndExpr }, + { ShaderIrInst.Asr, GetAsrExpr }, { ShaderIrInst.Band, GetBandExpr }, { ShaderIrInst.Bnot, GetBnotExpr }, { ShaderIrInst.Clt, GetCltExpr }, @@ -46,10 +55,16 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrInst.Fsin, GetFsinExpr }, { ShaderIrInst.Ipa, GetIpaExpr }, { ShaderIrInst.Kil, GetKilExpr }, + { ShaderIrInst.Lsr, GetLsrExpr }, + { ShaderIrInst.Not, GetNotExpr }, + { ShaderIrInst.Or, GetOrExpr }, + { ShaderIrInst.Stof, GetStofExpr }, + { ShaderIrInst.Utof, GetUtofExpr }, { ShaderIrInst.Texr, GetTexrExpr }, { ShaderIrInst.Texg, GetTexgExpr }, { ShaderIrInst.Texb, GetTexbExpr }, - { ShaderIrInst.Texa, GetTexaExpr } + { ShaderIrInst.Texa, GetTexaExpr }, + { ShaderIrInst.Xor, GetXorExpr }, }; } @@ -63,7 +78,7 @@ namespace Ryujinx.Graphics.Gal.Shader SB = new StringBuilder(); - SB.AppendLine("#version 430"); + SB.AppendLine("#version 330 core"); PrintDeclTextures(); PrintDeclUniforms(); @@ -207,17 +222,21 @@ namespace Ryujinx.Graphics.Gal.Shader if (Node is ShaderIrCond Cond) { - string SubScopeName = "if (" + GetInOperName(Cond.Pred, true) + ")"; + string SubScopeName = "if (" + GetSrcExpr(Cond.Pred, true) + ")"; PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child); } else if (Node is ShaderIrAsg Asg && IsValidOutOper(Asg.Dst)) { - SB.AppendLine(Identation + GetOutOperName(Asg.Dst) + " = " + GetInOperName(Asg.Src, true) + ";"); + string Expr = GetSrcExpr(Asg.Src, true); + + Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr); + + SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";"); } else if (Node is ShaderIrOp Op) { - SB.AppendLine(Identation + GetInOperName(Op, true) + ";"); + SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";"); } else { @@ -242,7 +261,7 @@ namespace Ryujinx.Graphics.Gal.Shader return true; } - private string GetOutOperName(ShaderIrNode Node) + private string GetDstOperName(ShaderIrNode Node) { if (Node is ShaderIrOperAbuf Abuf) { @@ -260,7 +279,7 @@ namespace Ryujinx.Graphics.Gal.Shader throw new ArgumentException(nameof(Node)); } - private string GetInOperName(ShaderIrNode Node, bool Entry = false) + private string GetSrcExpr(ShaderIrNode Node, bool Entry = false) { switch (Node) { @@ -317,6 +336,11 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetName(IReadOnlyDictionary Dict, ShaderIrOperAbuf Abuf) { + if (Abuf.Offs == GlslDecl.VertexIdAttr) + { + return "gl_VertexID"; + } + int Index = Abuf.Offs >> 4; int Elem = (Abuf.Offs >> 2) & 3; @@ -335,12 +359,21 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetValue(ShaderIrOperImm Imm) { - return Imm.Value.ToString(CultureInfo.InvariantCulture); + //Only use hex is the value is too big and would likely be hard to read as int. + if (Imm.Value > 0xfff || + Imm.Value < -0xfff) + { + return "0x" + Imm.Value.ToString("x8", CultureInfo.InvariantCulture); + } + else + { + return Imm.Value.ToString(CultureInfo.InvariantCulture); + } } private string GetValue(ShaderIrOperImmf Immf) { - return Immf.Value.ToString(CultureInfo.InvariantCulture); + return Immf.Value.ToString(CultureInfo.InvariantCulture) + "f"; } private string GetName(ShaderIrOperPred Pred) @@ -373,6 +406,10 @@ namespace Ryujinx.Graphics.Gal.Shader return "xyzw".Substring(Elem, 1); } + private string GetAndExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&"); + + private string GetAsrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">>"); + private string GetBandExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&&"); private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!"); @@ -408,31 +445,46 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin"); - private string GetIpaExpr(ShaderIrOp Op) => GetInOperName(Op.OperandA); + private string GetIpaExpr(ShaderIrOp Op) => GetSrcExpr(Op.OperandA); private string GetKilExpr(ShaderIrOp Op) => "discard"; + private string GetLsrExpr(ShaderIrOp Op) + { + return "(int)((uint)" + GetOperExpr(Op, Op.OperandA) + " >> " + + GetOperExpr(Op, Op.OperandB) + ")"; + } + + private string GetNotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "~"); + + private string GetOrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "|"); + + private string GetStofExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "(float)"); + private string GetUtofExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "(float)(uint)"); + + private string GetXorExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "^"); + private string GetUnaryCall(ShaderIrOp Op, string FuncName) { - return FuncName + "(" + GetInOperName(Op.OperandA) + ")"; + return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")"; } private string GetUnaryExpr(ShaderIrOp Op, string Opr) { - return Opr + GetInOperName(Op.OperandA); + return Opr + GetOperExpr(Op, Op.OperandA); } private string GetBinaryExpr(ShaderIrOp Op, string Opr) { - return GetInOperName(Op.OperandA) + " " + Opr + " " + - GetInOperName(Op.OperandB); + return GetOperExpr(Op, Op.OperandA) + " " + Opr + " " + + GetOperExpr(Op, Op.OperandB); } private string GetTernaryExpr(ShaderIrOp Op, string Opr1, string Opr2) { - return GetInOperName(Op.OperandA) + " " + Opr1 + " " + - GetInOperName(Op.OperandB) + " " + Opr2 + " " + - GetInOperName(Op.OperandC); + return GetOperExpr(Op, Op.OperandA) + " " + Opr1 + " " + + GetOperExpr(Op, Op.OperandB) + " " + Opr2 + " " + + GetOperExpr(Op, Op.OperandC); } private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r'); @@ -461,8 +513,102 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetTexSamplerCoords(ShaderIrOp Op) { - return "vec2(" + GetInOperName(Op.OperandA, Entry: true) + ", " + - GetInOperName(Op.OperandB, Entry: true) + ")"; + return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " + + GetOperExpr(Op, Op.OperandB) + ")"; + } + + private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper) + { + return GetExprWithCast(Op, Oper, GetSrcExpr(Oper)); + } + + private static string GetExprWithCast(ShaderIrNode Dst, ShaderIrNode Src, string Expr) + { + //Note: The "DstType" (of the cast) is the type that the operation + //uses on the source operands, while the "SrcType" is the destination + //type of the operand result (if it is a operation) or just the type + //of the variable for registers/uniforms/attributes. + OperType DstType = GetSrcNodeType(Dst); + OperType SrcType = GetDstNodeType(Src); + + if (DstType != SrcType) + { + //Check for invalid casts + //(like bool to int/float and others). + if (SrcType != OperType.F32 && + SrcType != OperType.I32) + { + throw new InvalidOperationException(); + } + + //For integer immediates being used as float, + //it's better (for readability) to just return the float value. + if (Src is ShaderIrOperImm Imm && DstType == OperType.F32) + { + float Value = BitConverter.Int32BitsToSingle(Imm.Value); + + return Value.ToString(CultureInfo.InvariantCulture) + "f"; + } + + switch (DstType) + { + case OperType.F32: Expr = "intBitsToFloat(" + Expr + ")"; break; + case OperType.I32: Expr = "floatBitsToInt(" + Expr + ")"; break; + } + } + + return Expr; + } + + private static OperType GetDstNodeType(ShaderIrNode Node) + { + if (Node is ShaderIrOp Op) + { + switch (Op.Inst) + { + case ShaderIrInst.Stof: return OperType.F32; + case ShaderIrInst.Utof: return OperType.F32; + } + } + + return GetSrcNodeType(Node); + } + + private static OperType GetSrcNodeType(ShaderIrNode Node) + { + switch (Node) + { + case ShaderIrOperAbuf Abuf: + return Abuf.Offs == GlslDecl.VertexIdAttr + ? OperType.I32 + : OperType.F32; + + case ShaderIrOperCbuf Cbuf: return OperType.F32; + case ShaderIrOperGpr Gpr: return OperType.F32; + case ShaderIrOperImm Imm: return OperType.I32; + case ShaderIrOperImmf Immf: return OperType.F32; + case ShaderIrOperPred Pred: return OperType.Bool; + + case ShaderIrOp Op: + if (Op.Inst > ShaderIrInst.B_Start && + Op.Inst < ShaderIrInst.B_End) + { + return OperType.Bool; + } + else if (Op.Inst > ShaderIrInst.F_Start && + Op.Inst < ShaderIrInst.F_End) + { + return OperType.F32; + } + else if (Op.Inst > ShaderIrInst.I_Start && + Op.Inst < ShaderIrInst.I_End) + { + return OperType.I32; + } + break; + } + + throw new ArgumentException(nameof(Node)); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index e43531e5a3..5c2f493e4f 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -6,27 +6,19 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - private enum ShaderOper - { - CR, - RR, - RC, - Imm - } - public static void Fadd_C(ShaderIrBlock Block, long OpCode) { - EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd); + EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd); } public static void Fadd_I(ShaderIrBlock Block, long OpCode) { - EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fadd); + EmitAluBinaryF(Block, OpCode, ShaderOper.Immf, ShaderIrInst.Fadd); } public static void Fadd_R(ShaderIrBlock Block, long OpCode) { - EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fadd); + EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fadd); } public static void Ffma_CR(ShaderIrBlock Block, long OpCode) @@ -36,7 +28,7 @@ namespace Ryujinx.Graphics.Gal.Shader public static void Ffma_I(ShaderIrBlock Block, long OpCode) { - EmitAluFfma(Block, OpCode, ShaderOper.Imm); + EmitAluFfma(Block, OpCode, ShaderOper.Immf); } public static void Ffma_RC(ShaderIrBlock Block, long OpCode) @@ -51,17 +43,17 @@ namespace Ryujinx.Graphics.Gal.Shader public static void Fmul_C(ShaderIrBlock Block, long OpCode) { - EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fmul); + EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fmul); } public static void Fmul_I(ShaderIrBlock Block, long OpCode) { - EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fmul); + EmitAluBinaryF(Block, OpCode, ShaderOper.Immf, ShaderIrInst.Fmul); } public static void Fmul_R(ShaderIrBlock Block, long OpCode) { - EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fmul); + EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fmul); } public static void Fsetp_C(ShaderIrBlock Block, long OpCode) @@ -71,7 +63,7 @@ namespace Ryujinx.Graphics.Gal.Shader public static void Fsetp_I(ShaderIrBlock Block, long OpCode) { - EmitFsetp(Block, OpCode, ShaderOper.Imm); + EmitFsetp(Block, OpCode, ShaderOper.Immf); } public static void Fsetp_R(ShaderIrBlock Block, long OpCode) @@ -89,6 +81,40 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } + public static void Lop32i(ShaderIrBlock Block, long OpCode) + { + int SubOp = (int)(OpCode >> 53) & 3; + + bool Ia = ((OpCode >> 55) & 1) != 0; + bool Ib = ((OpCode >> 56) & 1) != 0; + + ShaderIrInst Inst = 0; + + switch (SubOp) + { + case 0: Inst = ShaderIrInst.And; break; + case 1: Inst = ShaderIrInst.Or; break; + case 2: Inst = ShaderIrInst.Xor; break; + } + + ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), Ia); + + //SubOp == 3 is pass, used by the not instruction + //which just moves the inverted register value. + if (SubOp < 3) + { + ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), Ib); + + ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + else + { + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); + } + } + public static void Mufu(ShaderIrBlock Block, long OpCode) { int SubOp = (int)(OpCode >> 20) & 7; @@ -117,11 +143,55 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } + public static void Shr_C(ShaderIrBlock Block, long OpCode) + { + EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode)); + } + + public static void Shr_I(ShaderIrBlock Block, long OpCode) + { + EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode)); + } + + public static void Shr_R(ShaderIrBlock Block, long OpCode) + { + EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode)); + } + + private static ShaderIrInst GetShrInst(long OpCode) + { + bool Signed = ((OpCode >> 48) & 1) != 0; + + return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; + } + private static void EmitAluBinary( ShaderIrBlock Block, long OpCode, ShaderOper Oper, ShaderIrInst Inst) + { + ShaderIrNode OperA = GetOperGpr8(OpCode), OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + + private static void EmitAluBinaryF( + ShaderIrBlock Block, + long OpCode, + ShaderOper Oper, + ShaderIrInst Inst) { bool Nb = ((OpCode >> 45) & 1) != 0; bool Aa = ((OpCode >> 46) & 1) != 0; @@ -138,9 +208,9 @@ namespace Ryujinx.Graphics.Gal.Shader switch (Oper) { - case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; - case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break; - case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; default: throw new ArgumentException(nameof(Oper)); } @@ -163,10 +233,10 @@ namespace Ryujinx.Graphics.Gal.Shader switch (Oper) { - case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; - case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break; - case ShaderOper.RC: OperB = GetOperGpr39 (OpCode); break; - case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break; + case ShaderOper.RC: OperB = GetOperGpr39 (OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; default: throw new ArgumentException(nameof(Oper)); } @@ -198,9 +268,9 @@ namespace Ryujinx.Graphics.Gal.Shader switch (Oper) { - case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; - case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break; - case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; default: throw new ArgumentException(nameof(Oper)); } @@ -241,20 +311,5 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode)); } - - private static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg) - { - return GetAluNeg(GetAluAbs(Node, Abs), Neg); - } - - private static ShaderIrNode GetAluAbs(ShaderIrNode Node, bool Abs) - { - return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node; - } - - private static ShaderIrNode GetAluNeg(ShaderIrNode Node, bool Neg) - { - return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node; - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs index c9b904b38b..035b957df6 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs @@ -60,6 +60,20 @@ namespace Ryujinx.Graphics.Gal.Shader return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff); } + public static ShaderIrNode GetOperImm19_20(long OpCode) + { + uint Value = (uint)(OpCode >> 20) & 0x7ffff; + + bool Neg = ((OpCode >> 56) & 1) != 0; + + if (Neg) + { + Value |= 0x80000000; + } + + return new ShaderIrOperImm((int)Value); + } + public static ShaderIrNode GetOperImmf19_20(long OpCode) { uint Imm = (uint)(OpCode >> 20) & 0x7ffff; @@ -83,6 +97,11 @@ namespace Ryujinx.Graphics.Gal.Shader return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff); } + public static ShaderIrOperImm GetOperImm32_20(long OpCode) + { + return new ShaderIrOperImm((int)(OpCode >> 20)); + } + public static ShaderIrOperPred GetOperPred3(long OpCode) { return new ShaderIrOperPred((int)(OpCode >> 3) & 7); @@ -168,5 +187,25 @@ namespace Ryujinx.Graphics.Gal.Shader return new ShaderIrOperPred(Pred); } + + public static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg) + { + return GetAluNeg(GetAluAbs(Node, Abs), Neg); + } + + public static ShaderIrNode GetAluAbs(ShaderIrNode Node, bool Abs) + { + return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node; + } + + public static ShaderIrNode GetAluNeg(ShaderIrNode Node, bool Neg) + { + return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node; + } + + public static ShaderIrNode GetAluNot(ShaderIrNode Node, bool Not) + { + return Not ? new ShaderIrOp(ShaderIrInst.Not, Node) : Node; + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs new file mode 100644 index 0000000000..50c740bf9a --- /dev/null +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs @@ -0,0 +1,128 @@ +using System; + +using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; + +namespace Ryujinx.Graphics.Gal.Shader +{ + static partial class ShaderDecode + { + private enum IntType + { + U8 = 0, + U16 = 1, + U32 = 2, + U64 = 3, + S8 = 4, + S16 = 5, + S32 = 6, + S64 = 7 + } + + private enum FloatType + { + F16 = 1, + F32 = 2, + F64 = 3 + } + + public static void I2f_C(ShaderIrBlock Block, long OpCode) + { + EmitI2f(Block, OpCode, ShaderOper.CR); + } + + public static void I2f_I(ShaderIrBlock Block, long OpCode) + { + EmitI2f(Block, OpCode, ShaderOper.Imm); + } + + public static void I2f_R(ShaderIrBlock Block, long OpCode) + { + EmitI2f(Block, OpCode, ShaderOper.RR); + } + + private static void EmitI2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + IntType Type = GetIntType(OpCode); + + if (Type == IntType.U64 || + Type == IntType.S64) + { + //TODO: 64-bits support. + //Note: GLSL doesn't support 64-bits integers. + throw new NotImplementedException(); + } + + int Sel = (int)(OpCode >> 41) & 3; + + bool Na = ((OpCode >> 45) & 1) != 0; + bool Aa = ((OpCode >> 49) & 1) != 0; + + ShaderIrNode OperA; + + switch (Oper) + { + case ShaderOper.CR: OperA = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperA = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperA = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + OperA = GetAluAbsNeg(OperA, Aa, Na); + + bool Signed = Type >= IntType.S8; + + int Shift = Sel * 8; + + int Size = 8 << ((int)Type & 3); + + ulong Mask = ulong.MaxValue >> (64 - Size); + + int Mask32 = (int)Mask; + + if (Shift != 0) + { + OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift)); + } + + if (Mask != uint.MaxValue) + { + OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm(Mask32)); + } + + ShaderIrInst Inst = Signed + ? ShaderIrInst.Stof + : ShaderIrInst.Utof; + + ShaderIrNode Op = new ShaderIrOp(Inst, OperA); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + + public static void Mov32i(ShaderIrBlock Block, long OpCode) + { + ShaderIrOperImm Imm = GetOperImm32_20(OpCode); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode)); + } + + private static IntType GetIntType(long OpCode) + { + bool Signed = ((OpCode >> 13) & 1) != 0; + + IntType Type = (IntType)((OpCode >> 10) & 3); + + if (Signed) + { + Type += (int)IntType.S8; + } + + return Type; + } + + private static FloatType GetFloatType(long OpCode) + { + return (FloatType)((OpCode >> 8) & 3); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs index b9ca8bfb29..b6f4e80b98 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs @@ -2,6 +2,7 @@ namespace Ryujinx.Graphics.Gal.Shader { enum ShaderIrInst { + B_Start, Band, Bnot, Bor, @@ -20,7 +21,9 @@ namespace Ryujinx.Graphics.Gal.Shader Cgtu, Cneu, Cgeu, - Exit, + B_End, + + F_Start, Fabs, Fadd, Fcos, @@ -33,10 +36,24 @@ namespace Ryujinx.Graphics.Gal.Shader Frsq, Fsin, Ipa, - Kil, Texr, Texg, Texb, - Texa + Texa, + F_End, + + I_Start, + And, + Asr, + Lsr, + Not, + Or, + Stof, + Utof, + Xor, + I_End, + + Exit, + Kil } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index aa9682036f..48c3b2ee5e 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -27,10 +27,18 @@ namespace Ryujinx.Graphics.Gal.Shader Set("010010111011xx", ShaderDecode.Fsetp_C); Set("0011011x1011xx", ShaderDecode.Fsetp_I); Set("010110111011xx", ShaderDecode.Fsetp_R); + Set("0100110010111x", ShaderDecode.I2f_C); + Set("0011100x10111x", ShaderDecode.I2f_I); + Set("0101110010111x", ShaderDecode.I2f_R); Set("11100000xxxxxx", ShaderDecode.Ipa); Set("111000110011xx", ShaderDecode.Kil); Set("1110111111011x", ShaderDecode.Ld_A); + Set("000001xxxxxxxx", ShaderDecode.Lop32i); + Set("000000010000xx", ShaderDecode.Mov32i); Set("0101000010000x", ShaderDecode.Mufu); + Set("0100110000101x", ShaderDecode.Shr_C); + Set("0011100x00101x", ShaderDecode.Shr_I); + Set("0101110000101x", ShaderDecode.Shr_R); Set("1110111111110x", ShaderDecode.St_A); Set("1101100xxxxxxx", ShaderDecode.Texs); #endregion diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs new file mode 100644 index 0000000000..7989deed1e --- /dev/null +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Graphics.Gal.Shader +{ + enum ShaderOper + { + CR, + RC, + RR, + Imm, + Immf + } +} \ No newline at end of file