Fix FMUL and TEXS shader instructions (#347)

This commit is contained in:
gdkchan 2018-08-13 19:46:36 -03:00 committed by GitHub
parent 6e48312052
commit 4f499b6845
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 51 deletions

View file

@ -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;

View file

@ -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));
}
}