aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-08-13 19:46:36 -0300
committerGitHub <noreply@github.com>2018-08-13 19:46:36 -0300
commit4f499b6845f7f46542cde945bad8f3275d3a11d5 (patch)
tree1d3e59451d0dc9761b0971a989e61175857d7a4d
parent6e483120527c749854066b1ab0c5a1d53d49f0e3 (diff)
Fix FMUL and TEXS shader instructions (#347)
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs95
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs43
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);
-
- 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));
}
}