From 41fb25349a82ba0657e41e4597ac9e415f6e442a Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Tue, 16 Oct 2018 17:11:26 -0300
Subject: [PATCH] gl_shader_decompiler: Implement PBK and BRK

---
 src/video_core/engines/shader_bytecode.h      | 10 +++-
 .../renderer_opengl/gl_shader_decompiler.cpp  | 55 ++++++++++++-------
 2 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index f356f9a031..8c8d657692 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1095,11 +1095,13 @@ public:
         KIL,
         SSY,
         SYNC,
+        BRK,
         DEPBAR,
         BFE_C,
         BFE_R,
         BFE_IMM,
         BRA,
+        PBK,
         LD_A,
         LD_C,
         ST_A,
@@ -1239,7 +1241,7 @@ public:
     /// conditionally executed).
     static bool IsPredicatedInstruction(Id opcode) {
         // TODO(Subv): Add the rest of unpredicated instructions.
-        return opcode != Id::SSY;
+        return opcode != Id::SSY && opcode != Id::PBK;
     }
 
     class Matcher {
@@ -1335,9 +1337,11 @@ private:
 #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
             INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
             INST("111000101001----", Id::SSY, Type::Flow, "SSY"),
+            INST("111000101010----", Id::PBK, Type::Flow, "PBK"),
             INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
+            INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
+            INST("111000110100---", Id::BRK, Type::Flow, "BRK"),
             INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
-            INST("1111000011111---", Id::SYNC, Type::Synch, "SYNC"),
             INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
             INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"),
             INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
@@ -1463,4 +1467,4 @@ private:
     }
 };
 
-} // namespace Tegra::Shader
+} // namespace Tegra::Shader
\ No newline at end of file
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index ca063d90db..db52841f3d 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -165,10 +165,11 @@ private:
                     const ExitMethod jmp = Scan(target, end, labels);
                     return exit_method = ParallelExit(no_jmp, jmp);
                 }
-                case OpCode::Id::SSY: {
-                    // The SSY instruction uses a similar encoding as the BRA instruction.
+                case OpCode::Id::SSY:
+                case OpCode::Id::PBK: {
+                    // The SSY and PBK use a similar encoding as the BRA instruction.
                     ASSERT_MSG(instr.bra.constant_buffer == 0,
-                               "Constant buffer SSY is not supported");
+                               "Constant buffer branching is not supported");
                     const u32 target = offset + instr.bra.GetBranchTarget();
                     labels.insert(target);
                     // Continue scanning for an exit method.
@@ -1153,27 +1154,27 @@ private:
     }
 
     /*
-     * Emits code to push the input target address to the SSY address stack, incrementing the stack
+     * Emits code to push the input target address to the flow address stack, incrementing the stack
      * top.
      */
-    void EmitPushToSSYStack(u32 target) {
+    void EmitPushToFlowStack(u32 target) {
         shader.AddLine('{');
         ++shader.scope;
-        shader.AddLine("ssy_stack[ssy_stack_top] = " + std::to_string(target) + "u;");
-        shader.AddLine("ssy_stack_top++;");
+        shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
+        shader.AddLine("flow_stack_top++;");
         --shader.scope;
         shader.AddLine('}');
     }
 
     /*
-     * Emits code to pop an address from the SSY address stack, setting the jump address to the
+     * Emits code to pop an address from the flow address stack, setting the jump address to the
      * popped address and decrementing the stack top.
      */
-    void EmitPopFromSSYStack() {
+    void EmitPopFromFlowStack() {
         shader.AddLine('{');
         ++shader.scope;
-        shader.AddLine("ssy_stack_top--;");
-        shader.AddLine("jmp_to = ssy_stack[ssy_stack_top];");
+        shader.AddLine("flow_stack_top--;");
+        shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
         shader.AddLine("break;");
         --shader.scope;
         shader.AddLine('}');
@@ -2933,16 +2934,32 @@ private:
                 // The SSY opcode tells the GPU where to re-converge divergent execution paths, it
                 // sets the target of the jump that the SYNC instruction will make. The SSY opcode
                 // has a similar structure to the BRA opcode.
-                ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported");
+                ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer flow is not supported");
 
                 const u32 target = offset + instr.bra.GetBranchTarget();
-                EmitPushToSSYStack(target);
+                EmitPushToFlowStack(target);
+                break;
+            }
+            case OpCode::Id::PBK: {
+                // PBK pushes to a stack the address where BRK will jump to. This shares stack with
+                // SSY but using SYNC on a PBK address will kill the shader execution. We don't
+                // emulate this because it's very unlikely a driver will emit such invalid shader.
+                ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer PBK is not supported");
+
+                const u32 target = offset + instr.bra.GetBranchTarget();
+                EmitPushToFlowStack(target);
                 break;
             }
             case OpCode::Id::SYNC: {
                 // The SYNC opcode jumps to the address previously set by the SSY opcode
                 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
-                EmitPopFromSSYStack();
+                EmitPopFromFlowStack();
+                break;
+            }
+            case OpCode::Id::BRK: {
+                // The BRK opcode jumps to the address previously set by the PBK opcode
+                ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
+                EmitPopFromFlowStack();
                 break;
             }
             case OpCode::Id::DEPBAR: {
@@ -3096,11 +3113,11 @@ private:
                 labels.insert(subroutine.begin);
                 shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
 
-                // TODO(Subv): Figure out the actual depth of the SSY stack, for now it seems
-                // unlikely that shaders will use 20 nested SSYs.
-                constexpr u32 SSY_STACK_SIZE = 20;
-                shader.AddLine("uint ssy_stack[" + std::to_string(SSY_STACK_SIZE) + "];");
-                shader.AddLine("uint ssy_stack_top = 0u;");
+                // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
+                // unlikely that shaders will use 20 nested SSYs and PBKs.
+                constexpr u32 FLOW_STACK_SIZE = 20;
+                shader.AddLine("uint flow_stack[" + std::to_string(FLOW_STACK_SIZE) + "];");
+                shader.AddLine("uint flow_stack_top = 0u;");
 
                 shader.AddLine("while (true) {");
                 ++shader.scope;