Browse Source

Fix FMUL and TEXS shader instructions (#347)

gdkchan 7 năm trước cách đây
mục cha
commit
4f499b6845

+ 55 - 40
Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs

@@ -23,12 +23,12 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         public static void Fadd_C(ShaderIrBlock Block, long OpCode)
         {
-            EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd);
+            EmitFadd(Block, OpCode, ShaderOper.CR);
         }
 
         public static void Fadd_I(ShaderIrBlock Block, long OpCode)
         {
-            EmitAluBinaryF(Block, OpCode, ShaderOper.Immf, ShaderIrInst.Fadd);
+            EmitFadd(Block, OpCode, ShaderOper.Immf);
         }
 
         public static void Fadd_I32(ShaderIrBlock Block, long OpCode)
@@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         public static void Fadd_R(ShaderIrBlock Block, long OpCode)
         {
-            EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fadd);
+            EmitFadd(Block, OpCode, ShaderOper.RR);
         }
 
         public static void Ffma_CR(ShaderIrBlock Block, long OpCode)
@@ -101,17 +101,17 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         public static void Fmul_C(ShaderIrBlock Block, long OpCode)
         {
-            EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fmul);
+            EmitFmul(Block, OpCode, ShaderOper.CR);
         }
 
         public static void Fmul_I(ShaderIrBlock Block, long OpCode)
         {
-            EmitAluBinaryF(Block, OpCode, ShaderOper.Immf, ShaderIrInst.Fmul);
+            EmitFmul(Block, OpCode, ShaderOper.Immf);
         }
 
         public static void Fmul_R(ShaderIrBlock Block, long OpCode)
         {
-            EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fmul);
+            EmitFmul(Block, OpCode, ShaderOper.RR);
         }
 
         public static void Fset_C(ShaderIrBlock Block, long OpCode)
@@ -519,40 +519,6 @@ namespace Ryujinx.Graphics.Gal.Shader
             Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
         }
 
-        private static void EmitAluBinaryF(
-            ShaderIrBlock Block,
-            long          OpCode,
-            ShaderOper    Oper,
-            ShaderIrInst  Inst)
-        {
-            bool NegB = ((OpCode >> 45) & 1) != 0;
-            bool AbsA = ((OpCode >> 46) & 1) != 0;
-            bool NegA = ((OpCode >> 48) & 1) != 0;
-            bool AbsB = ((OpCode >> 49) & 1) != 0;
-
-            ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
-
-            if (Inst == ShaderIrInst.Fadd)
-            {
-                OperA = GetAluFabsFneg(OperA, AbsA, NegA);
-            }
-
-            switch (Oper)
-            {
-                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));
-            }
-
-            OperB = GetAluFabsFneg(OperB, AbsB, NegB);
-
-            ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
-
-            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
-        }
-
         private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
         {
             //TODO: Handle the case where position + length
@@ -609,6 +575,55 @@ namespace Ryujinx.Graphics.Gal.Shader
             Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
         }
 
+        private static void EmitFadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            bool NegB = ((OpCode >> 45) & 1) != 0;
+            bool AbsA = ((OpCode >> 46) & 1) != 0;
+            bool NegA = ((OpCode >> 48) & 1) != 0;
+            bool AbsB = ((OpCode >> 49) & 1) != 0;
+
+            ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
+
+            OperA = GetAluFabsFneg(OperA, AbsA, NegA);
+
+            switch (Oper)
+            {
+                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));
+            }
+
+            OperB = GetAluFabsFneg(OperB, AbsB, NegB);
+
+            ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+        }
+
+        private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            bool NegB = ((OpCode >> 48) & 1) != 0;
+
+            ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
+
+            switch (Oper)
+            {
+                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));
+            }
+
+            OperB = GetAluFneg(OperB, NegB);
+
+            ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+        }
+
         private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
         {
             bool NegB = ((OpCode >> 48) & 1) != 0;

+ 32 - 11
Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs

@@ -26,8 +26,8 @@ namespace Ryujinx.Graphics.Gal.Shader
         private static int[,] MaskLut = new int[,]
         {
             { ____, ____, ____, ____, ____, ____, ____, ____ },
-            { R___, _G__, __B_, ___A, RG__, ____, ____, ____ },
             { R___, _G__, __B_, ___A, RG__, R__A, _G_A, __BA },
+            { R___, _G__, __B_, ___A, RG__, ____, ____, ____ },
             { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
         };
 
@@ -209,9 +209,16 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             int LutIndex;
 
-            LutIndex  = GetOperGpr0(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 1 : 0;
+            LutIndex  = GetOperGpr0 (OpCode).Index != ShaderIrOperGpr.ZRIndex ? 1 : 0;
             LutIndex |= GetOperGpr28(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 2 : 0;
 
+            if (LutIndex == 0)
+            {
+                //Both registers are RZ, color is not written anywhere.
+                //So, the intruction is basically a no-op.
+                return;
+            }
+
             int ChMask = MaskLut[LutIndex, (OpCode >> 50) & 7];
 
             for (int Ch = 0; Ch < 4; Ch++)
@@ -227,6 +234,26 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             int RegInc = 0;
 
+            ShaderIrOperGpr GetDst()
+            {
+                ShaderIrOperGpr Dst;
+
+                switch (LutIndex)
+                {
+                    case 1: Dst = GetOperGpr0 (OpCode); break;
+                    case 2: Dst = GetOperGpr28(OpCode); break;
+                    case 3: Dst = (RegInc >> 1) != 0
+                        ? GetOperGpr28(OpCode)
+                        : GetOperGpr0 (OpCode); break;
+
+                    default: throw new InvalidOperationException();
+                }
+
+                Dst.Index += RegInc++ & 1;
+
+                return Dst;
+            }
+
             for (int Ch = 0; Ch < 4; Ch++)
             {
                 if (!IsChannelUsed(ChMask, Ch))
@@ -236,18 +263,12 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch);
 
-                ShaderIrOperGpr Dst = (RegInc >> 1) != 0
-                    ? GetOperGpr28(OpCode)
-                    : GetOperGpr0 (OpCode);
-
-                Dst.Index += RegInc++ & 1;
+                ShaderIrOperGpr Dst = GetDst();
 
-                if (Dst.Index >= ShaderIrOperGpr.ZRIndex)
+                if (Dst.Index != ShaderIrOperGpr.ZRIndex)
                 {
-                    continue;
+                    Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
                 }
-
-                Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
             }
         }