[GPU] Implemented I2F, SHR and LOP32I shader instructions
This commit is contained in:
parent
2000e904f1
commit
e26555608a
8 changed files with 475 additions and 63 deletions
|
@ -4,6 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
class GlslDecl
|
||||
{
|
||||
public const int VertexIdAttr = 0x2fc;
|
||||
|
||||
private const int AttrStartIndex = 8;
|
||||
private const int TexStartIndex = 8;
|
||||
|
||||
|
@ -130,6 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
case ShaderIrOperAbuf Abuf:
|
||||
{
|
||||
//This is a built-in input variable.
|
||||
if (Abuf.Offs == VertexIdAttr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int Index = Abuf.Offs >> 4;
|
||||
int Elem = (Abuf.Offs >> 2) & 3;
|
||||
|
||||
|
|
|
@ -12,6 +12,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private Dictionary<ShaderIrInst, GetInstExpr> InstsExpr;
|
||||
|
||||
private enum OperType
|
||||
{
|
||||
Bool,
|
||||
F32,
|
||||
I32
|
||||
}
|
||||
|
||||
private const string IdentationStr = " ";
|
||||
|
||||
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
||||
|
@ -24,6 +31,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
||||
{
|
||||
{ ShaderIrInst.And, GetAndExpr },
|
||||
{ ShaderIrInst.Asr, GetAsrExpr },
|
||||
{ ShaderIrInst.Band, GetBandExpr },
|
||||
{ ShaderIrInst.Bnot, GetBnotExpr },
|
||||
{ ShaderIrInst.Clt, GetCltExpr },
|
||||
|
@ -46,10 +55,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{ ShaderIrInst.Fsin, GetFsinExpr },
|
||||
{ ShaderIrInst.Ipa, GetIpaExpr },
|
||||
{ ShaderIrInst.Kil, GetKilExpr },
|
||||
{ ShaderIrInst.Lsr, GetLsrExpr },
|
||||
{ ShaderIrInst.Not, GetNotExpr },
|
||||
{ ShaderIrInst.Or, GetOrExpr },
|
||||
{ ShaderIrInst.Stof, GetStofExpr },
|
||||
{ ShaderIrInst.Utof, GetUtofExpr },
|
||||
{ ShaderIrInst.Texr, GetTexrExpr },
|
||||
{ ShaderIrInst.Texg, GetTexgExpr },
|
||||
{ ShaderIrInst.Texb, GetTexbExpr },
|
||||
{ ShaderIrInst.Texa, GetTexaExpr }
|
||||
{ ShaderIrInst.Texa, GetTexaExpr },
|
||||
{ ShaderIrInst.Xor, GetXorExpr },
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -63,7 +78,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
SB = new StringBuilder();
|
||||
|
||||
SB.AppendLine("#version 430");
|
||||
SB.AppendLine("#version 330 core");
|
||||
|
||||
PrintDeclTextures();
|
||||
PrintDeclUniforms();
|
||||
|
@ -207,17 +222,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (Node is ShaderIrCond Cond)
|
||||
{
|
||||
string SubScopeName = "if (" + GetInOperName(Cond.Pred, true) + ")";
|
||||
string SubScopeName = "if (" + GetSrcExpr(Cond.Pred, true) + ")";
|
||||
|
||||
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
|
||||
}
|
||||
else if (Node is ShaderIrAsg Asg && IsValidOutOper(Asg.Dst))
|
||||
{
|
||||
SB.AppendLine(Identation + GetOutOperName(Asg.Dst) + " = " + GetInOperName(Asg.Src, true) + ";");
|
||||
string Expr = GetSrcExpr(Asg.Src, true);
|
||||
|
||||
Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr);
|
||||
|
||||
SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";");
|
||||
}
|
||||
else if (Node is ShaderIrOp Op)
|
||||
{
|
||||
SB.AppendLine(Identation + GetInOperName(Op, true) + ";");
|
||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -242,7 +261,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return true;
|
||||
}
|
||||
|
||||
private string GetOutOperName(ShaderIrNode Node)
|
||||
private string GetDstOperName(ShaderIrNode Node)
|
||||
{
|
||||
if (Node is ShaderIrOperAbuf Abuf)
|
||||
{
|
||||
|
@ -260,7 +279,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
throw new ArgumentException(nameof(Node));
|
||||
}
|
||||
|
||||
private string GetInOperName(ShaderIrNode Node, bool Entry = false)
|
||||
private string GetSrcExpr(ShaderIrNode Node, bool Entry = false)
|
||||
{
|
||||
switch (Node)
|
||||
{
|
||||
|
@ -317,6 +336,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private string GetName(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, ShaderIrOperAbuf Abuf)
|
||||
{
|
||||
if (Abuf.Offs == GlslDecl.VertexIdAttr)
|
||||
{
|
||||
return "gl_VertexID";
|
||||
}
|
||||
|
||||
int Index = Abuf.Offs >> 4;
|
||||
int Elem = (Abuf.Offs >> 2) & 3;
|
||||
|
||||
|
@ -335,12 +359,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private string GetValue(ShaderIrOperImm Imm)
|
||||
{
|
||||
return Imm.Value.ToString(CultureInfo.InvariantCulture);
|
||||
//Only use hex is the value is too big and would likely be hard to read as int.
|
||||
if (Imm.Value > 0xfff ||
|
||||
Imm.Value < -0xfff)
|
||||
{
|
||||
return "0x" + Imm.Value.ToString("x8", CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Imm.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetValue(ShaderIrOperImmf Immf)
|
||||
{
|
||||
return Immf.Value.ToString(CultureInfo.InvariantCulture);
|
||||
return Immf.Value.ToString(CultureInfo.InvariantCulture) + "f";
|
||||
}
|
||||
|
||||
private string GetName(ShaderIrOperPred Pred)
|
||||
|
@ -373,6 +406,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return "xyzw".Substring(Elem, 1);
|
||||
}
|
||||
|
||||
private string GetAndExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&");
|
||||
|
||||
private string GetAsrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">>");
|
||||
|
||||
private string GetBandExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&&");
|
||||
|
||||
private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
|
||||
|
@ -408,31 +445,46 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin");
|
||||
|
||||
private string GetIpaExpr(ShaderIrOp Op) => GetInOperName(Op.OperandA);
|
||||
private string GetIpaExpr(ShaderIrOp Op) => GetSrcExpr(Op.OperandA);
|
||||
|
||||
private string GetKilExpr(ShaderIrOp Op) => "discard";
|
||||
|
||||
private string GetLsrExpr(ShaderIrOp Op)
|
||||
{
|
||||
return "(int)((uint)" + GetOperExpr(Op, Op.OperandA) + " >> " +
|
||||
GetOperExpr(Op, Op.OperandB) + ")";
|
||||
}
|
||||
|
||||
private string GetNotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "~");
|
||||
|
||||
private string GetOrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "|");
|
||||
|
||||
private string GetStofExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "(float)");
|
||||
private string GetUtofExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "(float)(uint)");
|
||||
|
||||
private string GetXorExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "^");
|
||||
|
||||
private string GetUnaryCall(ShaderIrOp Op, string FuncName)
|
||||
{
|
||||
return FuncName + "(" + GetInOperName(Op.OperandA) + ")";
|
||||
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")";
|
||||
}
|
||||
|
||||
private string GetUnaryExpr(ShaderIrOp Op, string Opr)
|
||||
{
|
||||
return Opr + GetInOperName(Op.OperandA);
|
||||
return Opr + GetOperExpr(Op, Op.OperandA);
|
||||
}
|
||||
|
||||
private string GetBinaryExpr(ShaderIrOp Op, string Opr)
|
||||
{
|
||||
return GetInOperName(Op.OperandA) + " " + Opr + " " +
|
||||
GetInOperName(Op.OperandB);
|
||||
return GetOperExpr(Op, Op.OperandA) + " " + Opr + " " +
|
||||
GetOperExpr(Op, Op.OperandB);
|
||||
}
|
||||
|
||||
private string GetTernaryExpr(ShaderIrOp Op, string Opr1, string Opr2)
|
||||
{
|
||||
return GetInOperName(Op.OperandA) + " " + Opr1 + " " +
|
||||
GetInOperName(Op.OperandB) + " " + Opr2 + " " +
|
||||
GetInOperName(Op.OperandC);
|
||||
return GetOperExpr(Op, Op.OperandA) + " " + Opr1 + " " +
|
||||
GetOperExpr(Op, Op.OperandB) + " " + Opr2 + " " +
|
||||
GetOperExpr(Op, Op.OperandC);
|
||||
}
|
||||
|
||||
private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
|
||||
|
@ -461,8 +513,102 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private string GetTexSamplerCoords(ShaderIrOp Op)
|
||||
{
|
||||
return "vec2(" + GetInOperName(Op.OperandA, Entry: true) + ", " +
|
||||
GetInOperName(Op.OperandB, Entry: true) + ")";
|
||||
return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
|
||||
GetOperExpr(Op, Op.OperandB) + ")";
|
||||
}
|
||||
|
||||
private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
|
||||
{
|
||||
return GetExprWithCast(Op, Oper, GetSrcExpr(Oper));
|
||||
}
|
||||
|
||||
private static string GetExprWithCast(ShaderIrNode Dst, ShaderIrNode Src, string Expr)
|
||||
{
|
||||
//Note: The "DstType" (of the cast) is the type that the operation
|
||||
//uses on the source operands, while the "SrcType" is the destination
|
||||
//type of the operand result (if it is a operation) or just the type
|
||||
//of the variable for registers/uniforms/attributes.
|
||||
OperType DstType = GetSrcNodeType(Dst);
|
||||
OperType SrcType = GetDstNodeType(Src);
|
||||
|
||||
if (DstType != SrcType)
|
||||
{
|
||||
//Check for invalid casts
|
||||
//(like bool to int/float and others).
|
||||
if (SrcType != OperType.F32 &&
|
||||
SrcType != OperType.I32)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
//For integer immediates being used as float,
|
||||
//it's better (for readability) to just return the float value.
|
||||
if (Src is ShaderIrOperImm Imm && DstType == OperType.F32)
|
||||
{
|
||||
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
|
||||
|
||||
return Value.ToString(CultureInfo.InvariantCulture) + "f";
|
||||
}
|
||||
|
||||
switch (DstType)
|
||||
{
|
||||
case OperType.F32: Expr = "intBitsToFloat(" + Expr + ")"; break;
|
||||
case OperType.I32: Expr = "floatBitsToInt(" + Expr + ")"; break;
|
||||
}
|
||||
}
|
||||
|
||||
return Expr;
|
||||
}
|
||||
|
||||
private static OperType GetDstNodeType(ShaderIrNode Node)
|
||||
{
|
||||
if (Node is ShaderIrOp Op)
|
||||
{
|
||||
switch (Op.Inst)
|
||||
{
|
||||
case ShaderIrInst.Stof: return OperType.F32;
|
||||
case ShaderIrInst.Utof: return OperType.F32;
|
||||
}
|
||||
}
|
||||
|
||||
return GetSrcNodeType(Node);
|
||||
}
|
||||
|
||||
private static OperType GetSrcNodeType(ShaderIrNode Node)
|
||||
{
|
||||
switch (Node)
|
||||
{
|
||||
case ShaderIrOperAbuf Abuf:
|
||||
return Abuf.Offs == GlslDecl.VertexIdAttr
|
||||
? OperType.I32
|
||||
: OperType.F32;
|
||||
|
||||
case ShaderIrOperCbuf Cbuf: return OperType.F32;
|
||||
case ShaderIrOperGpr Gpr: return OperType.F32;
|
||||
case ShaderIrOperImm Imm: return OperType.I32;
|
||||
case ShaderIrOperImmf Immf: return OperType.F32;
|
||||
case ShaderIrOperPred Pred: return OperType.Bool;
|
||||
|
||||
case ShaderIrOp Op:
|
||||
if (Op.Inst > ShaderIrInst.B_Start &&
|
||||
Op.Inst < ShaderIrInst.B_End)
|
||||
{
|
||||
return OperType.Bool;
|
||||
}
|
||||
else if (Op.Inst > ShaderIrInst.F_Start &&
|
||||
Op.Inst < ShaderIrInst.F_End)
|
||||
{
|
||||
return OperType.F32;
|
||||
}
|
||||
else if (Op.Inst > ShaderIrInst.I_Start &&
|
||||
Op.Inst < ShaderIrInst.I_End)
|
||||
{
|
||||
return OperType.I32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Node));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,27 +6,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
private enum ShaderOper
|
||||
{
|
||||
CR,
|
||||
RR,
|
||||
RC,
|
||||
Imm
|
||||
}
|
||||
|
||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd);
|
||||
EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd);
|
||||
}
|
||||
|
||||
public static void Fadd_I(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fadd);
|
||||
EmitAluBinaryF(Block, OpCode, ShaderOper.Immf, ShaderIrInst.Fadd);
|
||||
}
|
||||
|
||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fadd);
|
||||
EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fadd);
|
||||
}
|
||||
|
||||
public static void Ffma_CR(ShaderIrBlock Block, long OpCode)
|
||||
|
@ -36,7 +28,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Ffma_I(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluFfma(Block, OpCode, ShaderOper.Imm);
|
||||
EmitAluFfma(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Ffma_RC(ShaderIrBlock Block, long OpCode)
|
||||
|
@ -51,17 +43,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Fmul_C(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fmul);
|
||||
EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fmul);
|
||||
}
|
||||
|
||||
public static void Fmul_I(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fmul);
|
||||
EmitAluBinaryF(Block, OpCode, ShaderOper.Immf, ShaderIrInst.Fmul);
|
||||
}
|
||||
|
||||
public static void Fmul_R(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fmul);
|
||||
EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fmul);
|
||||
}
|
||||
|
||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode)
|
||||
|
@ -71,7 +63,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Fsetp_I(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitFsetp(Block, OpCode, ShaderOper.Imm);
|
||||
EmitFsetp(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fsetp_R(ShaderIrBlock Block, long OpCode)
|
||||
|
@ -89,6 +81,40 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||
}
|
||||
|
||||
public static void Lop32i(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
int SubOp = (int)(OpCode >> 53) & 3;
|
||||
|
||||
bool Ia = ((OpCode >> 55) & 1) != 0;
|
||||
bool Ib = ((OpCode >> 56) & 1) != 0;
|
||||
|
||||
ShaderIrInst Inst = 0;
|
||||
|
||||
switch (SubOp)
|
||||
{
|
||||
case 0: Inst = ShaderIrInst.And; break;
|
||||
case 1: Inst = ShaderIrInst.Or; break;
|
||||
case 2: Inst = ShaderIrInst.Xor; break;
|
||||
}
|
||||
|
||||
ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), Ia);
|
||||
|
||||
//SubOp == 3 is pass, used by the not instruction
|
||||
//which just moves the inverted register value.
|
||||
if (SubOp < 3)
|
||||
{
|
||||
ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), Ib);
|
||||
|
||||
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB);
|
||||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||
}
|
||||
else
|
||||
{
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Mufu(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
int SubOp = (int)(OpCode >> 20) & 7;
|
||||
|
@ -117,11 +143,55 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||
}
|
||||
|
||||
public static void Shr_C(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
||||
}
|
||||
|
||||
public static void Shr_I(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
|
||||
}
|
||||
|
||||
public static void Shr_R(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
|
||||
}
|
||||
|
||||
private static ShaderIrInst GetShrInst(long OpCode)
|
||||
{
|
||||
bool Signed = ((OpCode >> 48) & 1) != 0;
|
||||
|
||||
return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
}
|
||||
|
||||
private static void EmitAluBinary(
|
||||
ShaderIrBlock Block,
|
||||
long OpCode,
|
||||
ShaderOper Oper,
|
||||
ShaderIrInst Inst)
|
||||
{
|
||||
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
||||
|
||||
switch (Oper)
|
||||
{
|
||||
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||
case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
|
||||
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||
|
||||
default: throw new ArgumentException(nameof(Oper));
|
||||
}
|
||||
|
||||
ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
|
||||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||
}
|
||||
|
||||
private static void EmitAluBinaryF(
|
||||
ShaderIrBlock Block,
|
||||
long OpCode,
|
||||
ShaderOper Oper,
|
||||
ShaderIrInst Inst)
|
||||
{
|
||||
bool Nb = ((OpCode >> 45) & 1) != 0;
|
||||
bool Aa = ((OpCode >> 46) & 1) != 0;
|
||||
|
@ -138,9 +208,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
switch (Oper)
|
||||
{
|
||||
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||
case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break;
|
||||
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||
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));
|
||||
}
|
||||
|
@ -163,10 +233,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
switch (Oper)
|
||||
{
|
||||
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||
case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break;
|
||||
case ShaderOper.RC: OperB = GetOperGpr39 (OpCode); break;
|
||||
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||
case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break;
|
||||
case ShaderOper.RC: OperB = GetOperGpr39 (OpCode); break;
|
||||
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||
|
||||
default: throw new ArgumentException(nameof(Oper));
|
||||
}
|
||||
|
@ -198,9 +268,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
switch (Oper)
|
||||
{
|
||||
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||
case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break;
|
||||
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||
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));
|
||||
}
|
||||
|
@ -241,20 +311,5 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||
}
|
||||
|
||||
private static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||
{
|
||||
return GetAluNeg(GetAluAbs(Node, Abs), Neg);
|
||||
}
|
||||
|
||||
private static ShaderIrNode GetAluAbs(ShaderIrNode Node, bool Abs)
|
||||
{
|
||||
return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node;
|
||||
}
|
||||
|
||||
private static ShaderIrNode GetAluNeg(ShaderIrNode Node, bool Neg)
|
||||
{
|
||||
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,6 +60,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff);
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetOperImm19_20(long OpCode)
|
||||
{
|
||||
uint Value = (uint)(OpCode >> 20) & 0x7ffff;
|
||||
|
||||
bool Neg = ((OpCode >> 56) & 1) != 0;
|
||||
|
||||
if (Neg)
|
||||
{
|
||||
Value |= 0x80000000;
|
||||
}
|
||||
|
||||
return new ShaderIrOperImm((int)Value);
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetOperImmf19_20(long OpCode)
|
||||
{
|
||||
uint Imm = (uint)(OpCode >> 20) & 0x7ffff;
|
||||
|
@ -83,6 +97,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
||||
}
|
||||
|
||||
public static ShaderIrOperImm GetOperImm32_20(long OpCode)
|
||||
{
|
||||
return new ShaderIrOperImm((int)(OpCode >> 20));
|
||||
}
|
||||
|
||||
public static ShaderIrOperPred GetOperPred3(long OpCode)
|
||||
{
|
||||
return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
|
||||
|
@ -168,5 +187,25 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
return new ShaderIrOperPred(Pred);
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||
{
|
||||
return GetAluNeg(GetAluAbs(Node, Abs), Neg);
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetAluAbs(ShaderIrNode Node, bool Abs)
|
||||
{
|
||||
return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node;
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetAluNeg(ShaderIrNode Node, bool Neg)
|
||||
{
|
||||
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetAluNot(ShaderIrNode Node, bool Not)
|
||||
{
|
||||
return Not ? new ShaderIrOp(ShaderIrInst.Not, Node) : Node;
|
||||
}
|
||||
}
|
||||
}
|
128
Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
Normal file
128
Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
|
||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
private enum IntType
|
||||
{
|
||||
U8 = 0,
|
||||
U16 = 1,
|
||||
U32 = 2,
|
||||
U64 = 3,
|
||||
S8 = 4,
|
||||
S16 = 5,
|
||||
S32 = 6,
|
||||
S64 = 7
|
||||
}
|
||||
|
||||
private enum FloatType
|
||||
{
|
||||
F16 = 1,
|
||||
F32 = 2,
|
||||
F64 = 3
|
||||
}
|
||||
|
||||
public static void I2f_C(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void I2f_I(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void I2f_R(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
private static void EmitI2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||
{
|
||||
IntType Type = GetIntType(OpCode);
|
||||
|
||||
if (Type == IntType.U64 ||
|
||||
Type == IntType.S64)
|
||||
{
|
||||
//TODO: 64-bits support.
|
||||
//Note: GLSL doesn't support 64-bits integers.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int Sel = (int)(OpCode >> 41) & 3;
|
||||
|
||||
bool Na = ((OpCode >> 45) & 1) != 0;
|
||||
bool Aa = ((OpCode >> 49) & 1) != 0;
|
||||
|
||||
ShaderIrNode OperA;
|
||||
|
||||
switch (Oper)
|
||||
{
|
||||
case ShaderOper.CR: OperA = GetOperCbuf34 (OpCode); break;
|
||||
case ShaderOper.Imm: OperA = GetOperImm19_20(OpCode); break;
|
||||
case ShaderOper.RR: OperA = GetOperGpr20 (OpCode); break;
|
||||
|
||||
default: throw new ArgumentException(nameof(Oper));
|
||||
}
|
||||
|
||||
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
||||
|
||||
bool Signed = Type >= IntType.S8;
|
||||
|
||||
int Shift = Sel * 8;
|
||||
|
||||
int Size = 8 << ((int)Type & 3);
|
||||
|
||||
ulong Mask = ulong.MaxValue >> (64 - Size);
|
||||
|
||||
int Mask32 = (int)Mask;
|
||||
|
||||
if (Shift != 0)
|
||||
{
|
||||
OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift));
|
||||
}
|
||||
|
||||
if (Mask != uint.MaxValue)
|
||||
{
|
||||
OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm(Mask32));
|
||||
}
|
||||
|
||||
ShaderIrInst Inst = Signed
|
||||
? ShaderIrInst.Stof
|
||||
: ShaderIrInst.Utof;
|
||||
|
||||
ShaderIrNode Op = new ShaderIrOp(Inst, OperA);
|
||||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||
}
|
||||
|
||||
public static void Mov32i(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
|
||||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
||||
}
|
||||
|
||||
private static IntType GetIntType(long OpCode)
|
||||
{
|
||||
bool Signed = ((OpCode >> 13) & 1) != 0;
|
||||
|
||||
IntType Type = (IntType)((OpCode >> 10) & 3);
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
Type += (int)IntType.S8;
|
||||
}
|
||||
|
||||
return Type;
|
||||
}
|
||||
|
||||
private static FloatType GetFloatType(long OpCode)
|
||||
{
|
||||
return (FloatType)((OpCode >> 8) & 3);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
enum ShaderIrInst
|
||||
{
|
||||
B_Start,
|
||||
Band,
|
||||
Bnot,
|
||||
Bor,
|
||||
|
@ -20,7 +21,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Cgtu,
|
||||
Cneu,
|
||||
Cgeu,
|
||||
Exit,
|
||||
B_End,
|
||||
|
||||
F_Start,
|
||||
Fabs,
|
||||
Fadd,
|
||||
Fcos,
|
||||
|
@ -33,10 +36,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Frsq,
|
||||
Fsin,
|
||||
Ipa,
|
||||
Kil,
|
||||
Texr,
|
||||
Texg,
|
||||
Texb,
|
||||
Texa
|
||||
Texa,
|
||||
F_End,
|
||||
|
||||
I_Start,
|
||||
And,
|
||||
Asr,
|
||||
Lsr,
|
||||
Not,
|
||||
Or,
|
||||
Stof,
|
||||
Utof,
|
||||
Xor,
|
||||
I_End,
|
||||
|
||||
Exit,
|
||||
Kil
|
||||
}
|
||||
}
|
|
@ -27,10 +27,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Set("010010111011xx", ShaderDecode.Fsetp_C);
|
||||
Set("0011011x1011xx", ShaderDecode.Fsetp_I);
|
||||
Set("010110111011xx", ShaderDecode.Fsetp_R);
|
||||
Set("0100110010111x", ShaderDecode.I2f_C);
|
||||
Set("0011100x10111x", ShaderDecode.I2f_I);
|
||||
Set("0101110010111x", ShaderDecode.I2f_R);
|
||||
Set("11100000xxxxxx", ShaderDecode.Ipa);
|
||||
Set("111000110011xx", ShaderDecode.Kil);
|
||||
Set("1110111111011x", ShaderDecode.Ld_A);
|
||||
Set("000001xxxxxxxx", ShaderDecode.Lop32i);
|
||||
Set("000000010000xx", ShaderDecode.Mov32i);
|
||||
Set("0101000010000x", ShaderDecode.Mufu);
|
||||
Set("0100110000101x", ShaderDecode.Shr_C);
|
||||
Set("0011100x00101x", ShaderDecode.Shr_I);
|
||||
Set("0101110000101x", ShaderDecode.Shr_R);
|
||||
Set("1110111111110x", ShaderDecode.St_A);
|
||||
Set("1101100xxxxxxx", ShaderDecode.Texs);
|
||||
#endregion
|
||||
|
|
11
Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
Normal file
11
Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
enum ShaderOper
|
||||
{
|
||||
CR,
|
||||
RC,
|
||||
RR,
|
||||
Imm,
|
||||
Immf
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue