[GPU] Implemented I2F, SHR and LOP32I shader instructions

This commit is contained in:
gdkchan 2018-04-08 01:04:02 -03:00
parent 2000e904f1
commit e26555608a
8 changed files with 475 additions and 63 deletions

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

@ -0,0 +1,11 @@
namespace Ryujinx.Graphics.Gal.Shader
{
enum ShaderOper
{
CR,
RC,
RR,
Imm,
Immf
}
}