From 42dc925c3da59bf8801b14779482ee5bd9c25dc0 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 31 Aug 2018 13:14:04 -0300 Subject: [PATCH] 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 --- Ryujinx.Graphics/Gal/Shader/GlslDecl.cs | 10 +- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 324 +++++++++--------- Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs | 2 +- .../Gal/Shader/ShaderDecodeAlu.cs | 128 +++---- .../Gal/Shader/ShaderDecodeFlow.cs | 31 +- .../Gal/Shader/ShaderDecodeMem.cs | 16 +- .../Gal/Shader/ShaderDecodeMove.cs | 42 +-- .../Gal/Shader/ShaderDecodeSpecial.cs | 2 +- Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs | 22 +- Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs | 2 + .../Gal/Shader/ShaderOpCodeTable.cs | 2 + 11 files changed, 313 insertions(+), 268 deletions(-) diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index c22a282dcc..c837632ec2 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -43,9 +43,13 @@ namespace Ryujinx.Graphics.Gal.Shader public const string FlipUniformName = "flip"; public const string InstanceUniformName = "instance"; - public const string ProgramName = "program"; - public const string ProgramAName = ProgramName + "_a"; - public const string ProgramBName = ProgramName + "_b"; + public const string BasicBlockName = "bb"; + public const string BasicBlockAName = BasicBlockName + "_a"; + public const string BasicBlockBName = BasicBlockName + "_b"; + + public const int SsyStackSize = 16; + public const string SsyStackName = "ssy_stack"; + public const string SsyCursorName = "ssy_cursor"; private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 984684f16b..104fd72354 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 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 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); + foreach (ShaderIrBlock Block in Blocks) + { + SB.AppendLine("uint " + Name + "_" + Block.Position.ToString("x8") + "() {"); - if (IsDoWhile) - { - SB.AppendLine(UpIdent + "do {"); - } - else - { - SB.AppendLine(UpIdent + ScopeName + " {"); - } + PrintNodes(Block, Block.GetNodes()); - while (Block != null && Block != EndBlock) - { - ShaderIrNode[] Nodes = Block.GetNodes(); - - Block = PrintNodes(Block, EndBlock, LoopBlock, Identation, Nodes); - } - - 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; - - ShaderIrBlock LoopTail = GetLoopTailBlock(Block); - - if (LoopTail != null && LoopBlock != Block) + if (Node is ShaderIrCond Cond) { - //Shoock! kuma shock! We have a loop here! - //The entire sequence needs to be inside a do-while block. - ShaderIrBlock LoopEnd = GetDownBlock(LoopTail); + string IfExpr = GetSrcExpr(Cond.Pred, true); - PrintBlockScope(Block, LoopEnd, Block, "while (false)", NewIdent, IsDoWhile: true); + if (Cond.Not) + { + IfExpr = "!(" + IfExpr + ")"; + } - return LoopEnd; + SB.AppendLine(Identation + "if (" + IfExpr + ") {"); + + 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); + } + + 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) - { - IfExpr = "!(" + IfExpr + ")"; - } + Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr); - 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 + "}"); - } + SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";"); } - else if (Node is ShaderIrAsg Asg) + } + else if (Node is ShaderIrOp Op) + { + switch (Op.Inst) { - if (IsValidOutOper(Asg.Dst)) + case ShaderIrInst.Bra: { - string Expr = GetSrcExpr(Asg.Src, true); + SB.AppendLine(Identation + "return " + GetBlockPosition(Block.Branch) + ";"); - Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr); + break; + } - 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) + case ShaderIrInst.Emit: { PrintAttrToOutput(Identation); SB.AppendLine(Identation + "EmitVertex();"); + + break; } - else + + case ShaderIrInst.Ssy: { + string StackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; + + int TargetPosition = (Op.OperandA as ShaderIrOperImm).Value; + + string Target = "0x" + TargetPosition.ToString("x8") + "u"; + + SB.AppendLine(Identation + StackIndex + " = " + Target + ";"); + + SB.AppendLine(Identation + GlslDecl.SsyCursorName + "++;"); + + break; + } + + case ShaderIrInst.Sync: + { + SB.AppendLine(Identation + GlslDecl.SsyCursorName + "--;"); + + string Target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; + + SB.AppendLine(Identation + "return " + Target + ";"); + + break; + } + + 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; - } - - 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) + else if (Node is ShaderIrCmnt Cmnt) { - if (Block.Position >= LoopHead.Position) - { - if (Tail == null || Tail.Position < Block.Position) - { - Tail = Block; - } - } + 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); } - return Tail; + if (Nodes.Length > 0) + { + ShaderIrNode Last = Nodes[Nodes.Length - 1]; + + bool UnconditionalFlowChange = false; + + if (Last is ShaderIrOp Op) + { + switch (Op.Inst) + { + case ShaderIrInst.Bra: + case ShaderIrInst.Exit: + case ShaderIrInst.Kil: + case ShaderIrInst.Sync: + UnconditionalFlowChange = true; + break; + } + } + + 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"; + } + } } } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs index ef0fd78bd3..73625f65fe 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs @@ -1,4 +1,4 @@ namespace Ryujinx.Graphics.Gal.Shader { - delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode); + delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, long Position); } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index b60da7c1c3..5eb761dab6 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -6,32 +6,32 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - public static void Bfe_C(ShaderIrBlock Block, long OpCode) + public static void Bfe_C(ShaderIrBlock Block, long OpCode, long Position) { EmitBfe(Block, OpCode, ShaderOper.CR); } - public static void Bfe_I(ShaderIrBlock Block, long OpCode) + public static void Bfe_I(ShaderIrBlock Block, long OpCode, long Position) { EmitBfe(Block, OpCode, ShaderOper.Imm); } - public static void Bfe_R(ShaderIrBlock Block, long OpCode) + public static void Bfe_R(ShaderIrBlock Block, long OpCode, long Position) { EmitBfe(Block, OpCode, ShaderOper.RR); } - public static void Fadd_C(ShaderIrBlock Block, long OpCode) + public static void Fadd_C(ShaderIrBlock Block, long OpCode, long Position) { EmitFadd(Block, OpCode, ShaderOper.CR); } - public static void Fadd_I(ShaderIrBlock Block, long OpCode) + public static void Fadd_I(ShaderIrBlock Block, long OpCode, long Position) { EmitFadd(Block, OpCode, ShaderOper.Immf); } - public static void Fadd_I32(ShaderIrBlock Block, long OpCode) + public static void Fadd_I32(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode OperA = GetOperGpr8 (OpCode); ShaderIrNode OperB = GetOperImmf32_20(OpCode); @@ -49,47 +49,47 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } - public static void Fadd_R(ShaderIrBlock Block, long OpCode) + public static void Fadd_R(ShaderIrBlock Block, long OpCode, long Position) { EmitFadd(Block, OpCode, ShaderOper.RR); } - public static void Ffma_CR(ShaderIrBlock Block, long OpCode) + public static void Ffma_CR(ShaderIrBlock Block, long OpCode, long Position) { EmitFfma(Block, OpCode, ShaderOper.CR); } - public static void Ffma_I(ShaderIrBlock Block, long OpCode) + public static void Ffma_I(ShaderIrBlock Block, long OpCode, long Position) { EmitFfma(Block, OpCode, ShaderOper.Immf); } - public static void Ffma_RC(ShaderIrBlock Block, long OpCode) + public static void Ffma_RC(ShaderIrBlock Block, long OpCode, long Position) { EmitFfma(Block, OpCode, ShaderOper.RC); } - public static void Ffma_RR(ShaderIrBlock Block, long OpCode) + public static void Ffma_RR(ShaderIrBlock Block, long OpCode, long Position) { EmitFfma(Block, OpCode, ShaderOper.RR); } - public static void Fmnmx_C(ShaderIrBlock Block, long OpCode) + public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, long Position) { EmitFmnmx(Block, OpCode, ShaderOper.CR); } - public static void Fmnmx_I(ShaderIrBlock Block, long OpCode) + public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, long Position) { EmitFmnmx(Block, OpCode, ShaderOper.Immf); } - public static void Fmnmx_R(ShaderIrBlock Block, long OpCode) + public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, long Position) { EmitFmnmx(Block, OpCode, ShaderOper.RR); } - public static void Fmul_I32(ShaderIrBlock Block, long OpCode) + public static void Fmul_I32(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode OperA = GetOperGpr8 (OpCode); ShaderIrNode OperB = GetOperImmf32_20(OpCode); @@ -99,62 +99,62 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } - public static void Fmul_C(ShaderIrBlock Block, long OpCode) + public static void Fmul_C(ShaderIrBlock Block, long OpCode, long Position) { EmitFmul(Block, OpCode, ShaderOper.CR); } - public static void Fmul_I(ShaderIrBlock Block, long OpCode) + public static void Fmul_I(ShaderIrBlock Block, long OpCode, long Position) { EmitFmul(Block, OpCode, ShaderOper.Immf); } - public static void Fmul_R(ShaderIrBlock Block, long OpCode) + public static void Fmul_R(ShaderIrBlock Block, long OpCode, long Position) { EmitFmul(Block, OpCode, ShaderOper.RR); } - public static void Fset_C(ShaderIrBlock Block, long OpCode) + public static void Fset_C(ShaderIrBlock Block, long OpCode, long Position) { EmitFset(Block, OpCode, ShaderOper.CR); } - public static void Fset_I(ShaderIrBlock Block, long OpCode) + public static void Fset_I(ShaderIrBlock Block, long OpCode, long Position) { EmitFset(Block, OpCode, ShaderOper.Immf); } - public static void Fset_R(ShaderIrBlock Block, long OpCode) + public static void Fset_R(ShaderIrBlock Block, long OpCode, long Position) { EmitFset(Block, OpCode, ShaderOper.RR); } - public static void Fsetp_C(ShaderIrBlock Block, long OpCode) + public static void Fsetp_C(ShaderIrBlock Block, long OpCode, long Position) { EmitFsetp(Block, OpCode, ShaderOper.CR); } - public static void Fsetp_I(ShaderIrBlock Block, long OpCode) + public static void Fsetp_I(ShaderIrBlock Block, long OpCode, long Position) { EmitFsetp(Block, OpCode, ShaderOper.Immf); } - public static void Fsetp_R(ShaderIrBlock Block, long OpCode) + public static void Fsetp_R(ShaderIrBlock Block, long OpCode, long Position) { EmitFsetp(Block, OpCode, ShaderOper.RR); } - public static void Iadd_C(ShaderIrBlock Block, long OpCode) + public static void Iadd_C(ShaderIrBlock Block, long OpCode, long Position) { EmitIadd(Block, OpCode, ShaderOper.CR); } - public static void Iadd_I(ShaderIrBlock Block, long OpCode) + public static void Iadd_I(ShaderIrBlock Block, long OpCode, long Position) { EmitIadd(Block, OpCode, ShaderOper.Imm); } - public static void Iadd_I32(ShaderIrBlock Block, long OpCode) + public static void Iadd_I32(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode OperA = GetOperGpr8 (OpCode); ShaderIrNode OperB = GetOperImm32_20(OpCode); @@ -168,42 +168,42 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } - public static void Iadd_R(ShaderIrBlock Block, long OpCode) + public static void Iadd_R(ShaderIrBlock Block, long OpCode, long Position) { EmitIadd(Block, OpCode, ShaderOper.RR); } - public static void Iadd3_C(ShaderIrBlock Block, long OpCode) + public static void Iadd3_C(ShaderIrBlock Block, long OpCode, long Position) { EmitIadd3(Block, OpCode, ShaderOper.CR); } - public static void Iadd3_I(ShaderIrBlock Block, long OpCode) + public static void Iadd3_I(ShaderIrBlock Block, long OpCode, long Position) { EmitIadd3(Block, OpCode, ShaderOper.Imm); } - public static void Iadd3_R(ShaderIrBlock Block, long OpCode) + public static void Iadd3_R(ShaderIrBlock Block, long OpCode, long Position) { EmitIadd3(Block, OpCode, ShaderOper.RR); } - public static void Imnmx_C(ShaderIrBlock Block, long OpCode) + public static void Imnmx_C(ShaderIrBlock Block, long OpCode, long Position) { EmitImnmx(Block, OpCode, ShaderOper.CR); } - public static void Imnmx_I(ShaderIrBlock Block, long OpCode) + public static void Imnmx_I(ShaderIrBlock Block, long OpCode, long Position) { EmitImnmx(Block, OpCode, ShaderOper.Imm); } - public static void Imnmx_R(ShaderIrBlock Block, long OpCode) + public static void Imnmx_R(ShaderIrBlock Block, long OpCode, long Position) { EmitImnmx(Block, OpCode, ShaderOper.RR); } - public static void Ipa(ShaderIrBlock Block, long OpCode) + public static void Ipa(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode OperA = GetOperAbuf28(OpCode); ShaderIrNode OperB = GetOperGpr20 (OpCode); @@ -213,52 +213,52 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } - public static void Iscadd_C(ShaderIrBlock Block, long OpCode) + public static void Iscadd_C(ShaderIrBlock Block, long OpCode, long Position) { EmitIscadd(Block, OpCode, ShaderOper.CR); } - public static void Iscadd_I(ShaderIrBlock Block, long OpCode) + public static void Iscadd_I(ShaderIrBlock Block, long OpCode, long Position) { EmitIscadd(Block, OpCode, ShaderOper.Imm); } - public static void Iscadd_R(ShaderIrBlock Block, long OpCode) + public static void Iscadd_R(ShaderIrBlock Block, long OpCode, long Position) { EmitIscadd(Block, OpCode, ShaderOper.RR); } - public static void Iset_C(ShaderIrBlock Block, long OpCode) + public static void Iset_C(ShaderIrBlock Block, long OpCode, long Position) { EmitIset(Block, OpCode, ShaderOper.CR); } - public static void Iset_I(ShaderIrBlock Block, long OpCode) + public static void Iset_I(ShaderIrBlock Block, long OpCode, long Position) { EmitIset(Block, OpCode, ShaderOper.Imm); } - public static void Iset_R(ShaderIrBlock Block, long OpCode) + public static void Iset_R(ShaderIrBlock Block, long OpCode, long Position) { EmitIset(Block, OpCode, ShaderOper.RR); } - public static void Isetp_C(ShaderIrBlock Block, long OpCode) + public static void Isetp_C(ShaderIrBlock Block, long OpCode, long Position) { EmitIsetp(Block, OpCode, ShaderOper.CR); } - public static void Isetp_I(ShaderIrBlock Block, long OpCode) + public static void Isetp_I(ShaderIrBlock Block, long OpCode, long Position) { EmitIsetp(Block, OpCode, ShaderOper.Imm); } - public static void Isetp_R(ShaderIrBlock Block, long OpCode) + public static void Isetp_R(ShaderIrBlock Block, long OpCode, long Position) { EmitIsetp(Block, OpCode, ShaderOper.RR); } - public static void Lop_I32(ShaderIrBlock Block, long OpCode) + public static void Lop_I32(ShaderIrBlock Block, long OpCode, long Position) { int SubOp = (int)(OpCode >> 53) & 3; @@ -292,22 +292,22 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Lop_C(ShaderIrBlock Block, long OpCode) + public static void Lop_C(ShaderIrBlock Block, long OpCode, long Position) { EmitLop(Block, OpCode, ShaderOper.CR); } - public static void Lop_I(ShaderIrBlock Block, long OpCode) + public static void Lop_I(ShaderIrBlock Block, long OpCode, long Position) { EmitLop(Block, OpCode, ShaderOper.Imm); } - public static void Lop_R(ShaderIrBlock Block, long OpCode) + public static void Lop_R(ShaderIrBlock Block, long OpCode, long Position) { EmitLop(Block, OpCode, ShaderOper.RR); } - public static void Mufu(ShaderIrBlock Block, long OpCode) + public static void Mufu(ShaderIrBlock Block, long OpCode, long Position) { int SubOp = (int)(OpCode >> 20) & 0xf; @@ -336,7 +336,7 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } - public static void Psetp(ShaderIrBlock Block, long OpCode) + public static void Psetp(ShaderIrBlock Block, long OpCode, long Position) { bool NegA = ((OpCode >> 15) & 1) != 0; bool NegB = ((OpCode >> 32) & 1) != 0; @@ -390,47 +390,47 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode)); } - public static void Rro_C(ShaderIrBlock Block, long OpCode) + public static void Rro_C(ShaderIrBlock Block, long OpCode, long Position) { EmitRro(Block, OpCode, ShaderOper.CR); } - public static void Rro_I(ShaderIrBlock Block, long OpCode) + public static void Rro_I(ShaderIrBlock Block, long OpCode, long Position) { EmitRro(Block, OpCode, ShaderOper.Immf); } - public static void Rro_R(ShaderIrBlock Block, long OpCode) + public static void Rro_R(ShaderIrBlock Block, long OpCode, long Position) { EmitRro(Block, OpCode, ShaderOper.RR); } - public static void Shl_C(ShaderIrBlock Block, long OpCode) + public static void Shl_C(ShaderIrBlock Block, long OpCode, long Position) { EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl); } - public static void Shl_I(ShaderIrBlock Block, long OpCode) + public static void Shl_I(ShaderIrBlock Block, long OpCode, long Position) { EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl); } - public static void Shl_R(ShaderIrBlock Block, long OpCode) + public static void Shl_R(ShaderIrBlock Block, long OpCode, long Position) { EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl); } - public static void Shr_C(ShaderIrBlock Block, long OpCode) + public static void Shr_C(ShaderIrBlock Block, long OpCode, long Position) { EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode)); } - public static void Shr_I(ShaderIrBlock Block, long OpCode) + public static void Shr_I(ShaderIrBlock Block, long OpCode, long Position) { EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode)); } - public static void Shr_R(ShaderIrBlock Block, long OpCode) + public static void Shr_R(ShaderIrBlock Block, long OpCode, long Position) { EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode)); } @@ -442,7 +442,7 @@ namespace Ryujinx.Graphics.Gal.Shader return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; } - public static void Vmad(ShaderIrBlock Block, long OpCode) + public static void Vmad(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode OperA = GetOperGpr8(OpCode); @@ -477,22 +477,22 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Final), OpCode)); } - public static void Xmad_CR(ShaderIrBlock Block, long OpCode) + public static void Xmad_CR(ShaderIrBlock Block, long OpCode, long Position) { EmitXmad(Block, OpCode, ShaderOper.CR); } - public static void Xmad_I(ShaderIrBlock Block, long OpCode) + public static void Xmad_I(ShaderIrBlock Block, long OpCode, long Position) { EmitXmad(Block, OpCode, ShaderOper.Imm); } - public static void Xmad_RC(ShaderIrBlock Block, long OpCode) + public static void Xmad_RC(ShaderIrBlock Block, long OpCode, long Position) { EmitXmad(Block, OpCode, ShaderOper.RC); } - public static void Xmad_RR(ShaderIrBlock Block, long OpCode) + public static void Xmad_RR(ShaderIrBlock Block, long OpCode, long Position) { EmitXmad(Block, OpCode, ShaderOper.RR); } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs index 8d0925a321..2c699a1b82 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs @@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - public static void Bra(ShaderIrBlock Block, long OpCode) + public static void Bra(ShaderIrBlock Block, long OpCode, long Position) { if ((OpCode & 0x20) != 0) { @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm), OpCode)); } - public static void Exit(ShaderIrBlock Block, long OpCode) + public static void Exit(ShaderIrBlock Block, long OpCode, long Position) { int CCode = (int)OpCode & 0x1f; @@ -34,9 +34,34 @@ namespace Ryujinx.Graphics.Gal.Shader } - public static void Kil(ShaderIrBlock Block, long OpCode) + public static void Kil(ShaderIrBlock Block, long OpCode, long Position) { Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Kil), OpCode)); } + + public static void Ssy(ShaderIrBlock Block, long OpCode, long Position) + { + if ((OpCode & 0x20) != 0) + { + //This reads the target offset from the constant buffer. + //Almost impossible to support with GLSL. + throw new NotImplementedException(); + } + + int Offset = ((int)(OpCode >> 20) << 8) >> 8; + + int Target = (int)(Position + Offset); + + ShaderIrOperImm Imm = new ShaderIrOperImm(Target); + + Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm)); + } + + public static void Sync(ShaderIrBlock Block, long OpCode, long Position) + { + //TODO: Implement Sync condition codes + + Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Sync), OpCode)); + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index a183b0c69a..2ae58bf89d 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Gal.Shader { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } }; - public static void Ld_A(ShaderIrBlock Block, long OpCode) + public static void Ld_A(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode[] Opers = GetOperAbuf20(OpCode); @@ -50,7 +50,7 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Ld_C(ShaderIrBlock Block, long OpCode) + public static void Ld_C(ShaderIrBlock Block, long OpCode, long Position) { int CbufPos = (int)(OpCode >> 22) & 0x3fff; int CbufIndex = (int)(OpCode >> 36) & 0x1f; @@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void St_A(ShaderIrBlock Block, long OpCode) + public static void St_A(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode[] Opers = GetOperAbuf20(OpCode); @@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Texq(ShaderIrBlock Block, long OpCode) + public static void Texq(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrNode OperD = GetOperGpr0(OpCode); ShaderIrNode OperA = GetOperGpr8(OpCode); @@ -132,12 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right? } - public static void Tex(ShaderIrBlock Block, long OpCode) + public static void Tex(ShaderIrBlock Block, long OpCode, long Position) { EmitTex(Block, OpCode, GprHandle: false); } - public static void Tex_B(ShaderIrBlock Block, long OpCode) + public static void Tex_B(ShaderIrBlock Block, long OpCode, long Position) { EmitTex(Block, OpCode, GprHandle: true); } @@ -202,12 +202,12 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Texs(ShaderIrBlock Block, long OpCode) + public static void Texs(ShaderIrBlock Block, long OpCode, long Position) { EmitTexs(Block, OpCode, ShaderIrInst.Texs); } - public static void Tlds(ShaderIrBlock Block, long OpCode) + public static void Tlds(ShaderIrBlock Block, long OpCode, long Position) { EmitTexs(Block, OpCode, ShaderIrInst.Txlf); } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs index c6b71fb01a..aef92c5a90 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs @@ -25,67 +25,67 @@ namespace Ryujinx.Graphics.Gal.Shader F64 = 3 } - public static void F2f_C(ShaderIrBlock Block, long OpCode) + public static void F2f_C(ShaderIrBlock Block, long OpCode, long Position) { EmitF2f(Block, OpCode, ShaderOper.CR); } - public static void F2f_I(ShaderIrBlock Block, long OpCode) + public static void F2f_I(ShaderIrBlock Block, long OpCode, long Position) { EmitF2f(Block, OpCode, ShaderOper.Immf); } - public static void F2f_R(ShaderIrBlock Block, long OpCode) + public static void F2f_R(ShaderIrBlock Block, long OpCode, long Position) { EmitF2f(Block, OpCode, ShaderOper.RR); } - public static void F2i_C(ShaderIrBlock Block, long OpCode) + public static void F2i_C(ShaderIrBlock Block, long OpCode, long Position) { EmitF2i(Block, OpCode, ShaderOper.CR); } - public static void F2i_I(ShaderIrBlock Block, long OpCode) + public static void F2i_I(ShaderIrBlock Block, long OpCode, long Position) { EmitF2i(Block, OpCode, ShaderOper.Immf); } - public static void F2i_R(ShaderIrBlock Block, long OpCode) + public static void F2i_R(ShaderIrBlock Block, long OpCode, long Position) { EmitF2i(Block, OpCode, ShaderOper.RR); } - public static void I2f_C(ShaderIrBlock Block, long OpCode) + public static void I2f_C(ShaderIrBlock Block, long OpCode, long Position) { EmitI2f(Block, OpCode, ShaderOper.CR); } - public static void I2f_I(ShaderIrBlock Block, long OpCode) + public static void I2f_I(ShaderIrBlock Block, long OpCode, long Position) { EmitI2f(Block, OpCode, ShaderOper.Imm); } - public static void I2f_R(ShaderIrBlock Block, long OpCode) + public static void I2f_R(ShaderIrBlock Block, long OpCode, long Position) { EmitI2f(Block, OpCode, ShaderOper.RR); } - public static void I2i_C(ShaderIrBlock Block, long OpCode) + public static void I2i_C(ShaderIrBlock Block, long OpCode, long Position) { EmitI2i(Block, OpCode, ShaderOper.CR); } - public static void I2i_I(ShaderIrBlock Block, long OpCode) + public static void I2i_I(ShaderIrBlock Block, long OpCode, long Position) { EmitI2i(Block, OpCode, ShaderOper.Imm); } - public static void I2i_R(ShaderIrBlock Block, long OpCode) + public static void I2i_R(ShaderIrBlock Block, long OpCode, long Position) { EmitI2i(Block, OpCode, ShaderOper.RR); } - public static void Isberd(ShaderIrBlock Block, long OpCode) + public static void Isberd(ShaderIrBlock Block, long OpCode, long Position) { //This instruction seems to be used to translate from an address to a vertex index in a GS //Stub it as such @@ -95,50 +95,50 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), GetOperGpr8(OpCode)), OpCode)); } - public static void Mov_C(ShaderIrBlock Block, long OpCode) + public static void Mov_C(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Cbuf), OpCode)); } - public static void Mov_I(ShaderIrBlock Block, long OpCode) + public static void Mov_I(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrOperImm Imm = GetOperImm19_20(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode)); } - public static void Mov_I32(ShaderIrBlock Block, long OpCode) + public static void Mov_I32(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrOperImm Imm = GetOperImm32_20(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode)); } - public static void Mov_R(ShaderIrBlock Block, long OpCode) + public static void Mov_R(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrOperGpr Gpr = GetOperGpr20(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode)); } - public static void Sel_C(ShaderIrBlock Block, long OpCode) + public static void Sel_C(ShaderIrBlock Block, long OpCode, long Position) { EmitSel(Block, OpCode, ShaderOper.CR); } - public static void Sel_I(ShaderIrBlock Block, long OpCode) + public static void Sel_I(ShaderIrBlock Block, long OpCode, long Position) { EmitSel(Block, OpCode, ShaderOper.Imm); } - public static void Sel_R(ShaderIrBlock Block, long OpCode) + public static void Sel_R(ShaderIrBlock Block, long OpCode, long Position) { EmitSel(Block, OpCode, ShaderOper.RR); } - public static void Mov_S(ShaderIrBlock Block, long OpCode) + public static void Mov_S(ShaderIrBlock Block, long OpCode, long Position) { Block.AddNode(new ShaderIrCmnt("Stubbed.")); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs index f1be005f9c..4300c32e32 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs @@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - public static void Out_R(ShaderIrBlock Block, long OpCode) + public static void Out_R(ShaderIrBlock Block, long OpCode, long Position) { //TODO: Those registers have to be used for something ShaderIrOperGpr Gpr0 = GetOperGpr0(OpCode); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs index 98f371b573..81d8f31268 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs @@ -50,17 +50,29 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrNode LastNode = Current.GetLastNode(); - ShaderIrOp Op = GetInnermostOp(LastNode); + ShaderIrOp InnerOp = GetInnermostOp(LastNode); - if (Op?.Inst == ShaderIrInst.Bra) + if (InnerOp?.Inst == ShaderIrInst.Bra) { - int Offset = ((ShaderIrOperImm)Op.OperandA).Value; + int Offset = ((ShaderIrOperImm)InnerOp.OperandA).Value; long Target = Current.EndPosition + Offset; Current.Branch = Enqueue(Target, Current); } + foreach (ShaderIrNode Node in Current.Nodes) + { + if (Node is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy) + { + int Offset = ((ShaderIrOperImm)CurrOp.OperandA).Value; + + long Target = Offset; + + Current.Branch = Enqueue(Target, Current); + } + } + if (NodeHasNext(LastNode)) { Current.Next = Enqueue(Current.EndPosition); @@ -157,7 +169,7 @@ namespace Ryujinx.Graphics.Gal.Shader { int Offset = ((int)(OpCode >> 20) << 8) >> 8; - long Target = Position + Offset; + long Target = Position + Offset - Beginning; DbgOpCode += " (0x" + Target.ToString("x16") + ")"; } @@ -170,7 +182,7 @@ namespace Ryujinx.Graphics.Gal.Shader continue; } - Decode(Block, OpCode); + Decode(Block, OpCode, Position); } while (!IsFlowChange(Block.GetLastNode())); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs index d197835a7a..35dea61216 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs @@ -84,6 +84,8 @@ namespace Ryujinx.Graphics.Gal.Shader Bra, Exit, Kil, + Ssy, + Sync, Emit, Cut diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index 95b8e467d2..1e76eab169 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -112,7 +112,9 @@ namespace Ryujinx.Graphics.Gal.Shader Set("0100110000101x", ShaderDecode.Shr_C); Set("0011100x00101x", ShaderDecode.Shr_I); Set("0101110000101x", ShaderDecode.Shr_R); + Set("1110001010010x", ShaderDecode.Ssy); Set("1110111111110x", ShaderDecode.St_A); + Set("1111000011111x", ShaderDecode.Sync); Set("110000xxxx111x", ShaderDecode.Tex); Set("1101111010111x", ShaderDecode.Tex_B); Set("1101111101001x", ShaderDecode.Texq);