From d92afc74937610dc3a50d7f2659362351a02da14 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Wed, 21 Nov 2018 04:36:44 -0300
Subject: [PATCH] gl_shader_decompiler: Implement R2P_IMM

---
 src/video_core/engines/shader_bytecode.h      | 14 ++++++++++
 .../renderer_opengl/gl_shader_decompiler.cpp  | 28 +++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 83a6fd875..5b84bcb24 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -365,6 +365,11 @@ enum class HalfPrecision : u64 {
     FMZ = 2,
 };
 
+enum class R2pMode : u64 {
+    Pr = 0,
+    Cc = 1,
+};
+
 enum class IpaInterpMode : u64 {
     Linear = 0,
     Perspective = 1,
@@ -854,6 +859,12 @@ union Instruction {
         BitField<39, 3, u64> pred39;
     } hsetp2;
 
+    union {
+        BitField<40, 1, R2pMode> mode;
+        BitField<41, 2, u64> byte;
+        BitField<20, 7, u64> immediate_mask;
+    } r2p;
+
     union {
         BitField<39, 3, u64> pred39;
         BitField<42, 1, u64> neg_pred;
@@ -1381,6 +1392,7 @@ public:
         PSETP,
         PSET,
         CSETP,
+        R2P_IMM,
         XMAD_IMM,
         XMAD_CR,
         XMAD_RC,
@@ -1410,6 +1422,7 @@ public:
         HalfSetPredicate,
         PredicateSetPredicate,
         PredicateSetRegister,
+        RegisterSetPredicate,
         Conversion,
         Xmad,
         Unknown,
@@ -1647,6 +1660,7 @@ private:
             INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
             INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
             INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
+            INST("0011100-11110---", Id::R2P_IMM, Type::RegisterSetPredicate, "R2P_IMM"),
             INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
             INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
             INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 5fde22ad4..30050b585 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -3260,6 +3260,34 @@ private:
             }
             break;
         }
+        case OpCode::Type::RegisterSetPredicate: {
+            UNIMPLEMENTED_IF(instr.r2p.mode != Tegra::Shader::R2pMode::Pr);
+
+            const std::string apply_mask = [&]() {
+                switch (opcode->get().GetId()) {
+                case OpCode::Id::R2P_IMM:
+                    return std::to_string(instr.r2p.immediate_mask);
+                default:
+                    UNREACHABLE();
+                }
+            }();
+            const std::string mask = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
+                                     " >> " + std::to_string(instr.r2p.byte) + ')';
+
+            constexpr u64 programmable_preds = 7;
+            for (u64 pred = 0; pred < programmable_preds; ++pred) {
+                const auto shift = std::to_string(1 << pred);
+
+                shader.AddLine("if ((" + apply_mask + " & " + shift + ") != 0) {");
+                ++shader.scope;
+
+                SetPredicate(pred, '(' + mask + " & " + shift + ") != 0");
+
+                --shader.scope;
+                shader.AddLine('}');
+            }
+            break;
+        }
         case OpCode::Type::FloatSet: {
             const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8),
                                                       instr.fset.abs_a != 0, instr.fset.neg_a != 0);