Started to add support for fragment shaders aswell
This commit is contained in:
parent
b0641ecd16
commit
e5ada9cb6d
24 changed files with 908 additions and 230 deletions
|
@ -6,10 +6,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class GlslDecompiler
|
class GlslDecompiler
|
||||||
{
|
{
|
||||||
private delegate string GetInstExpr(ShaderIrOperOp Op);
|
private delegate string GetInstExpr(ShaderIrOp Op);
|
||||||
|
|
||||||
private Dictionary<ShaderIrInst, GetInstExpr> InstsExpr;
|
private Dictionary<ShaderIrInst, GetInstExpr> InstsExpr;
|
||||||
|
|
||||||
|
private const string IdentationStr = " ";
|
||||||
|
|
||||||
|
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
||||||
|
|
||||||
private class Attrib
|
private class Attrib
|
||||||
{
|
{
|
||||||
public string Name;
|
public string Name;
|
||||||
|
@ -20,9 +24,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
this.Name = Name;
|
this.Name = Name;
|
||||||
this.Elems = Elems;
|
this.Elems = Elems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
|
||||||
|
|
||||||
private SortedDictionary<int, Attrib> InputAttributes;
|
private SortedDictionary<int, Attrib> InputAttributes;
|
||||||
private SortedDictionary<int, Attrib> OutputAttributes;
|
private SortedDictionary<int, Attrib> OutputAttributes;
|
||||||
|
@ -30,6 +32,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
private HashSet<int> UsedCbufs;
|
private HashSet<int> UsedCbufs;
|
||||||
|
|
||||||
private const int AttrStartIndex = 8;
|
private const int AttrStartIndex = 8;
|
||||||
|
private const int TexStartIndex = 8;
|
||||||
|
|
||||||
private const string InputAttrPrefix = "in_attr";
|
private const string InputAttrPrefix = "in_attr";
|
||||||
private const string OutputAttrPrefix = "out_attr";
|
private const string OutputAttrPrefix = "out_attr";
|
||||||
|
@ -37,11 +40,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
private const string CbufBuffPrefix = "c";
|
private const string CbufBuffPrefix = "c";
|
||||||
private const string CbufDataName = "buf";
|
private const string CbufDataName = "buf";
|
||||||
|
|
||||||
private const string GprName = "gpr";
|
private const string GprName = "gpr";
|
||||||
|
private const string PredName = "pred";
|
||||||
private const string IdentationStr = "\t";
|
private const string SampName = "samp";
|
||||||
|
|
||||||
private int GprsCount;
|
private int GprsCount;
|
||||||
|
private int PredsCount;
|
||||||
|
private int SampsCount;
|
||||||
|
|
||||||
private StringBuilder BodySB;
|
private StringBuilder BodySB;
|
||||||
|
|
||||||
|
@ -49,15 +54,35 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
||||||
{
|
{
|
||||||
|
{ ShaderIrInst.Band, GetBandExpr },
|
||||||
|
{ ShaderIrInst.Bnot, GetBnotExpr },
|
||||||
|
{ ShaderIrInst.Clt, GetCltExpr },
|
||||||
|
{ ShaderIrInst.Ceq, GetCeqExpr },
|
||||||
|
{ ShaderIrInst.Cle, GetCleExpr },
|
||||||
|
{ ShaderIrInst.Cgt, GetCgtExpr },
|
||||||
|
{ ShaderIrInst.Cne, GetCneExpr },
|
||||||
|
{ ShaderIrInst.Cge, GetCgeExpr },
|
||||||
{ ShaderIrInst.Fabs, GetFabsExpr },
|
{ ShaderIrInst.Fabs, GetFabsExpr },
|
||||||
{ ShaderIrInst.Fadd, GetFaddExpr },
|
{ ShaderIrInst.Fadd, GetFaddExpr },
|
||||||
|
{ ShaderIrInst.Fcos, GetFcosExpr },
|
||||||
|
{ ShaderIrInst.Fex2, GetFex2Expr },
|
||||||
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
||||||
|
{ ShaderIrInst.Flg2, GetFlg2Expr },
|
||||||
{ ShaderIrInst.Fmul, GetFmulExpr },
|
{ ShaderIrInst.Fmul, GetFmulExpr },
|
||||||
{ ShaderIrInst.Fneg, GetFnegExpr }
|
{ ShaderIrInst.Fneg, GetFnegExpr },
|
||||||
|
{ ShaderIrInst.Frcp, GetFrcpExpr },
|
||||||
|
{ ShaderIrInst.Frsq, GetFrsqExpr },
|
||||||
|
{ ShaderIrInst.Fsin, GetFsinExpr },
|
||||||
|
{ ShaderIrInst.Ipa, GetIpaExpr },
|
||||||
|
{ ShaderIrInst.Kil, GetKilExpr },
|
||||||
|
{ ShaderIrInst.Texr, GetTexrExpr },
|
||||||
|
{ ShaderIrInst.Texg, GetTexgExpr },
|
||||||
|
{ ShaderIrInst.Texb, GetTexbExpr },
|
||||||
|
{ ShaderIrInst.Texa, GetTexaExpr }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Decompile(int[] Code)
|
public string Decompile(int[] Code, ShaderType Type)
|
||||||
{
|
{
|
||||||
InputAttributes = new SortedDictionary<int, Attrib>();
|
InputAttributes = new SortedDictionary<int, Attrib>();
|
||||||
OutputAttributes = new SortedDictionary<int, Attrib>();
|
OutputAttributes = new SortedDictionary<int, Attrib>();
|
||||||
|
@ -67,13 +92,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
BodySB = new StringBuilder();
|
BodySB = new StringBuilder();
|
||||||
|
|
||||||
//FIXME: Only valid for vertex shaders.
|
//FIXME: Only valid for vertex shaders.
|
||||||
OutputAttributes.Add(7, new Attrib("gl_Position", 4));
|
if (Type == ShaderType.Fragment)
|
||||||
|
{
|
||||||
|
OutputAttributes.Add(7, new Attrib("FragColor", 4));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OutputAttributes.Add(7, new Attrib("gl_Position", 4));
|
||||||
|
}
|
||||||
|
|
||||||
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0);
|
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0, Type);
|
||||||
|
|
||||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
ShaderIrNode[] Nodes = Block.GetNodes();
|
||||||
|
|
||||||
PrintBlockScope(Nodes, "void main()", 1);
|
PrintBlockScope("void main()", 1, Nodes);
|
||||||
|
|
||||||
StringBuilder SB = new StringBuilder();
|
StringBuilder SB = new StringBuilder();
|
||||||
|
|
||||||
|
@ -83,12 +115,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
PrintDeclInAttributes(SB);
|
PrintDeclInAttributes(SB);
|
||||||
PrintDeclOutAttributes(SB);
|
PrintDeclOutAttributes(SB);
|
||||||
|
|
||||||
if (GprsCount > 0)
|
if (Type == ShaderType.Fragment)
|
||||||
{
|
{
|
||||||
SB.AppendLine($"float {GprName}[{GprsCount}];");
|
SB.AppendLine($"out vec4 {OutputAttributes[7].Name};");
|
||||||
SB.AppendLine(string.Empty);
|
SB.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintDeclSamplers(SB);
|
||||||
|
PrintDeclGprs(SB);
|
||||||
|
PrintDeclPreds(SB);
|
||||||
|
|
||||||
SB.Append(BodySB.ToString());
|
SB.Append(BodySB.ToString());
|
||||||
|
|
||||||
BodySB.Clear();
|
BodySB.Clear();
|
||||||
|
@ -103,12 +139,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
SB.AppendLine($"layout(std430, binding = {Cbuf}) buffer {CbufBuffPrefix}{Cbuf} {{");
|
SB.AppendLine($"layout(std430, binding = {Cbuf}) buffer {CbufBuffPrefix}{Cbuf} {{");
|
||||||
SB.AppendLine($"{IdentationStr}float {CbufDataName}[];");
|
SB.AppendLine($"{IdentationStr}float {CbufDataName}[];");
|
||||||
SB.AppendLine("};");
|
SB.AppendLine("};");
|
||||||
SB.AppendLine(string.Empty);
|
SB.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclInAttributes(StringBuilder SB)
|
private void PrintDeclInAttributes(StringBuilder SB)
|
||||||
{
|
{
|
||||||
|
bool PrintNl = false;
|
||||||
|
|
||||||
foreach (KeyValuePair<int, Attrib> KV in InputAttributes)
|
foreach (KeyValuePair<int, Attrib> KV in InputAttributes)
|
||||||
{
|
{
|
||||||
int Index = KV.Key - AttrStartIndex;
|
int Index = KV.Key - AttrStartIndex;
|
||||||
|
@ -118,14 +156,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
string Type = ElemTypes[KV.Value.Elems];
|
string Type = ElemTypes[KV.Value.Elems];
|
||||||
|
|
||||||
SB.AppendLine($"layout(location = {Index}) in {Type} {KV.Value.Name};");
|
SB.AppendLine($"layout(location = {Index}) in {Type} {KV.Value.Name};");
|
||||||
|
|
||||||
|
PrintNl = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SB.AppendLine(string.Empty);
|
if (PrintNl)
|
||||||
|
{
|
||||||
|
SB.AppendLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclOutAttributes(StringBuilder SB)
|
private void PrintDeclOutAttributes(StringBuilder SB)
|
||||||
{
|
{
|
||||||
|
bool PrintNl = false;
|
||||||
|
|
||||||
foreach (KeyValuePair<int, Attrib> KV in OutputAttributes)
|
foreach (KeyValuePair<int, Attrib> KV in OutputAttributes)
|
||||||
{
|
{
|
||||||
int Index = KV.Key - AttrStartIndex;
|
int Index = KV.Key - AttrStartIndex;
|
||||||
|
@ -135,13 +180,45 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
string Type = ElemTypes[KV.Value.Elems];
|
string Type = ElemTypes[KV.Value.Elems];
|
||||||
|
|
||||||
SB.AppendLine($"layout(location = {Index}) out {Type} {KV.Value.Name};");
|
SB.AppendLine($"layout(location = {Index}) out {Type} {KV.Value.Name};");
|
||||||
|
|
||||||
|
PrintNl = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SB.AppendLine(string.Empty);
|
if (PrintNl)
|
||||||
|
{
|
||||||
|
SB.AppendLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintBlockScope(ShaderIrNode[] Nodes, string ScopeName, int IdentationLevel)
|
private void PrintDeclSamplers(StringBuilder SB)
|
||||||
|
{
|
||||||
|
if (SampsCount > 0)
|
||||||
|
{
|
||||||
|
SB.AppendLine($"uniform sampler2D {SampName}[{SampsCount}];");
|
||||||
|
SB.AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclGprs(StringBuilder SB)
|
||||||
|
{
|
||||||
|
if (GprsCount > 0)
|
||||||
|
{
|
||||||
|
SB.AppendLine($"float {GprName}[{GprsCount}];");
|
||||||
|
SB.AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclPreds(StringBuilder SB)
|
||||||
|
{
|
||||||
|
if (PredsCount > 0)
|
||||||
|
{
|
||||||
|
SB.AppendLine($"bool {PredName}[{PredsCount}];");
|
||||||
|
SB.AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintBlockScope(string ScopeName, int IdentationLevel, params ShaderIrNode[] Nodes)
|
||||||
{
|
{
|
||||||
string Identation = string.Empty;
|
string Identation = string.Empty;
|
||||||
|
|
||||||
|
@ -164,43 +241,80 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Identation += IdentationStr;
|
Identation += IdentationStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Nodes)
|
for (int Index = 0; Index < Nodes.Length; Index++)
|
||||||
{
|
{
|
||||||
if (Node.Dst is ShaderIrOperReg Reg && Reg.GprIndex == ShaderIrOperReg.ZRIndex)
|
ShaderIrNode Node = Nodes[Index];
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BodySB.AppendLine(Identation +
|
if (Node is ShaderIrCond Cond)
|
||||||
$"{GetOOperName(Node.Dst)} = " +
|
{
|
||||||
$"{GetIOperName(Node.Src, true)};");
|
string SubScopeName = $"if ({GetInOperName(Cond.Pred, true)})";
|
||||||
|
|
||||||
|
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrAsg Asg)
|
||||||
|
{
|
||||||
|
if (IsValidOutOper(Asg.Dst))
|
||||||
|
{
|
||||||
|
BodySB.AppendLine(Identation +
|
||||||
|
$"{GetOutOperName(Asg.Dst)} = " +
|
||||||
|
$"{GetInOperName (Asg.Src, true)};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
BodySB.AppendLine($"{Identation}{GetInOperName(Op, true)};");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BodySB.AppendLine(LastLine);
|
BodySB.AppendLine(LastLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetOOperName(ShaderIrOper Oper)
|
private bool IsValidOutOper(ShaderIrNode Node)
|
||||||
{
|
{
|
||||||
if (Oper is ShaderIrOperAbuf Abuf)
|
if (Node is ShaderIrOperGpr Gpr && Gpr.Index == ShaderIrOperGpr.ZRIndex)
|
||||||
{
|
{
|
||||||
return GetOAbufName(Abuf);
|
return false;
|
||||||
}
|
}
|
||||||
else if (Oper is ShaderIrOperReg Reg)
|
else if (Node is ShaderIrOperPred Pred && Pred.Index == ShaderIrOperPred.UnusedIndex)
|
||||||
{
|
{
|
||||||
return GetRegName(Reg);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Oper));
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetIOperName(ShaderIrOper Oper, bool Entry = false)
|
private string GetOutOperName(ShaderIrNode Node)
|
||||||
{
|
{
|
||||||
switch (Oper)
|
if (Node is ShaderIrOperAbuf Abuf)
|
||||||
{
|
{
|
||||||
case ShaderIrOperAbuf Abuf: return GetIAbufName(Abuf);
|
return GetOutAbufName(Abuf);
|
||||||
case ShaderIrOperCbuf Cbuf: return GetCbufName(Cbuf);
|
}
|
||||||
case ShaderIrOperReg Reg: return GetRegName(Reg);
|
else if (Node is ShaderIrOperGpr Gpr)
|
||||||
case ShaderIrOperOp Op:
|
{
|
||||||
|
return GetName(Gpr);
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOperPred Pred)
|
||||||
|
{
|
||||||
|
return GetName(Pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(Node));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetInOperName(ShaderIrNode Node, bool Entry = false)
|
||||||
|
{
|
||||||
|
switch (Node)
|
||||||
|
{
|
||||||
|
case ShaderIrOperAbuf Abuf: return GetName(Abuf);
|
||||||
|
case ShaderIrOperCbuf Cbuf: return GetName(Cbuf);
|
||||||
|
case ShaderIrOperGpr Gpr: return GetName(Gpr);
|
||||||
|
case ShaderIrOperPred Pred: return GetName(Pred);
|
||||||
|
|
||||||
|
case ShaderIrOp Op:
|
||||||
string Expr;
|
string Expr;
|
||||||
|
|
||||||
if (InstsExpr.TryGetValue(Op.Inst, out GetInstExpr GetExpr))
|
if (InstsExpr.TryGetValue(Op.Inst, out GetInstExpr GetExpr))
|
||||||
|
@ -219,17 +333,29 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
return Expr;
|
return Expr;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsUnary(ShaderIrInst Inst)
|
private bool IsUnary(ShaderIrInst Inst)
|
||||||
{
|
{
|
||||||
return Inst == ShaderIrInst.Fabs ||
|
return Inst == ShaderIrInst.Bnot ||
|
||||||
Inst == ShaderIrInst.Fneg;
|
Inst == ShaderIrInst.Fabs ||
|
||||||
|
Inst == ShaderIrInst.Fcos ||
|
||||||
|
Inst == ShaderIrInst.Fex2 ||
|
||||||
|
Inst == ShaderIrInst.Flg2 ||
|
||||||
|
Inst == ShaderIrInst.Fneg ||
|
||||||
|
Inst == ShaderIrInst.Frcp ||
|
||||||
|
Inst == ShaderIrInst.Frsq ||
|
||||||
|
Inst == ShaderIrInst.Fsin ||
|
||||||
|
Inst == ShaderIrInst.Ipa ||
|
||||||
|
Inst == ShaderIrInst.Texr ||
|
||||||
|
Inst == ShaderIrInst.Texg ||
|
||||||
|
Inst == ShaderIrInst.Texb ||
|
||||||
|
Inst == ShaderIrInst.Texa;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetOAbufName(ShaderIrOperAbuf Abuf)
|
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
||||||
{
|
{
|
||||||
int AttrIndex = Abuf.Offs >> 4;
|
int AttrIndex = Abuf.Offs >> 4;
|
||||||
|
|
||||||
|
@ -250,7 +376,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return $"{Attr.Name}.{GetAttrSwizzle(Elem)}";
|
return $"{Attr.Name}.{GetAttrSwizzle(Elem)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetIAbufName(ShaderIrOperAbuf Abuf)
|
private string GetName(ShaderIrOperAbuf Abuf, bool Swizzle = true)
|
||||||
{
|
{
|
||||||
int AttrIndex = Abuf.Offs >> 4;
|
int AttrIndex = Abuf.Offs >> 4;
|
||||||
|
|
||||||
|
@ -268,63 +394,224 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Attr.Elems = Elem;
|
Attr.Elems = Elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{Attr.Name}.{GetAttrSwizzle(Elem)}";
|
return Attr.Name + (Swizzle ? $".{GetAttrSwizzle(Elem)}" : string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetAttrSwizzle(int Elem)
|
private string GetName(ShaderIrOperCbuf Cbuf)
|
||||||
{
|
|
||||||
return "xyzw".Substring(Elem, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetCbufName(ShaderIrOperCbuf Cbuf)
|
|
||||||
{
|
{
|
||||||
UsedCbufs.Add(Cbuf.Index);
|
UsedCbufs.Add(Cbuf.Index);
|
||||||
|
|
||||||
return $"{CbufBuffPrefix}{Cbuf.Index}.{CbufDataName}[{Cbuf.Offs}]";
|
return $"{CbufBuffPrefix}{Cbuf.Index}.{CbufDataName}[{Cbuf.Offs}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetRegName(ShaderIrOperReg Reg)
|
private string GetName(ShaderIrOperGpr Gpr)
|
||||||
{
|
{
|
||||||
if (GprsCount < Reg.GprIndex + 1)
|
if (GprsCount < Gpr.Index + 1)
|
||||||
{
|
{
|
||||||
GprsCount = Reg.GprIndex + 1;
|
GprsCount = Gpr.Index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetRegName(Reg.GprIndex);
|
return GetRegName(Gpr.Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetName(ShaderIrOperPred Pred)
|
||||||
|
{
|
||||||
|
if (PredsCount < Pred.Index + 1)
|
||||||
|
{
|
||||||
|
PredsCount = Pred.Index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetPredName(Pred.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetRegName(int GprIndex)
|
private string GetRegName(int GprIndex)
|
||||||
{
|
{
|
||||||
return GprIndex == ShaderIrOperReg.ZRIndex ? "0" : $"{GprName}[{GprIndex}]";
|
return GprIndex == ShaderIrOperGpr.ZRIndex ? "0" : $"{GprName}[{GprIndex}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFabsExpr(ShaderIrOperOp Op)
|
private string GetPredName(int PredIndex)
|
||||||
{
|
{
|
||||||
return $"abs({GetIOperName(Op.OperandA)})";
|
return PredIndex == ShaderIrOperPred.UnusedIndex ? "true" : $"{PredName}[{PredIndex}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFaddExpr(ShaderIrOperOp Op)
|
private string GetBandExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
return $"{GetIOperName(Op.OperandA)} + " +
|
return $"{GetInOperName(Op.OperandA)} && " +
|
||||||
$"{GetIOperName(Op.OperandB)}";
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFfmaExpr(ShaderIrOperOp Op)
|
private string GetBnotExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
return $"{GetIOperName(Op.OperandA)} * " +
|
return $"!{GetInOperName(Op.OperandA)}";
|
||||||
$"{GetIOperName(Op.OperandB)} + " +
|
|
||||||
$"{GetIOperName(Op.OperandC)}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFmulExpr(ShaderIrOperOp Op)
|
private string GetCltExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
return $"{GetIOperName(Op.OperandA)} * " +
|
return $"{GetInOperName(Op.OperandA)} < " +
|
||||||
$"{GetIOperName(Op.OperandB)}";
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFnegExpr(ShaderIrOperOp Op)
|
private string GetCeqExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
return $"-{GetIOperName(Op.OperandA)}";
|
return $"{GetInOperName(Op.OperandA)} == " +
|
||||||
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCleExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetInOperName(Op.OperandA)} <= " +
|
||||||
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCgtExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetInOperName(Op.OperandA)} > " +
|
||||||
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCneExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetInOperName(Op.OperandA)} != " +
|
||||||
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCgeExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetInOperName(Op.OperandA)} >= " +
|
||||||
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFabsExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"abs({GetInOperName(Op.OperandA)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFaddExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetInOperName(Op.OperandA)} + " +
|
||||||
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFcosExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"cos({GetInOperName(Op.OperandA)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFex2Expr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"exp2({GetInOperName(Op.OperandA)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFfmaExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetInOperName(Op.OperandA)} * " +
|
||||||
|
$"{GetInOperName(Op.OperandB)} + " +
|
||||||
|
$"{GetInOperName(Op.OperandC)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFlg2Expr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"log2({GetInOperName(Op.OperandA)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFmulExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetInOperName(Op.OperandA)} * " +
|
||||||
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFnegExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"-{GetInOperName(Op.OperandA)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFrcpExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"1 / {GetInOperName(Op.OperandA)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFrsqExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"inversesqrt({GetInOperName(Op.OperandA)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFsinExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return $"sin({GetInOperName(Op.OperandA)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetIpaExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return GetInOperName(Op.OperandA);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetKilExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return "discard";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
|
||||||
|
private string GetTexgExpr(ShaderIrOp Op) => GetTexExpr(Op, 'g');
|
||||||
|
private string GetTexbExpr(ShaderIrOp Op) => GetTexExpr(Op, 'b');
|
||||||
|
private string GetTexaExpr(ShaderIrOp Op) => GetTexExpr(Op, 'a');
|
||||||
|
|
||||||
|
private string GetTexExpr(ShaderIrOp Op, char Ch)
|
||||||
|
{
|
||||||
|
return $"texture({GetTexSamplerName(Op)}, {GetTexSamplerCoords(Op)}).{Ch}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTexSamplerName(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
|
||||||
|
|
||||||
|
int Handle = Node.Imm - TexStartIndex;
|
||||||
|
|
||||||
|
if (SampsCount < Handle + 1)
|
||||||
|
{
|
||||||
|
SampsCount = Handle + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{SampName}[{Handle}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTexSamplerCoords(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
if (GetInnerNode(Op.OperandA) is ShaderIrOperAbuf AAbuf &&
|
||||||
|
GetInnerNode(Op.OperandB) is ShaderIrOperAbuf BAbuf)
|
||||||
|
{
|
||||||
|
if (AAbuf.GprIndex == ShaderIrOperGpr.ZRIndex &&
|
||||||
|
BAbuf.GprIndex == ShaderIrOperGpr.ZRIndex &&
|
||||||
|
(AAbuf.Offs >> 4) == (BAbuf.Offs >> 4))
|
||||||
|
{
|
||||||
|
string AttrName = GetName(AAbuf, Swizzle: false);
|
||||||
|
|
||||||
|
//Needs to call this to ensure it registers all elements used.
|
||||||
|
GetName(BAbuf);
|
||||||
|
|
||||||
|
return $"{AttrName}." +
|
||||||
|
$"{GetAttrSwizzle((AAbuf.Offs >> 2) & 3)}" +
|
||||||
|
$"{GetAttrSwizzle((BAbuf.Offs >> 2) & 3)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "vec2(" +
|
||||||
|
$"{GetInOperName(Op.OperandA)}, " +
|
||||||
|
$"{GetInOperName(Op.OperandB)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShaderIrNode GetInnerNode(ShaderIrNode Node)
|
||||||
|
{
|
||||||
|
if (Node is ShaderIrOp Op && Op.Inst == ShaderIrInst.Ipa)
|
||||||
|
{
|
||||||
|
return Op.OperandA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetAttrSwizzle(int Elem)
|
||||||
|
{
|
||||||
|
return "xyzw".Substring(Elem, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,6 +64,83 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fmul);
|
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fmul);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Fsetp_C(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
bool Aa = ((OpCode >> 7) & 1) != 0;
|
||||||
|
bool Na = ((OpCode >> 43) & 1) != 0;
|
||||||
|
bool Ab = ((OpCode >> 44) & 1) != 0;
|
||||||
|
|
||||||
|
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
||||||
|
ShaderIrNode OperB = GetOperCbuf34(OpCode);
|
||||||
|
|
||||||
|
ShaderIrInst CmpInst = GetCmp(OpCode);
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(CmpInst,
|
||||||
|
GetAluAbsNeg(OperA, Aa, Na),
|
||||||
|
GetAluAbs (OperB, Ab));
|
||||||
|
|
||||||
|
ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
|
||||||
|
ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
|
||||||
|
ShaderIrOperPred P2Node = GetOperPred39(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
|
|
||||||
|
ShaderIrInst LopInst = GetBLop(OpCode);
|
||||||
|
|
||||||
|
if (LopInst == ShaderIrInst.Band &&
|
||||||
|
P1Node.Index == ShaderIrOperPred.UnusedIndex &&
|
||||||
|
P2Node.Index == ShaderIrOperPred.UnusedIndex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrNode P2NNode = GetOperPred39N(OpCode);
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(LopInst, new ShaderIrOp(ShaderIrInst.Bnot, P0Node), P2NNode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P1Node, Op), OpCode));
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ipa(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrNode OperA = GetOperAbuf28(OpCode);
|
||||||
|
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ipa, OperA, OperB);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Mufu(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
int SubOp = (int)(OpCode >> 20) & 7;
|
||||||
|
|
||||||
|
bool Aa = ((OpCode >> 46) & 1) != 0;
|
||||||
|
bool Na = ((OpCode >> 48) & 1) != 0;
|
||||||
|
|
||||||
|
ShaderIrInst Inst = 0;
|
||||||
|
|
||||||
|
switch (SubOp)
|
||||||
|
{
|
||||||
|
case 0: Inst = ShaderIrInst.Fcos; break;
|
||||||
|
case 1: Inst = ShaderIrInst.Fsin; break;
|
||||||
|
case 2: Inst = ShaderIrInst.Fex2; break;
|
||||||
|
case 3: Inst = ShaderIrInst.Flg2; break;
|
||||||
|
case 4: Inst = ShaderIrInst.Frcp; break;
|
||||||
|
case 5: Inst = ShaderIrInst.Frsq; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrNode OperA = GetOperGpr8(OpCode);
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(Inst, GetAluAbsNeg(OperA, Aa, Na));
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitAluBinary(
|
private static void EmitAluBinary(
|
||||||
ShaderIrBlock Block,
|
ShaderIrBlock Block,
|
||||||
long OpCode,
|
long OpCode,
|
||||||
|
@ -76,8 +153,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
bool Ab = ((OpCode >> 49) & 1) != 0;
|
bool Ab = ((OpCode >> 49) & 1) != 0;
|
||||||
bool Ad = ((OpCode >> 50) & 1) != 0;
|
bool Ad = ((OpCode >> 50) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrOper OperA = GetAluOperANode_R(OpCode);
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
||||||
ShaderIrOper OperB;
|
|
||||||
|
|
||||||
if (Inst == ShaderIrInst.Fadd)
|
if (Inst == ShaderIrInst.Fadd)
|
||||||
{
|
{
|
||||||
|
@ -86,18 +162,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
switch (Oper)
|
switch (Oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.RR: OperB = GetAluOperBNode_RR (OpCode); break;
|
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||||
case ShaderOper.CR: OperB = GetAluOperBCNode_C (OpCode); break;
|
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||||
case ShaderOper.Imm: OperB = GetAluOperBNode_Imm(OpCode); break;
|
case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperB = GetAluAbsNeg(OperB, Ab, Nb);
|
OperB = GetAluAbsNeg(OperB, Ab, Nb);
|
||||||
|
|
||||||
ShaderIrOper Op = GetAluAbs(new ShaderIrOperOp(Inst, OperA, OperB), Ad);
|
ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrNode(GetAluOperDNode(OpCode), Op));
|
Op = GetAluAbs(Op, Ad);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitAluFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitAluFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
@ -105,16 +183,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
bool Nb = ((OpCode >> 48) & 1) != 0;
|
bool Nb = ((OpCode >> 48) & 1) != 0;
|
||||||
bool Nc = ((OpCode >> 49) & 1) != 0;
|
bool Nc = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrOper OperA = GetAluOperANode_R(OpCode);
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB, OperC;
|
||||||
ShaderIrOper OperB;
|
|
||||||
ShaderIrOper OperC;
|
|
||||||
|
|
||||||
switch (Oper)
|
switch (Oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.RR: OperB = GetAluOperBNode_RR (OpCode); break;
|
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||||
case ShaderOper.CR: OperB = GetAluOperBCNode_C (OpCode); break;
|
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||||
case ShaderOper.RC: OperB = GetAluOperBCNode_R (OpCode); break;
|
case ShaderOper.RC: OperB = GetOperGpr39 (OpCode); break;
|
||||||
case ShaderOper.Imm: OperB = GetAluOperBNode_Imm(OpCode); break;
|
case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
@ -123,31 +199,31 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (Oper == ShaderOper.RC)
|
if (Oper == ShaderOper.RC)
|
||||||
{
|
{
|
||||||
OperC = GetAluNeg(GetAluOperBCNode_C(OpCode), Nc);
|
OperC = GetAluNeg(GetOperCbuf34(OpCode), Nc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OperC = GetAluNeg(GetAluOperBCNode_R(OpCode), Nc);
|
OperC = GetAluNeg(GetOperGpr39(OpCode), Nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOper Op = new ShaderIrOperOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
|
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrNode(GetAluOperDNode(OpCode), Op));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOper GetAluAbsNeg(ShaderIrOper Node, bool Abs, bool Neg)
|
private static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||||
{
|
{
|
||||||
return GetAluNeg(GetAluAbs(Node, Abs), Neg);
|
return GetAluNeg(GetAluAbs(Node, Abs), Neg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOper GetAluAbs(ShaderIrOper Node, bool Abs)
|
private static ShaderIrNode GetAluAbs(ShaderIrNode Node, bool Abs)
|
||||||
{
|
{
|
||||||
return Abs ? new ShaderIrOperOp(ShaderIrInst.Fabs, Node) : Node;
|
return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOper GetAluNeg(ShaderIrOper Node, bool Neg)
|
private static ShaderIrNode GetAluNeg(ShaderIrNode Node, bool Neg)
|
||||||
{
|
{
|
||||||
return Neg ? new ShaderIrOperOp(ShaderIrInst.Fneg, Node) : Node;
|
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
12
Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
Normal file
12
Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
static partial class ShaderDecode
|
||||||
|
{
|
||||||
|
public static void Kil(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Kil), OpCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static class ShaderDecodeHelper
|
static class ShaderDecodeHelper
|
||||||
{
|
{
|
||||||
public static ShaderIrOperAbuf[] GetAluOperANode_A(long OpCode)
|
public static ShaderIrOperAbuf[] GetOperAbuf20(long OpCode)
|
||||||
{
|
{
|
||||||
int Abuf = (int)(OpCode >> 20) & 0x3ff;
|
int Abuf = (int)(OpCode >> 20) & 0x3ff;
|
||||||
int Reg = (int)(OpCode >> 39) & 0xff;
|
int Reg = (int)(OpCode >> 39) & 0xff;
|
||||||
|
@ -18,37 +20,141 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return Opers;
|
return Opers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperReg GetAluOperANode_R(long OpCode)
|
public static ShaderIrOperAbuf GetOperAbuf28(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperReg((int)(OpCode >> 8) & 0xff);
|
int Abuf = (int)(OpCode >> 28) & 0x3ff;
|
||||||
|
int Reg = (int)(OpCode >> 39) & 0xff;
|
||||||
|
|
||||||
|
return new ShaderIrOperAbuf(Abuf, Reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperReg GetAluOperBNode_RR(long OpCode)
|
public static ShaderIrOperCbuf GetOperCbuf34(long OpCode)
|
||||||
{
|
|
||||||
return new ShaderIrOperReg((int)(OpCode >> 20) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ShaderIrOperReg GetAluOperBCNode_R(long OpCode)
|
|
||||||
{
|
|
||||||
return new ShaderIrOperReg((int)(OpCode >> 39) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ShaderIrOperCbuf GetAluOperBCNode_C(long OpCode)
|
|
||||||
{
|
{
|
||||||
return new ShaderIrOperCbuf(
|
return new ShaderIrOperCbuf(
|
||||||
(int)(OpCode >> 34) & 0x1f,
|
(int)(OpCode >> 34) & 0x1f,
|
||||||
(int)(OpCode >> 20) & 0x3fff);
|
(int)(OpCode >> 20) & 0x3fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperReg GetAluOperDNode(long OpCode)
|
public static ShaderIrOperGpr GetOperGpr8(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperReg((int)(OpCode >> 0) & 0xff);
|
return new ShaderIrOperGpr((int)(OpCode >> 8) & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOper GetAluOperBNode_Imm(long OpCode)
|
public static ShaderIrOperGpr GetOperGpr20(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperGpr((int)(OpCode >> 20) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperGpr GetOperGpr39(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperGpr((int)(OpCode >> 39) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperGpr GetOperGpr0(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperGpr((int)(OpCode >> 0) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperGpr GetOperGpr28(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrNode GetOperImmf19_20(long OpCode)
|
||||||
{
|
{
|
||||||
//TODO
|
//TODO
|
||||||
return new ShaderIrOper();
|
return new ShaderIrNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperPred GetOperPred3(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperPred GetOperPred0(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperPred((int)(OpCode >> 0) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrNode GetOperPred39N(long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrNode Node = GetOperPred39(OpCode);
|
||||||
|
|
||||||
|
if (((OpCode >> 42) & 1) != 0)
|
||||||
|
{
|
||||||
|
Node = new ShaderIrOp(ShaderIrInst.Bnot, Node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperPred GetOperPred39(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperPred((int)(OpCode >> 39) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrInst GetCmp(long OpCode)
|
||||||
|
{
|
||||||
|
switch ((int)(OpCode >> 48) & 0xf)
|
||||||
|
{
|
||||||
|
case 0x1: return ShaderIrInst.Clt;
|
||||||
|
case 0x2: return ShaderIrInst.Ceq;
|
||||||
|
case 0x3: return ShaderIrInst.Cle;
|
||||||
|
case 0x4: return ShaderIrInst.Cgt;
|
||||||
|
case 0x5: return ShaderIrInst.Cne;
|
||||||
|
case 0x6: return ShaderIrInst.Cge;
|
||||||
|
case 0x7: return ShaderIrInst.Cnum;
|
||||||
|
case 0x8: return ShaderIrInst.Cnan;
|
||||||
|
case 0x9: return ShaderIrInst.Cltu;
|
||||||
|
case 0xa: return ShaderIrInst.Cequ;
|
||||||
|
case 0xb: return ShaderIrInst.Cleu;
|
||||||
|
case 0xc: return ShaderIrInst.Cgtu;
|
||||||
|
case 0xd: return ShaderIrInst.Cneu;
|
||||||
|
case 0xe: return ShaderIrInst.Cgeu;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrInst GetBLop(long OpCode)
|
||||||
|
{
|
||||||
|
switch ((int)(OpCode >> 45) & 3)
|
||||||
|
{
|
||||||
|
case 0: return ShaderIrInst.Band;
|
||||||
|
case 1: return ShaderIrInst.Bor;
|
||||||
|
case 2: return ShaderIrInst.Bxor;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrNode GetPredNode(ShaderIrNode Node, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrOperPred Pred = GetPredNode(OpCode);
|
||||||
|
|
||||||
|
if (Pred.Index != ShaderIrOperPred.UnusedIndex)
|
||||||
|
{
|
||||||
|
Node = new ShaderIrCond(Pred, Node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShaderIrOperPred GetPredNode(long OpCode)
|
||||||
|
{
|
||||||
|
int Pred = (int)(OpCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
if (Pred != 0xf)
|
||||||
|
{
|
||||||
|
Pred &= 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ShaderIrOperPred(Pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,34 +6,54 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
public static void Ld_A(ShaderIrBlock Block, long OpCode)
|
public static void Ld_A(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
ShaderIrOper[] Opers = GetAluOperANode_A(OpCode);
|
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
||||||
|
|
||||||
int Index = 0;
|
int Index = 0;
|
||||||
|
|
||||||
foreach (ShaderIrOper OperA in Opers)
|
foreach (ShaderIrNode OperA in Opers)
|
||||||
{
|
{
|
||||||
ShaderIrOperReg OperD = GetAluOperDNode(OpCode);
|
ShaderIrOperGpr OperD = GetOperGpr0(OpCode);
|
||||||
|
|
||||||
OperD.GprIndex += Index++;
|
OperD.Index += Index++;
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrNode(OperD, OperA));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, OperA), OpCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void St_A(ShaderIrBlock Block, long OpCode)
|
public static void St_A(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
ShaderIrOper[] Opers = GetAluOperANode_A(OpCode);
|
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
||||||
|
|
||||||
int Index = 0;
|
int Index = 0;
|
||||||
|
|
||||||
foreach (ShaderIrOper OperA in Opers)
|
foreach (ShaderIrNode OperA in Opers)
|
||||||
{
|
{
|
||||||
ShaderIrOperReg OperD = GetAluOperDNode(OpCode);
|
ShaderIrOperGpr OperD = GetOperGpr0(OpCode);
|
||||||
|
|
||||||
OperD.GprIndex += Index++;
|
OperD.Index += Index++;
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrNode(OperA, OperD));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, OperD), OpCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Texs(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
//TODO: Support other formats.
|
||||||
|
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
||||||
|
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
||||||
|
ShaderIrNode OperC = GetOperGpr28 (OpCode);
|
||||||
|
ShaderIrNode OperD = GetOperImm13_36(OpCode);
|
||||||
|
|
||||||
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
|
{
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Texr + Ch, OperA, OperB, OperD);
|
||||||
|
|
||||||
|
ShaderIrOperGpr Dst = GetOperGpr0(OpCode);
|
||||||
|
|
||||||
|
Dst.Index += Ch;
|
||||||
|
|
||||||
|
Block.AddNode(new ShaderIrAsg(Dst, Op));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static class ShaderDecoder
|
static class ShaderDecoder
|
||||||
{
|
{
|
||||||
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset)
|
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset, ShaderType Type)
|
||||||
{
|
{
|
||||||
ShaderIrBlock Block = new ShaderIrBlock();
|
ShaderIrBlock Block = new ShaderIrBlock();
|
||||||
|
|
||||||
|
@ -23,6 +23,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Decode(Block, OpCode);
|
Decode(Block, OpCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Type == ShaderType.Fragment)
|
||||||
|
{
|
||||||
|
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x70, 0), new ShaderIrOperGpr(0)));
|
||||||
|
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x74, 0), new ShaderIrOperGpr(1)));
|
||||||
|
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x78, 0), new ShaderIrOperGpr(2)));
|
||||||
|
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x7c, 0), new ShaderIrOperGpr(3)));
|
||||||
|
}
|
||||||
|
|
||||||
Block.RunOptimizationPasses();
|
Block.RunOptimizationPasses();
|
||||||
|
|
||||||
return Block;
|
return Block;
|
||||||
|
|
14
Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs
Normal file
14
Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrAsg : ShaderIrNode
|
||||||
|
{
|
||||||
|
public ShaderIrNode Dst { get; set; }
|
||||||
|
public ShaderIrNode Src { get; set; }
|
||||||
|
|
||||||
|
public ShaderIrAsg(ShaderIrNode Dst, ShaderIrNode Src)
|
||||||
|
{
|
||||||
|
this.Dst = Dst;
|
||||||
|
this.Src = Src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
Normal file
14
Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrCond : ShaderIrNode
|
||||||
|
{
|
||||||
|
public ShaderIrNode Pred { get; set; }
|
||||||
|
public ShaderIrNode Child { get; set; }
|
||||||
|
|
||||||
|
public ShaderIrCond(ShaderIrNode Pred, ShaderIrNode Child)
|
||||||
|
{
|
||||||
|
this.Pred = Pred;
|
||||||
|
this.Child = Child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,40 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
enum ShaderIrInst
|
enum ShaderIrInst
|
||||||
{
|
{
|
||||||
|
Band,
|
||||||
|
Bnot,
|
||||||
|
Bor,
|
||||||
|
Bxor,
|
||||||
|
Clt,
|
||||||
|
Ceq,
|
||||||
|
Cle,
|
||||||
|
Cgt,
|
||||||
|
Cne,
|
||||||
|
Cge,
|
||||||
|
Cnum,
|
||||||
|
Cnan,
|
||||||
|
Cltu,
|
||||||
|
Cequ,
|
||||||
|
Cleu,
|
||||||
|
Cgtu,
|
||||||
|
Cneu,
|
||||||
|
Cgeu,
|
||||||
Fabs,
|
Fabs,
|
||||||
Fadd,
|
Fadd,
|
||||||
|
Fcos,
|
||||||
|
Fex2,
|
||||||
Ffma,
|
Ffma,
|
||||||
|
Flg2,
|
||||||
Fmul,
|
Fmul,
|
||||||
Fneg,
|
Fneg,
|
||||||
|
Frcp,
|
||||||
|
Frsq,
|
||||||
|
Fsin,
|
||||||
|
Ipa,
|
||||||
|
Kil,
|
||||||
|
Texr,
|
||||||
|
Texg,
|
||||||
|
Texb,
|
||||||
|
Texa
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,4 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrNode
|
class ShaderIrNode { }
|
||||||
{
|
|
||||||
public ShaderIrOper Dst { get; set; }
|
|
||||||
public ShaderIrOper Src { get; set; }
|
|
||||||
|
|
||||||
public ShaderIrNode(ShaderIrOper Dst, ShaderIrOper Src)
|
|
||||||
{
|
|
||||||
this.Dst = Dst;
|
|
||||||
this.Src = Src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
22
Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
Normal file
22
Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrOp : ShaderIrNode
|
||||||
|
{
|
||||||
|
public ShaderIrInst Inst { get; private set; }
|
||||||
|
public ShaderIrNode OperandA { get; set; }
|
||||||
|
public ShaderIrNode OperandB { get; set; }
|
||||||
|
public ShaderIrNode OperandC { get; set; }
|
||||||
|
|
||||||
|
public ShaderIrOp(
|
||||||
|
ShaderIrInst Inst,
|
||||||
|
ShaderIrNode OperandA = null,
|
||||||
|
ShaderIrNode OperandB = null,
|
||||||
|
ShaderIrNode OperandC = null)
|
||||||
|
{
|
||||||
|
this.Inst = Inst;
|
||||||
|
this.OperandA = OperandA;
|
||||||
|
this.OperandB = OperandB;
|
||||||
|
this.OperandC = OperandC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
|
||||||
{
|
|
||||||
class ShaderIrOper { }
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrOperAbuf : ShaderIrOper
|
class ShaderIrOperAbuf : ShaderIrNode
|
||||||
{
|
{
|
||||||
public int Offs { get; private set; }
|
public int Offs { get; private set; }
|
||||||
public int GprIndex { get; private set; }
|
public int GprIndex { get; private set; }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrOperCbuf : ShaderIrOper
|
class ShaderIrOperCbuf : ShaderIrNode
|
||||||
{
|
{
|
||||||
public int Index { get; private set; }
|
public int Index { get; private set; }
|
||||||
public int Offs { get; private set; }
|
public int Offs { get; private set; }
|
||||||
|
|
14
Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs
Normal file
14
Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrOperGpr : ShaderIrNode
|
||||||
|
{
|
||||||
|
public const int ZRIndex = 0xff;
|
||||||
|
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
public ShaderIrOperGpr(int Index)
|
||||||
|
{
|
||||||
|
this.Index = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrOperImm : ShaderIrOper
|
class ShaderIrOperImm : ShaderIrNode
|
||||||
{
|
{
|
||||||
public int Imm { get; private set; }
|
public int Imm { get; private set; }
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrOperImmf : ShaderIrOper
|
class ShaderIrOperImmf : ShaderIrNode
|
||||||
{
|
{
|
||||||
public float Imm { get; private set; }
|
public float Imm { get; private set; }
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
|
||||||
{
|
|
||||||
class ShaderIrOperOp : ShaderIrOper
|
|
||||||
{
|
|
||||||
public ShaderIrInst Inst { get; private set; }
|
|
||||||
public ShaderIrOper OperandA { get; set; }
|
|
||||||
public ShaderIrOper OperandB { get; set; }
|
|
||||||
public ShaderIrOper OperandC { get; set; }
|
|
||||||
|
|
||||||
public ShaderIrOperOp(
|
|
||||||
ShaderIrInst Inst,
|
|
||||||
ShaderIrOper OperandA = null,
|
|
||||||
ShaderIrOper OperandB = null,
|
|
||||||
ShaderIrOper OperandC = null)
|
|
||||||
{
|
|
||||||
this.Inst = Inst;
|
|
||||||
this.OperandA = OperandA;
|
|
||||||
this.OperandB = OperandB;
|
|
||||||
this.OperandC = OperandC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
15
Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs
Normal file
15
Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrOperPred : ShaderIrNode
|
||||||
|
{
|
||||||
|
public const int UnusedIndex = 0x7;
|
||||||
|
public const int NeverExecute = 0xf;
|
||||||
|
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
public ShaderIrOperPred(int Index)
|
||||||
|
{
|
||||||
|
this.Index = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
|
||||||
{
|
|
||||||
class ShaderIrOperReg : ShaderIrOper
|
|
||||||
{
|
|
||||||
public const int ZRIndex = 0xff;
|
|
||||||
|
|
||||||
public int GprIndex { get; set; }
|
|
||||||
|
|
||||||
public ShaderIrOperReg(int GprIndex)
|
|
||||||
{
|
|
||||||
this.GprIndex = GprIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,11 +23,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("0101110001101x", ShaderDecode.Fmul_R);
|
Set("0101110001101x", ShaderDecode.Fmul_R);
|
||||||
Set("0100110001101x", ShaderDecode.Fmul_C);
|
Set("0100110001101x", ShaderDecode.Fmul_C);
|
||||||
Set("0011100x01101x", ShaderDecode.Fmul_Imm);
|
Set("0011100x01101x", ShaderDecode.Fmul_Imm);
|
||||||
|
Set("010010111011xx", ShaderDecode.Fsetp_C);
|
||||||
|
Set("11100000xxxxxx", ShaderDecode.Ipa);
|
||||||
|
Set("111000110011xx", ShaderDecode.Kil);
|
||||||
Set("1110111111011x", ShaderDecode.Ld_A);
|
Set("1110111111011x", ShaderDecode.Ld_A);
|
||||||
|
Set("0101000010000x", ShaderDecode.Mufu);
|
||||||
Set("1110111111110x", ShaderDecode.St_A);
|
Set("1110111111110x", ShaderDecode.St_A);
|
||||||
|
Set("1101100xxxxxxx", ShaderDecode.Texs);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Set(string Encoding, ShaderDecodeFunc Func)
|
private static void Set(string Encoding, ShaderDecodeFunc Func)
|
||||||
{
|
{
|
||||||
if (Encoding.Length != EncodingBits)
|
if (Encoding.Length != EncodingBits)
|
||||||
|
|
|
@ -20,7 +20,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private class RegUse
|
private class RegUse
|
||||||
{
|
{
|
||||||
public ShaderIrNode Node { get; private set; }
|
public ShaderIrAsg Asg { get; private set; }
|
||||||
|
|
||||||
|
public int AsgIndex { get; private set; }
|
||||||
|
|
||||||
|
private bool Propagate;
|
||||||
|
|
||||||
private List<UseSite> Sites;
|
private List<UseSite> Sites;
|
||||||
|
|
||||||
|
@ -36,45 +40,60 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public bool TryPropagate()
|
public bool TryPropagate()
|
||||||
{
|
{
|
||||||
//If the use count of the register is more than 1,
|
//This happens when a untiliazied register is used,
|
||||||
//then propagating the expression is not worth it,
|
//this usually indicates a decoding error, but may also
|
||||||
//because the code will be larger, harder to read,
|
//be cased by bogus programs (?). In any case, we just
|
||||||
//and less efficient due to the common sub-expression being
|
//keep the unitialized access and avoid trying to propagate
|
||||||
//propagated.
|
//the expression (since we can't propagate what doesn't yet exist).
|
||||||
if (Sites.Count == 1 || !(Node.Src is ShaderIrOperOp))
|
if (Asg == null || !Propagate)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Sites.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (UseSite Site in Sites)
|
foreach (UseSite Site in Sites)
|
||||||
{
|
{
|
||||||
if (Site.Parent is ShaderIrOperOp Op)
|
if (Site.Parent is ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
switch (Site.OperIndex)
|
switch (Site.OperIndex)
|
||||||
{
|
{
|
||||||
case 0: Op.OperandA = Node.Src; break;
|
case 0: Cond.Pred = Asg.Src; break;
|
||||||
case 1: Op.OperandB = Node.Src; break;
|
case 1: Cond.Child = Asg.Src; break;
|
||||||
case 2: Op.OperandC = Node.Src; break;
|
|
||||||
|
|
||||||
default: throw new InvalidOperationException();
|
default: throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Site.Parent is ShaderIrNode SiteNode)
|
else if (Site.Parent is ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
SiteNode.Src = Node.Src;
|
switch (Site.OperIndex)
|
||||||
|
{
|
||||||
|
case 0: Op.OperandA = Asg.Src; break;
|
||||||
|
case 1: Op.OperandB = Asg.Src; break;
|
||||||
|
case 2: Op.OperandC = Asg.Src; break;
|
||||||
|
|
||||||
|
default: throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Site.Parent is ShaderIrAsg SiteAsg)
|
||||||
|
{
|
||||||
|
SiteAsg.Src = Asg.Src;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Sites.Count == 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetNewAsg(ShaderIrNode Node)
|
public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, bool Propagate)
|
||||||
{
|
{
|
||||||
this.Node = Node;
|
this.Asg = Asg;
|
||||||
|
this.AsgIndex = AsgIndex;
|
||||||
|
this.Propagate = Propagate;
|
||||||
|
|
||||||
Sites.Clear();
|
Sites.Clear();
|
||||||
}
|
}
|
||||||
|
@ -84,69 +103,147 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
Dictionary<int, RegUse> Uses = new Dictionary<int, RegUse>();
|
Dictionary<int, RegUse> Uses = new Dictionary<int, RegUse>();
|
||||||
|
|
||||||
RegUse GetRegUse(int GprIndex)
|
RegUse GetUse(int Key)
|
||||||
{
|
{
|
||||||
RegUse Use;
|
RegUse Use;
|
||||||
|
|
||||||
if (!Uses.TryGetValue(GprIndex, out Use))
|
if (!Uses.TryGetValue(Key, out Use))
|
||||||
{
|
{
|
||||||
Use = new RegUse();
|
Use = new RegUse();
|
||||||
|
|
||||||
Uses.Add(GprIndex, Use);
|
Uses.Add(Key, Use);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Use;
|
return Use;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TryAddRegUse(object Parent, ShaderIrOper Oper, int OperIndex = 0)
|
int GetGprKey(int GprIndex)
|
||||||
{
|
{
|
||||||
if (Oper is ShaderIrOperOp Op)
|
return GprIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetPredKey(int PredIndex)
|
||||||
|
{
|
||||||
|
return PredIndex | 0x10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegUse GetGprUse(int GprIndex)
|
||||||
|
{
|
||||||
|
return GetUse(GetGprKey(GprIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
RegUse GetPredUse(int PredIndex)
|
||||||
|
{
|
||||||
|
return GetUse(GetPredKey(PredIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindRegUses(List<(int, UseSite)> UseList, object Parent, ShaderIrNode Node, int OperIndex = 0)
|
||||||
|
{
|
||||||
|
if (Node is ShaderIrAsg Asg)
|
||||||
{
|
{
|
||||||
TryAddRegUse(Op, Op.OperandA, 0);
|
FindRegUses(UseList, Asg, Asg.Src);
|
||||||
TryAddRegUse(Op, Op.OperandB, 1);
|
|
||||||
TryAddRegUse(Op, Op.OperandC, 2);
|
|
||||||
}
|
}
|
||||||
else if (Oper is ShaderIrOperReg Reg && Reg.GprIndex != ShaderIrOperReg.ZRIndex)
|
else if (Node is ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
GetRegUse(Reg.GprIndex).AddUseSite(new UseSite(Parent, OperIndex));
|
FindRegUses(UseList, Cond, Cond.Pred, 0);
|
||||||
|
FindRegUses(UseList, Cond, Cond.Child, 1);
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
FindRegUses(UseList, Op, Op.OperandA, 0);
|
||||||
|
FindRegUses(UseList, Op, Op.OperandB, 1);
|
||||||
|
FindRegUses(UseList, Op, Op.OperandC, 2);
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
|
||||||
|
{
|
||||||
|
UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, OperIndex)));
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOperPred Pred)
|
||||||
|
{
|
||||||
|
UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, OperIndex)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int Index = 0; Index < Nodes.Count; Index++)
|
void TryAddRegUseSite(ShaderIrNode Node)
|
||||||
|
{
|
||||||
|
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
||||||
|
|
||||||
|
FindRegUses(UseList, null, Node);
|
||||||
|
|
||||||
|
foreach ((int Key, UseSite Site) in UseList)
|
||||||
|
{
|
||||||
|
GetUse(Key).AddUseSite(Site);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryPropagate(RegUse Use)
|
||||||
|
{
|
||||||
|
//We can only propagate if the registers that the expression depends
|
||||||
|
//on weren't assigned after the original expression assignment
|
||||||
|
//to a register took place. We traverse the expression tree to find
|
||||||
|
//all registers being used, if any of those registers was assigned
|
||||||
|
//after the assignment to be propagated, then we can't propagate.
|
||||||
|
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
||||||
|
|
||||||
|
FindRegUses(UseList, Use.Asg, Use.Asg.Src);
|
||||||
|
|
||||||
|
foreach ((int Key, UseSite Site) in UseList)
|
||||||
|
{
|
||||||
|
if (GetUse(Key).AsgIndex >= Use.AsgIndex)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Use.TryPropagate();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int Index = 0, AsgIndex = 0; Index < Nodes.Count; Index++, AsgIndex++)
|
||||||
{
|
{
|
||||||
ShaderIrNode Node = Nodes[Index];
|
ShaderIrNode Node = Nodes[Index];
|
||||||
|
|
||||||
if (Node.Src is ShaderIrOperOp Op)
|
bool IsConditional = Node is ShaderIrCond;
|
||||||
|
|
||||||
|
TryAddRegUseSite(Node);
|
||||||
|
|
||||||
|
while (Node is ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
TryAddRegUse(Node, Op);
|
Node = Cond.Child;
|
||||||
}
|
|
||||||
else if (Node.Src is ShaderIrOperReg)
|
|
||||||
{
|
|
||||||
TryAddRegUse(Node, Node.Src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Node.Dst is ShaderIrOperReg Reg && Reg.GprIndex != ShaderIrOperReg.ZRIndex)
|
if (!(Node is ShaderIrAsg Asg))
|
||||||
{
|
{
|
||||||
RegUse Use = GetRegUse(Reg.GprIndex);
|
continue;
|
||||||
|
|
||||||
if (Use.Node != null && Use.TryPropagate())
|
|
||||||
{
|
|
||||||
Nodes.Remove(Use.Node);
|
|
||||||
|
|
||||||
Index--;
|
|
||||||
}
|
|
||||||
|
|
||||||
Use.SetNewAsg(Node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RegUse Use = null;
|
||||||
|
|
||||||
|
if (Asg.Dst is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
|
||||||
|
{
|
||||||
|
Use = GetGprUse(Gpr.Index);
|
||||||
|
}
|
||||||
|
else if (Asg.Dst is ShaderIrOperPred Pred)
|
||||||
|
{
|
||||||
|
Use = GetPredUse(Pred.Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Use?.Asg != null && !IsConditional && TryPropagate(Use))
|
||||||
|
{
|
||||||
|
Nodes.Remove(Use.Asg);
|
||||||
|
|
||||||
|
Index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
//All nodes inside conditional nodes can't be propagated,
|
||||||
|
//as we don't even know if they will be executed to begin with.
|
||||||
|
Use?.SetNewAsg(Asg, AsgIndex, !IsConditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: On the fragment shader, we should keep the values on r0-r3,
|
|
||||||
//because they are the fragment shader color output.
|
|
||||||
foreach (RegUse Use in Uses.Values)
|
foreach (RegUse Use in Uses.Values)
|
||||||
{
|
{
|
||||||
if (Use.TryPropagate())
|
if (TryPropagate(Use))
|
||||||
{
|
{
|
||||||
Nodes.Remove(Use.Node);
|
Nodes.Remove(Use.Asg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
System.Collections.Generic.List<int> CodeList = new System.Collections.Generic.List<int>();
|
System.Collections.Generic.List<int> CodeList = new System.Collections.Generic.List<int>();
|
||||||
|
|
||||||
using (System.IO.FileStream FS = new System.IO.FileStream("D:\\puyo_vsh.bin", System.IO.FileMode.Open))
|
using (System.IO.FileStream FS = new System.IO.FileStream("D:\\puyo_fsh.bin", System.IO.FileMode.Open))
|
||||||
{
|
{
|
||||||
System.IO.BinaryReader Reader = new System.IO.BinaryReader(FS);
|
System.IO.BinaryReader Reader = new System.IO.BinaryReader(FS);
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
GlslDecompiler Decompiler = new GlslDecompiler();
|
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||||
|
|
||||||
System.Console.WriteLine(Decompiler.Decompile(Code));
|
System.Console.WriteLine(Decompiler.Decompile(Code, ShaderType.Fragment));
|
||||||
|
|
||||||
System.Console.WriteLine("Done!");
|
System.Console.WriteLine("Done!");
|
||||||
}
|
}
|
||||||
|
|
8
Ryujinx.Graphics/Gal/Shader/ShaderType.cs
Normal file
8
Ryujinx.Graphics/Gal/Shader/ShaderType.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
enum ShaderType
|
||||||
|
{
|
||||||
|
Vertex,
|
||||||
|
Fragment
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue