Started to work on glsl decompiler
This commit is contained in:
parent
94f3befc96
commit
7949ceffa5
4 changed files with 337 additions and 125 deletions
328
Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
Normal file
328
Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class GlslDecompiler
|
||||||
|
{
|
||||||
|
private delegate string GetInstExpr(ShaderIrOperOp Op);
|
||||||
|
|
||||||
|
private Dictionary<ShaderIrInst, GetInstExpr> InstsExpr;
|
||||||
|
|
||||||
|
private class Attrib
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public int Elems;
|
||||||
|
|
||||||
|
public Attrib(string Name, int Elems)
|
||||||
|
{
|
||||||
|
this.Name = Name;
|
||||||
|
this.Elems = Elems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
||||||
|
|
||||||
|
private SortedDictionary<int, Attrib> InputAttributes;
|
||||||
|
private SortedDictionary<int, Attrib> OutputAttributes;
|
||||||
|
|
||||||
|
private HashSet<int> UsedCbufs;
|
||||||
|
|
||||||
|
private const int AttrStartIndex = 8;
|
||||||
|
|
||||||
|
private const string InputAttrPrefix = "in_attr";
|
||||||
|
private const string OutputAttrPrefix = "out_attr";
|
||||||
|
|
||||||
|
private const string CbufBuffPrefix = "c";
|
||||||
|
private const string CbufDataName = "buf";
|
||||||
|
|
||||||
|
private const string GprName = "gpr";
|
||||||
|
|
||||||
|
private string IdentationStr = "\t";
|
||||||
|
|
||||||
|
private int GprsCount;
|
||||||
|
|
||||||
|
private StringBuilder BodySB;
|
||||||
|
|
||||||
|
public GlslDecompiler()
|
||||||
|
{
|
||||||
|
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
||||||
|
{
|
||||||
|
{ ShaderIrInst.Fabs, GetFabsExpr },
|
||||||
|
{ ShaderIrInst.Fadd, GetFaddExpr },
|
||||||
|
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
||||||
|
{ ShaderIrInst.Fmul, GetFmulExpr },
|
||||||
|
{ ShaderIrInst.Fneg, GetFnegExpr }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Decompile(int[] Code)
|
||||||
|
{
|
||||||
|
InputAttributes = new SortedDictionary<int, Attrib>();
|
||||||
|
OutputAttributes = new SortedDictionary<int, Attrib>();
|
||||||
|
|
||||||
|
UsedCbufs = new HashSet<int>();
|
||||||
|
|
||||||
|
BodySB = new StringBuilder();
|
||||||
|
|
||||||
|
//FIXME: Only valid for vertex shaders.
|
||||||
|
OutputAttributes.Add(7, new Attrib("gl_Position", 4));
|
||||||
|
|
||||||
|
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0);
|
||||||
|
|
||||||
|
ShaderIrNode[] Nodes = Block.GetNodes();
|
||||||
|
|
||||||
|
PrintBlockScope(Nodes, "void main()", 1);
|
||||||
|
|
||||||
|
StringBuilder SB = new StringBuilder();
|
||||||
|
|
||||||
|
PrintDeclUBOs(SB);
|
||||||
|
PrintDeclInAttributes(SB);
|
||||||
|
PrintDeclOutAttributes(SB);
|
||||||
|
|
||||||
|
if (GprsCount > 0)
|
||||||
|
{
|
||||||
|
SB.AppendLine($"float {GprName}[{GprsCount}];");
|
||||||
|
SB.AppendLine(string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
SB.Append(BodySB.ToString());
|
||||||
|
|
||||||
|
BodySB.Clear();
|
||||||
|
|
||||||
|
return SB.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclUBOs(StringBuilder SB)
|
||||||
|
{
|
||||||
|
foreach (int Cbuf in UsedCbufs)
|
||||||
|
{
|
||||||
|
SB.AppendLine($"layout(std430, binding = {Cbuf}) buffer {CbufBuffPrefix}{Cbuf} {{");
|
||||||
|
SB.AppendLine($"{IdentationStr}float[] {CbufDataName};");
|
||||||
|
SB.AppendLine("};");
|
||||||
|
SB.AppendLine(string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclInAttributes(StringBuilder SB)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<int, Attrib> KV in InputAttributes)
|
||||||
|
{
|
||||||
|
int Index = KV.Key - AttrStartIndex;
|
||||||
|
|
||||||
|
if (Index >= 0)
|
||||||
|
{
|
||||||
|
string Type = ElemTypes[KV.Value.Elems];
|
||||||
|
|
||||||
|
SB.AppendLine($"layout(location = {Index}) in {Type} {KV.Value.Name};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SB.AppendLine(string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclOutAttributes(StringBuilder SB)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<int, Attrib> KV in OutputAttributes)
|
||||||
|
{
|
||||||
|
int Index = KV.Key - AttrStartIndex;
|
||||||
|
|
||||||
|
if (Index >= 0)
|
||||||
|
{
|
||||||
|
string Type = ElemTypes[KV.Value.Elems];
|
||||||
|
|
||||||
|
SB.AppendLine($"layout(location = {Index}) out {Type} {KV.Value.Name};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SB.AppendLine(string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintBlockScope(ShaderIrNode[] Nodes, string ScopeName, int IdentationLevel)
|
||||||
|
{
|
||||||
|
string Identation = string.Empty;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < IdentationLevel - 1; Index++)
|
||||||
|
{
|
||||||
|
Identation += IdentationStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ScopeName != string.Empty)
|
||||||
|
{
|
||||||
|
ScopeName += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
BodySB.AppendLine(Identation + ScopeName + "{");
|
||||||
|
|
||||||
|
string LastLine = Identation + "}";
|
||||||
|
|
||||||
|
if (IdentationLevel > 0)
|
||||||
|
{
|
||||||
|
Identation += IdentationStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ShaderIrNode Node in Nodes)
|
||||||
|
{
|
||||||
|
if (Node.Dst is ShaderIrOperReg Reg && Reg.GprIndex == ShaderIrOperReg.ZRIndex)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BodySB.AppendLine(Identation +
|
||||||
|
$"{GetOOperName(Node.Dst)} = " +
|
||||||
|
$"{GetIOperName(Node.Src, true)};");
|
||||||
|
}
|
||||||
|
|
||||||
|
BodySB.AppendLine(LastLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetOOperName(ShaderIrOper Oper)
|
||||||
|
{
|
||||||
|
if (Oper is ShaderIrOperAbuf Abuf)
|
||||||
|
{
|
||||||
|
return GetOAbufName(Abuf);
|
||||||
|
}
|
||||||
|
else if (Oper is ShaderIrOperReg Reg)
|
||||||
|
{
|
||||||
|
return GetRegName(Reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(Oper));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetIOperName(ShaderIrOper Oper, bool Entry = false)
|
||||||
|
{
|
||||||
|
switch (Oper)
|
||||||
|
{
|
||||||
|
case ShaderIrOperAbuf Abuf: return GetIAbufName(Abuf);
|
||||||
|
case ShaderIrOperCbuf Cbuf: return GetCbufName(Cbuf);
|
||||||
|
case ShaderIrOperReg Reg: return GetRegName(Reg);
|
||||||
|
case ShaderIrOperOp Op:
|
||||||
|
string Expr;
|
||||||
|
|
||||||
|
if (InstsExpr.TryGetValue(Op.Inst, out GetInstExpr GetExpr))
|
||||||
|
{
|
||||||
|
Expr = GetExpr(Op);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException(Op.Inst.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Entry || IsUnary(Op.Inst)))
|
||||||
|
{
|
||||||
|
Expr = $"({Expr})";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Expr;
|
||||||
|
|
||||||
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsUnary(ShaderIrInst Inst)
|
||||||
|
{
|
||||||
|
return Inst == ShaderIrInst.Fabs ||
|
||||||
|
Inst == ShaderIrInst.Fneg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetOAbufName(ShaderIrOperAbuf Abuf)
|
||||||
|
{
|
||||||
|
int AttrIndex = Abuf.Offs >> 4;
|
||||||
|
|
||||||
|
int Elem = (Abuf.Offs >> 2) & 3;
|
||||||
|
|
||||||
|
if (!OutputAttributes.TryGetValue(AttrIndex, out Attrib Attr))
|
||||||
|
{
|
||||||
|
Attr = new Attrib(OutputAttrPrefix + (AttrIndex - AttrStartIndex), Elem);
|
||||||
|
|
||||||
|
OutputAttributes.Add(AttrIndex, Attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attr.Elems < Elem)
|
||||||
|
{
|
||||||
|
Attr.Elems = Elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{Attr.Name}.{GetAttrSwizzle(Elem)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetIAbufName(ShaderIrOperAbuf Abuf)
|
||||||
|
{
|
||||||
|
int AttrIndex = Abuf.Offs >> 4;
|
||||||
|
|
||||||
|
int Elem = (Abuf.Offs >> 2) & 3;
|
||||||
|
|
||||||
|
if (!InputAttributes.TryGetValue(AttrIndex, out Attrib Attr))
|
||||||
|
{
|
||||||
|
Attr = new Attrib(InputAttrPrefix + (AttrIndex - AttrStartIndex), Elem);
|
||||||
|
|
||||||
|
InputAttributes.Add(AttrIndex, Attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attr.Elems < Elem)
|
||||||
|
{
|
||||||
|
Attr.Elems = Elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{Attr.Name}.{GetAttrSwizzle(Elem)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetAttrSwizzle(int Elem)
|
||||||
|
{
|
||||||
|
return "xyzw".Substring(Elem, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCbufName(ShaderIrOperCbuf Cbuf)
|
||||||
|
{
|
||||||
|
UsedCbufs.Add(Cbuf.Index);
|
||||||
|
|
||||||
|
return $"{CbufBuffPrefix}{Cbuf.Index}.{CbufDataName}[{Cbuf.Offs}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRegName(ShaderIrOperReg Reg)
|
||||||
|
{
|
||||||
|
if (GprsCount < Reg.GprIndex + 1)
|
||||||
|
{
|
||||||
|
GprsCount = Reg.GprIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetRegName(Reg.GprIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRegName(int GprIndex)
|
||||||
|
{
|
||||||
|
return GprIndex == ShaderIrOperReg.ZRIndex ? "0" : $"{GprName}[{GprIndex}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFabsExpr(ShaderIrOperOp Op)
|
||||||
|
{
|
||||||
|
return $"abs({GetIOperName(Op.OperandA)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFaddExpr(ShaderIrOperOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetIOperName(Op.OperandA)} + " +
|
||||||
|
$"{GetIOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFfmaExpr(ShaderIrOperOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetIOperName(Op.OperandA)} * " +
|
||||||
|
$"{GetIOperName(Op.OperandB)} + " +
|
||||||
|
$"{GetIOperName(Op.OperandC)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFmulExpr(ShaderIrOperOp Op)
|
||||||
|
{
|
||||||
|
return $"{GetIOperName(Op.OperandA)} * " +
|
||||||
|
$"{GetIOperName(Op.OperandB)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFnegExpr(ShaderIrOperOp Op)
|
||||||
|
{
|
||||||
|
return $"-{GetIOperName(Op.OperandA)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrOperReg : ShaderIrOper
|
class ShaderIrOperReg : ShaderIrOper
|
||||||
{
|
{
|
||||||
|
public const int ZRIndex = 0xff;
|
||||||
|
|
||||||
public int GprIndex { get; private set; }
|
public int GprIndex { get; private set; }
|
||||||
|
|
||||||
public ShaderIrOperReg(int GprIndex)
|
public ShaderIrOperReg(int GprIndex)
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
TryAddRegUse(Op, Op.OperandB, 1);
|
TryAddRegUse(Op, Op.OperandB, 1);
|
||||||
TryAddRegUse(Op, Op.OperandC, 2);
|
TryAddRegUse(Op, Op.OperandC, 2);
|
||||||
}
|
}
|
||||||
else if (Oper is ShaderIrOperReg Reg && Reg.GprIndex != 0xff)
|
else if (Oper is ShaderIrOperReg Reg && Reg.GprIndex != ShaderIrOperReg.ZRIndex)
|
||||||
{
|
{
|
||||||
GetRegUse(Reg.GprIndex).AddUseSite(new UseSite(Parent, OperIndex));
|
GetRegUse(Reg.GprIndex).AddUseSite(new UseSite(Parent, OperIndex));
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
TryAddRegUse(Node, Node.Src);
|
TryAddRegUse(Node, Node.Src);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Node.Dst is ShaderIrOperReg Reg && Reg.GprIndex != 0xff)
|
if (Node.Dst is ShaderIrOperReg Reg && Reg.GprIndex != ShaderIrOperReg.ZRIndex)
|
||||||
{
|
{
|
||||||
RegUse Use = GetRegUse(Reg.GprIndex);
|
RegUse Use = GetRegUse(Reg.GprIndex);
|
||||||
|
|
||||||
|
@ -140,6 +140,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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 (Use.TryPropagate())
|
||||||
|
|
|
@ -7,8 +7,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
public static void Test()
|
public static void Test()
|
||||||
{
|
{
|
||||||
System.Console.WriteLine("Starting test code...");
|
|
||||||
|
|
||||||
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_vsh.bin", System.IO.FileMode.Open))
|
||||||
|
@ -23,129 +21,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
int[] Code = CodeList.ToArray();
|
int[] Code = CodeList.ToArray();
|
||||||
|
|
||||||
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0);
|
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||||
|
|
||||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
System.Console.WriteLine(Decompiler.Decompile(Code));
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Nodes)
|
System.Console.WriteLine("Done!");
|
||||||
{
|
|
||||||
System.Console.WriteLine($"{GetOutOperName(Node.Dst)} = {GetInOperName(Node.Src, true)}");
|
|
||||||
}
|
|
||||||
|
|
||||||
System.Console.WriteLine("Test code finished!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetOutOperName(ShaderIrOper Oper)
|
|
||||||
{
|
|
||||||
switch (Oper)
|
|
||||||
{
|
|
||||||
case ShaderIrOperAbuf Abuf: return GetOAbufName(Abuf);
|
|
||||||
case ShaderIrOperReg Reg: return GetRegName(Reg);
|
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetInOperName(ShaderIrOper Oper, bool Entry = false)
|
|
||||||
{
|
|
||||||
switch (Oper)
|
|
||||||
{
|
|
||||||
case ShaderIrOperAbuf Abuf: return GetIAbufName(Abuf);
|
|
||||||
case ShaderIrOperCbuf Cbuf: return GetCbufName(Cbuf);
|
|
||||||
case ShaderIrOperReg Reg: return GetRegName(Reg);
|
|
||||||
case ShaderIrOperOp Op:
|
|
||||||
string Expr;
|
|
||||||
|
|
||||||
if (InstsExpr.TryGetValue(Op.Inst, out GetInstExpr GetExpr))
|
|
||||||
{
|
|
||||||
Expr = GetExpr(Op);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotImplementedException(Op.Inst.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(Entry || IsUnary(Op.Inst)))
|
|
||||||
{
|
|
||||||
Expr = $"({Expr})";
|
|
||||||
}
|
|
||||||
|
|
||||||
return Expr;
|
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsUnary(ShaderIrInst Inst)
|
|
||||||
{
|
|
||||||
return Inst == ShaderIrInst.Fabs ||
|
|
||||||
Inst == ShaderIrInst.Fneg;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetOAbufName(ShaderIrOperAbuf Abuf)
|
|
||||||
{
|
|
||||||
return $"a_out[0x{Abuf.Offs:x} + {GetRegName(Abuf.GprIndex)}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetIAbufName(ShaderIrOperAbuf Abuf)
|
|
||||||
{
|
|
||||||
return $"a_in[0x{Abuf.Offs:x} + {GetRegName(Abuf.GprIndex)}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetCbufName(ShaderIrOperCbuf Cbuf)
|
|
||||||
{
|
|
||||||
return $"c{Cbuf.Index}[{Cbuf.Offs}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetRegName(ShaderIrOperReg Reg)
|
|
||||||
{
|
|
||||||
return GetRegName(Reg.GprIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetRegName(int GprIndex)
|
|
||||||
{
|
|
||||||
return GprIndex == 0xff ? "0" : $"r{GprIndex}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private delegate string GetInstExpr(ShaderIrOperOp Op);
|
|
||||||
|
|
||||||
private static Dictionary<ShaderIrInst, GetInstExpr> InstsExpr = new
|
|
||||||
Dictionary<ShaderIrInst, GetInstExpr>()
|
|
||||||
{
|
|
||||||
{ ShaderIrInst.Fabs, GetFabsExpr },
|
|
||||||
{ ShaderIrInst.Fadd, GetFaddExpr },
|
|
||||||
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
|
||||||
{ ShaderIrInst.Fmul, GetFmulExpr },
|
|
||||||
{ ShaderIrInst.Fneg, GetFnegExpr },
|
|
||||||
};
|
|
||||||
|
|
||||||
private static string GetFabsExpr(ShaderIrOperOp Op)
|
|
||||||
{
|
|
||||||
return $"abs({GetInOperName(Op.OperandA)})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFaddExpr(ShaderIrOperOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} + " +
|
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFfmaExpr(ShaderIrOperOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} * " +
|
|
||||||
$"{GetInOperName(Op.OperandB)} + " +
|
|
||||||
$"{GetInOperName(Op.OperandC)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFmulExpr(ShaderIrOperOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} * " +
|
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFnegExpr(ShaderIrOperOp Op)
|
|
||||||
{
|
|
||||||
return $"-{GetInOperName(Op.OperandA)}";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue