forked from Mirror/Ryujinx
Fix FMUL and TEXS shader instructions (#347)
This commit is contained in:
parent
6e48312052
commit
4f499b6845
2 changed files with 87 additions and 51 deletions
|
@ -23,12 +23,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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));
|
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)
|
private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
//TODO: Handle the case where position + length
|
//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));
|
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)
|
private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool NegB = ((OpCode >> 48) & 1) != 0;
|
bool NegB = ((OpCode >> 48) & 1) != 0;
|
||||||
|
|
|
@ -26,8 +26,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
private static int[,] MaskLut = new int[,]
|
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__, R__A, _G_A, __BA },
|
||||||
|
{ R___, _G__, __B_, ___A, RG__, ____, ____, ____ },
|
||||||
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -212,6 +212,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
LutIndex = GetOperGpr0 (OpCode).Index != ShaderIrOperGpr.ZRIndex ? 1 : 0;
|
LutIndex = GetOperGpr0 (OpCode).Index != ShaderIrOperGpr.ZRIndex ? 1 : 0;
|
||||||
LutIndex |= GetOperGpr28(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 2 : 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];
|
int ChMask = MaskLut[LutIndex, (OpCode >> 50) & 7];
|
||||||
|
|
||||||
for (int Ch = 0; Ch < 4; Ch++)
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
|
@ -227,6 +234,26 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
int RegInc = 0;
|
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++)
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
{
|
{
|
||||||
if (!IsChannelUsed(ChMask, Ch))
|
if (!IsChannelUsed(ChMask, Ch))
|
||||||
|
@ -236,20 +263,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch);
|
ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch);
|
||||||
|
|
||||||
ShaderIrOperGpr Dst = (RegInc >> 1) != 0
|
ShaderIrOperGpr Dst = GetDst();
|
||||||
? GetOperGpr28(OpCode)
|
|
||||||
: GetOperGpr0 (OpCode);
|
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsChannelUsed(int ChMask, int Ch)
|
private static bool IsChannelUsed(int ChMask, int Ch)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue