Use a program counter to control shaders' flow
This commit is contained in:
parent
056c2840b1
commit
67fb356e9f
2 changed files with 135 additions and 171 deletions
|
@ -158,15 +158,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (BlocksB != null)
|
if (BlocksB != null)
|
||||||
{
|
{
|
||||||
PrintBlockScope(Blocks[0], null, null, "void " + GlslDecl.ProgramAName + "()", IdentationStr);
|
PrintBlockScope(Blocks, "bb_a");
|
||||||
|
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
|
|
||||||
PrintBlockScope(BlocksB[0], null, null, "void " + GlslDecl.ProgramBName + "()", IdentationStr);
|
PrintBlockScope(BlocksB, "bb_b");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PrintBlockScope(Blocks[0], null, null, "void " + GlslDecl.ProgramName + "()", IdentationStr);
|
PrintBlockScope(Blocks, "bb");
|
||||||
}
|
}
|
||||||
|
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
|
@ -241,7 +241,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
if (Decl.ShaderType == GalShaderType.Vertex)
|
if (Decl.ShaderType == GalShaderType.Vertex)
|
||||||
{
|
{
|
||||||
SB.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + "{");
|
SB.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + " {");
|
||||||
|
|
||||||
SB.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";");
|
SB.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";");
|
||||||
|
|
||||||
|
@ -417,14 +417,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SB.AppendLine(IdentationStr + "uint pc;");
|
||||||
|
|
||||||
if (BlocksB != null)
|
if (BlocksB != null)
|
||||||
{
|
{
|
||||||
SB.AppendLine(IdentationStr + GlslDecl.ProgramAName + "();");
|
PrintProgram(Blocks, "bb_a");
|
||||||
SB.AppendLine(IdentationStr + GlslDecl.ProgramBName + "();");
|
PrintProgram(BlocksB, "bb_b");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SB.AppendLine(IdentationStr + GlslDecl.ProgramName + "();");
|
PrintProgram(Blocks, "bb");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Decl.ShaderType != GalShaderType.Geometry)
|
if (Decl.ShaderType != GalShaderType.Geometry)
|
||||||
|
@ -435,6 +437,37 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
SB.AppendLine("}");
|
SB.AppendLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PrintProgram(ShaderIrBlock[] Blocks, string Name)
|
||||||
|
{
|
||||||
|
string Ident1 = IdentationStr;
|
||||||
|
string Ident2 = Ident1 + IdentationStr;
|
||||||
|
string Ident3 = Ident2 + IdentationStr;
|
||||||
|
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)
|
private void PrintAttrToOutput(string Identation = IdentationStr)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<int, ShaderDeclInfo> KV in Decl.OutAttributes)
|
foreach (KeyValuePair<int, ShaderDeclInfo> KV in Decl.OutAttributes)
|
||||||
|
@ -468,193 +501,112 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintBlockScope(
|
private void PrintBlockScope(ShaderIrBlock[] Blocks, string Name)
|
||||||
ShaderIrBlock Block,
|
|
||||||
ShaderIrBlock EndBlock,
|
|
||||||
ShaderIrBlock LoopBlock,
|
|
||||||
string ScopeName,
|
|
||||||
string Identation,
|
|
||||||
bool IsDoWhile = false)
|
|
||||||
{
|
{
|
||||||
string UpIdent = Identation.Substring(0, Identation.Length - IdentationStr.Length);
|
foreach (ShaderIrBlock Block in Blocks)
|
||||||
|
{
|
||||||
|
SB.AppendLine("uint " + Name + "_" + Block.Position.ToString("x8") + "() {");
|
||||||
|
|
||||||
if (IsDoWhile)
|
PrintNodes(Block, Block.GetNodes());
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + "do {");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + ScopeName + " {");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (Block != null && Block != EndBlock)
|
SB.AppendLine("}" + Environment.NewLine);
|
||||||
{
|
|
||||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
|
||||||
|
|
||||||
Block = PrintNodes(Block, EndBlock, LoopBlock, Identation, Nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDoWhile)
|
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + "} " + ScopeName + ";");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + "}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShaderIrBlock PrintNodes(
|
private void PrintNode(ShaderIrBlock Block, ShaderIrNode Node, string Identation)
|
||||||
ShaderIrBlock Block,
|
|
||||||
ShaderIrBlock EndBlock,
|
|
||||||
ShaderIrBlock LoopBlock,
|
|
||||||
string Identation,
|
|
||||||
params ShaderIrNode[] Nodes)
|
|
||||||
{
|
{
|
||||||
/*
|
if (Node is ShaderIrCond Cond)
|
||||||
* 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;
|
|
||||||
|
|
||||||
ShaderIrBlock LoopTail = GetLoopTailBlock(Block);
|
|
||||||
|
|
||||||
if (LoopTail != null && LoopBlock != Block)
|
|
||||||
{
|
{
|
||||||
//Shoock! kuma shock! We have a loop here!
|
string IfExpr = GetSrcExpr(Cond.Pred, true);
|
||||||
//The entire sequence needs to be inside a do-while block.
|
|
||||||
ShaderIrBlock LoopEnd = GetDownBlock(LoopTail);
|
|
||||||
|
|
||||||
PrintBlockScope(Block, LoopEnd, Block, "while (false)", NewIdent, IsDoWhile: true);
|
if (Cond.Not)
|
||||||
|
|
||||||
return LoopEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Nodes)
|
|
||||||
{
|
|
||||||
if (Node is ShaderIrCond Cond)
|
|
||||||
{
|
{
|
||||||
string IfExpr = GetSrcExpr(Cond.Pred, true);
|
IfExpr = "!(" + IfExpr + ")";
|
||||||
|
|
||||||
if (Cond.Not)
|
|
||||||
{
|
|
||||||
IfExpr = "!(" + IfExpr + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
|
|
||||||
{
|
|
||||||
//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;");
|
|
||||||
|
|
||||||
SB.AppendLine(Identation + "}");
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string SubScopeName = "if (!" + IfExpr + ")";
|
|
||||||
|
|
||||||
PrintBlockScope(Block.Next, Block.Branch, LoopBlock, SubScopeName, NewIdent);
|
|
||||||
|
|
||||||
ShaderIrBlock IfElseEnd = GetUpBlock(Block.Branch).Branch;
|
|
||||||
|
|
||||||
if (IfElseEnd?.Position > Block.Branch.Position)
|
|
||||||
{
|
|
||||||
PrintBlockScope(Block.Branch, IfElseEnd, LoopBlock, "else", NewIdent);
|
|
||||||
|
|
||||||
return IfElseEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Block.Branch;
|
|
||||||
}
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
string Expr = GetSrcExpr(Asg.Src, true);
|
|
||||||
|
|
||||||
Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr);
|
SB.AppendLine(Identation + "if (" + IfExpr + ") {");
|
||||||
|
|
||||||
SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";");
|
if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Node is ShaderIrOp Op)
|
|
||||||
{
|
{
|
||||||
if (Op.Inst == ShaderIrInst.Bra)
|
SB.AppendLine(Identation + IdentationStr + "return " + GetBlockPosition(Block.Branch) + ";");
|
||||||
{
|
|
||||||
if (Block.Branch.Position <= Block.Position)
|
|
||||||
{
|
|
||||||
SB.AppendLine(Identation + "continue;");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Op.Inst == ShaderIrInst.Emit)
|
|
||||||
{
|
|
||||||
PrintAttrToOutput(Identation);
|
|
||||||
|
|
||||||
SB.AppendLine(Identation + "EmitVertex();");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Node is ShaderIrCmnt Cmnt)
|
|
||||||
{
|
|
||||||
SB.AppendLine(Identation + "// " + Cmnt.Comment);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
PrintNode(Block, Cond.Child, Identation + IdentationStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SB.AppendLine(Identation + "}");
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrAsg Asg)
|
||||||
|
{
|
||||||
|
if (IsValidOutOper(Asg.Dst))
|
||||||
|
{
|
||||||
|
string Expr = GetSrcExpr(Asg.Src, true);
|
||||||
|
|
||||||
|
Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr);
|
||||||
|
|
||||||
|
SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (Node is ShaderIrOp Op)
|
||||||
return Block.Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderIrBlock GetUpBlock(ShaderIrBlock Block)
|
|
||||||
{
|
|
||||||
return Blocks.FirstOrDefault(x => x.EndPosition == Block.Position);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderIrBlock GetDownBlock(ShaderIrBlock Block)
|
|
||||||
{
|
|
||||||
return Blocks.FirstOrDefault(x => x.Position == Block.EndPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderIrBlock GetLoopTailBlock(ShaderIrBlock LoopHead)
|
|
||||||
{
|
|
||||||
ShaderIrBlock Tail = null;
|
|
||||||
|
|
||||||
foreach (ShaderIrBlock Block in LoopHead.Sources)
|
|
||||||
{
|
{
|
||||||
if (Block.Position >= LoopHead.Position)
|
if (Op.Inst == ShaderIrInst.Bra)
|
||||||
{
|
{
|
||||||
if (Tail == null || Tail.Position < Block.Position)
|
SB.AppendLine(Identation + "return " + GetBlockPosition(Block.Branch) + ";");
|
||||||
|
}
|
||||||
|
else if (Op.Inst == ShaderIrInst.Emit)
|
||||||
|
{
|
||||||
|
PrintAttrToOutput(Identation);
|
||||||
|
|
||||||
|
SB.AppendLine(Identation + "EmitVertex();");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrCmnt Cmnt)
|
||||||
|
{
|
||||||
|
SB.AppendLine(Identation + "// " + Cmnt.Comment);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintNodes(ShaderIrBlock Block, ShaderIrNode[] Nodes)
|
||||||
|
{
|
||||||
|
foreach (ShaderIrNode Node in Nodes)
|
||||||
|
{
|
||||||
|
PrintNode(Block, Node, IdentationStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Nodes.Length > 0)
|
||||||
|
{
|
||||||
|
ShaderIrNode Last = Nodes[Nodes.Length - 1];
|
||||||
|
|
||||||
|
bool TailBranch = false;
|
||||||
|
|
||||||
|
if (Last is ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
switch (Op.Inst)
|
||||||
{
|
{
|
||||||
Tail = Block;
|
case ShaderIrInst.Bra:
|
||||||
|
case ShaderIrInst.Exit:
|
||||||
|
case ShaderIrInst.Kil:
|
||||||
|
TailBranch = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return Tail;
|
if (!TailBranch)
|
||||||
|
{
|
||||||
|
SB.AppendLine(IdentationStr + "// Jump to next block");
|
||||||
|
|
||||||
|
SB.AppendLine(IdentationStr + "return " + GetBlockPosition(Block.Next) + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsValidOutOper(ShaderIrNode Node)
|
private bool IsValidOutOper(ShaderIrNode Node)
|
||||||
|
@ -961,7 +913,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan");
|
private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan");
|
||||||
|
|
||||||
private string GetExitExpr(ShaderIrOp Op) => "return";
|
private string GetExitExpr(ShaderIrOp Op) => "return 0";
|
||||||
|
|
||||||
private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
|
private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
|
||||||
|
|
||||||
|
@ -1306,5 +1258,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Node));
|
throw new ArgumentException(nameof(Node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetBlockPosition(ShaderIrBlock Block)
|
||||||
|
{
|
||||||
|
if (Block != null)
|
||||||
|
{
|
||||||
|
return "0x" + Block.Position.ToString("x8") + "u";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "0u";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
||||||
|
|
||||||
long Target = Position + Offset;
|
long Target = Position + Offset - Beginning;
|
||||||
|
|
||||||
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue