diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 3e409c2e1e55e0ef249a00304bda1b5334f1fc19..6cb7bea1c4f3941fd7728bb1352b7461d428882c 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -597,6 +597,13 @@ public:
         Unknown,
     };
 
+    /// Returns whether an opcode has an execution predicate field or not (ie, whether it can be
+    /// conditionally executed).
+    static bool IsPredicatedInstruction(Id opcode) {
+        // TODO(Subv): Add the rest of unpredicated instructions.
+        return opcode != Id::SSY;
+    }
+
     class Matcher {
     public:
         Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 32f06f4095950d23cbdb6daf45dcdb9b4c94831a..8954deb810b7599f183ff7e7f69e8260737207d4 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -141,6 +141,15 @@ private:
                     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.
+                    ASSERT_MSG(instr.bra.constant_buffer == 0,
+                               "Constant buffer SSY is not supported");
+                    u32 target = offset + instr.bra.GetBranchTarget();
+                    labels.insert(target);
+                    // Continue scanning for an exit method.
+                    break;
+                }
                 }
             }
         }
@@ -828,7 +837,11 @@ private:
         ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
                    "NeverExecute predicate not implemented");
 
-        if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+        // Some instructions (like SSY) don't have a predicate field, they are always
+        // unconditionally executed.
+        bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->GetId());
+
+        if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
             shader.AddLine("if (" +
                            GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) +
                            ')');
@@ -1668,16 +1681,25 @@ private:
                 break;
             }
             case OpCode::Id::SSY: {
-                // The SSY opcode tells the GPU where to re-converge divergent execution paths, we
-                // can ignore this when generating GLSL code.
+                // 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");
+
+                u32 target = offset + instr.bra.GetBranchTarget();
+                shader.AddLine("ssy_target = " + std::to_string(target) + "u;");
                 break;
             }
-            case OpCode::Id::SYNC:
+            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);
+                shader.AddLine("{ jmp_to = ssy_target; break; }");
+                break;
+            }
             case OpCode::Id::DEPBAR: {
-                // TODO(Subv): Find out if we actually have to care about these instructions or if
+                // TODO(Subv): Find out if we actually have to care about this instruction or if
                 // the GLSL compiler takes care of that for us.
-                LOG_WARNING(HW_GPU, "DEPBAR/SYNC instruction is stubbed");
+                LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed");
                 break;
             }
             default: {
@@ -1691,7 +1713,7 @@ private:
         }
 
         // Close the predicate condition scope.
-        if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+        if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
             --shader.scope;
             shader.AddLine('}');
         }
@@ -1742,6 +1764,7 @@ private:
             } else {
                 labels.insert(subroutine.begin);
                 shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
+                shader.AddLine("uint ssy_target = 0u;");
                 shader.AddLine("while (true) {");
                 ++shader.scope;
 
@@ -1757,7 +1780,7 @@ private:
                     u32 compile_end = CompileRange(label, next_label);
                     if (compile_end > next_label && compile_end != PROGRAM_END) {
                         // This happens only when there is a label inside a IF/LOOP block
-                        shader.AddLine("{ jmp_to = " + std::to_string(compile_end) + "u; break; }");
+                        shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }");
                         labels.emplace(compile_end);
                     }