aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2018-08-31 13:14:04 -0300
committergdkchan <gab.dark.100@gmail.com>2018-08-31 13:14:04 -0300
commit42dc925c3da59bf8801b14779482ee5bd9c25dc0 (patch)
tree6134135c08fe81414297b75fbf6e1a7479742d07 /Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
parent7cb6fd8090513b703da9b83dec04866647694f09 (diff)
Implement SSY/SYNC shader instructions (#382)
* Use a program counter to control shaders' flow * Cleanup * Implement SSY/SYNC * Address feedback * Fixup commentary * Fixup Ssy instruction
Diffstat (limited to 'Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs')
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs290
1 files changed, 145 insertions, 145 deletions
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index 984684f1..104fd723 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -155,18 +155,19 @@ namespace Ryujinx.Graphics.Gal.Shader
PrintDeclOutAttributes();
PrintDeclGprs();
PrintDeclPreds();
+ PrintDeclSsy();
if (BlocksB != null)
{
- PrintBlockScope(Blocks[0], null, null, "void " + GlslDecl.ProgramAName + "()", IdentationStr);
+ PrintBlockScope(Blocks, GlslDecl.BasicBlockAName);
SB.AppendLine();
- PrintBlockScope(BlocksB[0], null, null, "void " + GlslDecl.ProgramBName + "()", IdentationStr);
+ PrintBlockScope(BlocksB, GlslDecl.BasicBlockBName);
}
else
{
- PrintBlockScope(Blocks[0], null, null, "void " + GlslDecl.ProgramName + "()", IdentationStr);
+ PrintBlockScope(Blocks, GlslDecl.BasicBlockName);
}
SB.AppendLine();
@@ -357,6 +358,13 @@ namespace Ryujinx.Graphics.Gal.Shader
PrintDecls(Decl.Preds, "bool");
}
+ private void PrintDeclSsy()
+ {
+ SB.AppendLine("uint " + GlslDecl.SsyCursorName + ";");
+
+ SB.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine);
+ }
+
private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, string CustomType = null, string Suffix = "")
{
foreach (ShaderDeclInfo DeclInfo in Dict.Values.OrderBy(DeclKeySelector))
@@ -432,14 +440,16 @@ namespace Ryujinx.Graphics.Gal.Shader
}
}
+ SB.AppendLine(IdentationStr + "uint pc;");
+
if (BlocksB != null)
{
- SB.AppendLine(IdentationStr + GlslDecl.ProgramAName + "();");
- SB.AppendLine(IdentationStr + GlslDecl.ProgramBName + "();");
+ PrintProgram(Blocks, GlslDecl.BasicBlockAName);
+ PrintProgram(BlocksB, GlslDecl.BasicBlockBName);
}
else
{
- SB.AppendLine(IdentationStr + GlslDecl.ProgramName + "();");
+ PrintProgram(Blocks, GlslDecl.BasicBlockName);
}
if (Decl.ShaderType != GalShaderType.Geometry)
@@ -477,6 +487,32 @@ namespace Ryujinx.Graphics.Gal.Shader
SB.AppendLine("}");
}
+ private void PrintProgram(ShaderIrBlock[] Blocks, string Name)
+ {
+ const string Ident1 = IdentationStr;
+ const string Ident2 = Ident1 + IdentationStr;
+ const string Ident3 = Ident2 + IdentationStr;
+ const string Ident4 = Ident3 + IdentationStr;
+
+ SB.AppendLine(Ident1 + "pc = " + GetBlockPosition(Blocks[0]) + ";");
+ SB.AppendLine(Ident1 + "do {");
+ SB.AppendLine(Ident2 + "switch (pc) {");
+
+ foreach (ShaderIrBlock Block in Blocks)
+ {
+ string FunctionName = Block.Position.ToString("x8");
+
+ SB.AppendLine(Ident3 + "case 0x" + FunctionName + ": pc = " + Name + "_" + FunctionName + "(); break;");
+ }
+
+ SB.AppendLine(Ident3 + "default:");
+ SB.AppendLine(Ident4 + "pc = 0;");
+ SB.AppendLine(Ident4 + "break;");
+
+ SB.AppendLine(Ident2 + "}");
+ SB.AppendLine(Ident1 + "} while (pc != 0);");
+ }
+
private void PrintAttrToOutput(string Identation = IdentationStr)
{
foreach (KeyValuePair<int, ShaderDeclInfo> KV in Decl.OutAttributes)
@@ -510,193 +546,145 @@ namespace Ryujinx.Graphics.Gal.Shader
}
}
- private void PrintBlockScope(
- ShaderIrBlock Block,
- ShaderIrBlock EndBlock,
- ShaderIrBlock LoopBlock,
- string ScopeName,
- string Identation,
- bool IsDoWhile = false)
+ private void PrintBlockScope(ShaderIrBlock[] Blocks, string Name)
{
- string UpIdent = Identation.Substring(0, Identation.Length - IdentationStr.Length);
-
- if (IsDoWhile)
- {
- SB.AppendLine(UpIdent + "do {");
- }
- else
- {
- SB.AppendLine(UpIdent + ScopeName + " {");
- }
-
- while (Block != null && Block != EndBlock)
+ foreach (ShaderIrBlock Block in Blocks)
{
- ShaderIrNode[] Nodes = Block.GetNodes();
+ SB.AppendLine("uint " + Name + "_" + Block.Position.ToString("x8") + "() {");
- Block = PrintNodes(Block, EndBlock, LoopBlock, Identation, Nodes);
- }
+ PrintNodes(Block, Block.GetNodes());
- if (IsDoWhile)
- {
- SB.AppendLine(UpIdent + "} " + ScopeName + ";");
- }
- else
- {
- SB.AppendLine(UpIdent + "}");
+ SB.AppendLine("}" + Environment.NewLine);
}
}
- private ShaderIrBlock PrintNodes(
- ShaderIrBlock Block,
- ShaderIrBlock EndBlock,
- ShaderIrBlock LoopBlock,
- string Identation,
- params ShaderIrNode[] Nodes)
+ private void PrintNode(ShaderIrBlock Block, ShaderIrNode Node, string Identation)
{
- /*
- * Notes about control flow and if-else/loop generation:
- * The code assumes that the program has sane control flow,
- * that is, there's no jumps to a location after another jump or
- * jump target (except for the end of an if-else block), and backwards
- * jumps to a location before the last loop dominator.
- * Such cases needs to be transformed on a step before the GLSL code
- * generation to ensure that we have sane graphs to work with.
- * TODO: Such transformation is not yet implemented.
- */
- string NewIdent = Identation + IdentationStr;
+ if (Node is ShaderIrCond Cond)
+ {
+ string IfExpr = GetSrcExpr(Cond.Pred, true);
- ShaderIrBlock LoopTail = GetLoopTailBlock(Block);
+ if (Cond.Not)
+ {
+ IfExpr = "!(" + IfExpr + ")";
+ }
- if (LoopTail != null && LoopBlock != Block)
- {
- //Shoock! kuma shock! We have a loop here!
- //The entire sequence needs to be inside a do-while block.
- ShaderIrBlock LoopEnd = GetDownBlock(LoopTail);
+ SB.AppendLine(Identation + "if (" + IfExpr + ") {");
- PrintBlockScope(Block, LoopEnd, Block, "while (false)", NewIdent, IsDoWhile: true);
+ if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
+ {
+ SB.AppendLine(Identation + IdentationStr + "return " + GetBlockPosition(Block.Branch) + ";");
+ }
+ else
+ {
+ PrintNode(Block, Cond.Child, Identation + IdentationStr);
+ }
- return LoopEnd;
+ SB.AppendLine(Identation + "}");
}
-
- foreach (ShaderIrNode Node in Nodes)
+ else if (Node is ShaderIrAsg Asg)
{
- if (Node is ShaderIrCond Cond)
+ if (IsValidOutOper(Asg.Dst))
{
- string IfExpr = GetSrcExpr(Cond.Pred, true);
+ string Expr = GetSrcExpr(Asg.Src, true);
- if (Cond.Not)
+ Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr);
+
+ SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";");
+ }
+ }
+ else if (Node is ShaderIrOp Op)
+ {
+ switch (Op.Inst)
+ {
+ case ShaderIrInst.Bra:
{
- IfExpr = "!(" + IfExpr + ")";
+ SB.AppendLine(Identation + "return " + GetBlockPosition(Block.Branch) + ";");
+
+ break;
}
- if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
+ case ShaderIrInst.Emit:
{
- //Branch is a loop branch and would result in infinite recursion.
- if (Block.Branch.Position <= Block.Position)
- {
- SB.AppendLine(Identation + "if (" + IfExpr + ") {");
-
- SB.AppendLine(Identation + IdentationStr + "continue;");
+ PrintAttrToOutput(Identation);
- SB.AppendLine(Identation + "}");
+ SB.AppendLine(Identation + "EmitVertex();");
- continue;
- }
+ break;
+ }
- string SubScopeName = "if (!" + IfExpr + ")";
+ case ShaderIrInst.Ssy:
+ {
+ string StackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
- PrintBlockScope(Block.Next, Block.Branch, LoopBlock, SubScopeName, NewIdent);
+ int TargetPosition = (Op.OperandA as ShaderIrOperImm).Value;
- ShaderIrBlock IfElseEnd = GetUpBlock(Block.Branch).Branch;
+ string Target = "0x" + TargetPosition.ToString("x8") + "u";
- if (IfElseEnd?.Position > Block.Branch.Position)
- {
- PrintBlockScope(Block.Branch, IfElseEnd, LoopBlock, "else", NewIdent);
+ SB.AppendLine(Identation + StackIndex + " = " + Target + ";");
- return IfElseEnd;
- }
+ SB.AppendLine(Identation + GlslDecl.SsyCursorName + "++;");
- return Block.Branch;
+ break;
}
- else
- {
- SB.AppendLine(Identation + "if (" + IfExpr + ") {");
- PrintNodes(Block, EndBlock, LoopBlock, NewIdent, Cond.Child);
-
- SB.AppendLine(Identation + "}");
- }
- }
- else if (Node is ShaderIrAsg Asg)
- {
- if (IsValidOutOper(Asg.Dst))
+ case ShaderIrInst.Sync:
{
- string Expr = GetSrcExpr(Asg.Src, true);
+ SB.AppendLine(Identation + GlslDecl.SsyCursorName + "--;");
- Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr);
+ string Target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
- SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";");
- }
- }
- else if (Node is ShaderIrOp Op)
- {
- if (Op.Inst == ShaderIrInst.Bra)
- {
- if (Block.Branch.Position <= Block.Position)
- {
- SB.AppendLine(Identation + "continue;");
- }
- }
- else if (Op.Inst == ShaderIrInst.Emit)
- {
- PrintAttrToOutput(Identation);
+ SB.AppendLine(Identation + "return " + Target + ";");
- SB.AppendLine(Identation + "EmitVertex();");
+ break;
}
- else
- {
+
+ default:
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
- }
- }
- else if (Node is ShaderIrCmnt Cmnt)
- {
- SB.AppendLine(Identation + "// " + Cmnt.Comment);
- }
- else
- {
- throw new InvalidOperationException();
+ break;
}
}
-
- return Block.Next;
+ else if (Node is ShaderIrCmnt Cmnt)
+ {
+ SB.AppendLine(Identation + "// " + Cmnt.Comment);
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
}
- private ShaderIrBlock GetUpBlock(ShaderIrBlock Block)
+ private void PrintNodes(ShaderIrBlock Block, ShaderIrNode[] Nodes)
{
- return Blocks.FirstOrDefault(x => x.EndPosition == Block.Position);
- }
+ foreach (ShaderIrNode Node in Nodes)
+ {
+ PrintNode(Block, Node, IdentationStr);
+ }
- private ShaderIrBlock GetDownBlock(ShaderIrBlock Block)
- {
- return Blocks.FirstOrDefault(x => x.Position == Block.EndPosition);
- }
+ if (Nodes.Length > 0)
+ {
+ ShaderIrNode Last = Nodes[Nodes.Length - 1];
- private ShaderIrBlock GetLoopTailBlock(ShaderIrBlock LoopHead)
- {
- ShaderIrBlock Tail = null;
+ bool UnconditionalFlowChange = false;
- foreach (ShaderIrBlock Block in LoopHead.Sources)
- {
- if (Block.Position >= LoopHead.Position)
+ if (Last is ShaderIrOp Op)
{
- if (Tail == null || Tail.Position < Block.Position)
+ switch (Op.Inst)
{
- Tail = Block;
+ case ShaderIrInst.Bra:
+ case ShaderIrInst.Exit:
+ case ShaderIrInst.Kil:
+ case ShaderIrInst.Sync:
+ UnconditionalFlowChange = true;
+ break;
}
}
- }
- return Tail;
+ if (!UnconditionalFlowChange)
+ {
+ SB.AppendLine(IdentationStr + "return " + GetBlockPosition(Block.Next) + ";");
+ }
+ }
}
private bool IsValidOutOper(ShaderIrNode Node)
@@ -1006,7 +994,7 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan");
- private string GetExitExpr(ShaderIrOp Op) => "return";
+ private string GetExitExpr(ShaderIrOp Op) => "return 0u";
private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
@@ -1351,5 +1339,17 @@ namespace Ryujinx.Graphics.Gal.Shader
throw new ArgumentException(nameof(Node));
}
+
+ private static string GetBlockPosition(ShaderIrBlock Block)
+ {
+ if (Block != null)
+ {
+ return "0x" + Block.Position.ToString("x8") + "u";
+ }
+ else
+ {
+ return "0u";
+ }
+ }
}
}