From 4f499b6845f7f46542cde945bad8f3275d3a11d5 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 13 Aug 2018 19:46:36 -0300 Subject: [PATCH] Fix FMUL and TEXS shader instructions (#347) --- .../Gal/Shader/ShaderDecodeAlu.cs | 95 +++++++++++-------- .../Gal/Shader/ShaderDecodeMem.cs | 43 ++++++--- 2 files changed, 87 insertions(+), 51 deletions(-) diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index 8486d8a7..b60da7c1 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/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; diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index 5ef2e2e5..e794e1f8 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/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); + ShaderIrOperGpr Dst = GetDst(); - Dst.Index += RegInc++ & 1; - - 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)); } }