diff options
| author | ReinUsesLisp <reinuseslisp@airmail.cc> | 2018-08-31 13:14:04 -0300 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-08-31 13:14:04 -0300 |
| commit | 42dc925c3da59bf8801b14779482ee5bd9c25dc0 (patch) | |
| tree | 6134135c08fe81414297b75fbf6e1a7479742d07 /Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | |
| parent | 7cb6fd8090513b703da9b83dec04866647694f09 (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.cs | 290 |
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"; + } + } } } |
