From a7b5ab4d9a275c6a16c5a7fdb2fd39827922eb61 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 26 Apr 2018 23:21:17 -0400
Subject: [PATCH 1/5] gl_shader_decompiler: Implement MOV32_IMM instruction.

---
 src/video_core/engines/shader_bytecode.h                | 4 ++--
 src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 5 +++++
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index f3ca30cfaa..fba9ab4961 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -290,7 +290,7 @@ public:
         MOV_C,
         MOV_R,
         MOV_IMM,
-        MOV32I,
+        MOV32_IMM,
         SHR_C,
         SHR_R,
         SHR_IMM,
@@ -445,7 +445,7 @@ private:
             INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
             INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
             INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
-            INST("000000010000----", Id::MOV32I, Type::Arithmetic, "MOV32I"),
+            INST("000000010000----", Id::MOV32_IMM, Type::Arithmetic, "MOV32_IMM"),
             INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
             INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
             INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8b235e252f..647da4eb08 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -620,6 +620,11 @@ private:
             }
 
             switch (opcode->GetId()) {
+            case OpCode::Id::MOV32_IMM: {
+                // mov32i doesn't have abs or neg bits.
+                regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1);
+                break;
+            }
             case OpCode::Id::FMUL_C:
             case OpCode::Id::FMUL_R:
             case OpCode::Id::FMUL_IMM: {

From f2dcb3904918cf559f958f1cb4974b2702f91bb8 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 27 Apr 2018 22:19:14 -0400
Subject: [PATCH 2/5] shader_bytecode: Add decodings for i2i instructions.

---
 src/video_core/engines/shader_bytecode.h | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index fba9ab4961..0cbe5e94d5 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -25,6 +25,13 @@ struct Register {
     /// Register 255 is special cased to always be 0
     static constexpr size_t ZeroIndex = 255;
 
+    enum class Size : u64 {
+        Byte = 0,
+        Short = 1,
+        Word = 2,
+        Long = 3,
+    };
+
     constexpr Register() = default;
 
     constexpr Register(u64 value) : value(value) {}
@@ -236,6 +243,15 @@ union Instruction {
         BitField<56, 1, u64> neg_imm;
     } fset;
 
+    union {
+        BitField<10, 2, Register::Size> size;
+        BitField<13, 1, u64> is_signed;
+        BitField<41, 2, u64> selector;
+        BitField<45, 1, u64> negate_a;
+        BitField<49, 1, u64> abs_a;
+        BitField<50, 1, u64> saturate_a;
+    } i2i;
+
     BitField<61, 1, u64> is_b_imm;
     BitField<60, 1, u64> is_b_gpr;
     BitField<59, 1, u64> is_c_gpr;
@@ -314,6 +330,7 @@ public:
         FloatSet,
         FloatSetPredicate,
         IntegerSetPredicate,
+        I2I,
         Unknown,
     };
 
@@ -438,9 +455,6 @@ private:
             INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
             INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
             INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
-            INST("0100110011100---", Id::I2I_C, Type::Arithmetic, "I2I_C"),
-            INST("0101110011100---", Id::I2I_R, Type::Arithmetic, "I2I_R"),
-            INST("01110001-1000---", Id::I2I_IMM, Type::Arithmetic, "I2I_IMM"),
             INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
             INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
             INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
@@ -449,6 +463,9 @@ private:
             INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
             INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
             INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
+            INST("0100110011100---", Id::I2I_C, Type::I2I, "I2I_C"),
+            INST("0101110011100---", Id::I2I_R, Type::I2I, "I2I_R"),
+            INST("01110001-1000---", Id::I2I_IMM, Type::I2I, "I2I_IMM"),
             INST("01011000--------", Id::FSET_R, Type::FloatSet, "FSET_R"),
             INST("0100100---------", Id::FSET_C, Type::FloatSet, "FSET_C"),
             INST("0011000---------", Id::FSET_IMM, Type::FloatSet, "FSET_IMM"),

From c691fa4074d27bffa537f0f0da4b8e71a813c594 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 27 Apr 2018 22:24:53 -0400
Subject: [PATCH 3/5] GLSLRegister: Simplify register declarations, etc.

---
 .../renderer_opengl/gl_shader_decompiler.cpp  | 126 +++++++-----------
 1 file changed, 47 insertions(+), 79 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 647da4eb08..555aa8cc7d 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -153,85 +153,54 @@ private:
  */
 class GLSLRegister {
 public:
-    GLSLRegister(size_t index, ShaderWriter& shader)
-        : index{index}, shader{shader}, float_str{"freg_" + std::to_string(index)},
-          integer_str{"ireg_" + std::to_string(index)} {}
-
-    /// Returns a GLSL string representing the current state of the register
-    const std::string& GetActiveString() {
-        declr_type.insert(active_type);
-
-        switch (active_type) {
-        case Type::Float:
-            return float_str;
-        case Type::Integer:
-            return integer_str;
-        }
-
-        UNREACHABLE();
-        return float_str;
-    }
-
-    /// Returns a GLSL string representing the register as a float
-    const std::string& GetFloatString() const {
-        ASSERT(IsFloatUsed());
-        return float_str;
-    }
-
-    /// Returns a GLSL string representing the register as an integer
-    const std::string& GetIntegerString() const {
-        ASSERT(IsIntegerUsed());
-        return integer_str;
-    }
-
-    /// Convert the current register state from float to integer
-    void FloatToInteger() {
-        ASSERT(active_type == Type::Float);
-
-        const std::string src = GetActiveString();
-        active_type = Type::Integer;
-        const std::string dest = GetActiveString();
-
-        shader.AddLine(dest + " = floatBitsToInt(" + src + ");");
-    }
-
-    /// Convert the current register state from integer to float
-    void IntegerToFloat() {
-        ASSERT(active_type == Type::Integer);
-
-        const std::string src = GetActiveString();
-        active_type = Type::Float;
-        const std::string dest = GetActiveString();
-
-        shader.AddLine(dest + " = intBitsToFloat(" + src + ");");
-    }
-
-    /// Returns true if the register was ever used as a float, used for register declarations
-    bool IsFloatUsed() const {
-        return declr_type.find(Type::Float) != declr_type.end();
-    }
-
-    /// Returns true if the register was ever used as an integer, used for register declarations
-    bool IsIntegerUsed() const {
-        return declr_type.find(Type::Integer) != declr_type.end();
-    }
-
-    /// Returns true if the active type is float
-    bool IsFloat() const {
-        return active_type == Type::Float;
-    }
-
-    /// Returns true if the active type is integer
-    bool IsInteger() const {
-        return active_type == Type::Integer;
-    }
-
-private:
     enum class Type {
         Float,
         Integer,
     };
 
+    GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {}
+
+    static std::string GetTypeString(Type type) {
+        switch (type) {
+        case Type::Float:
+            return "float";
+        }
+
+        UNREACHABLE();
+        return {};
+    }
+
+    static std::string GetPrefixString(Type type) {
+        return "reg_" + GetTypeString(type) + '_';
+    }
+
+    /// Returns a GLSL string representing the current state of the register
+    const std::string GetActiveString() {
+        declr_type.insert(active_type);
+        return GetPrefixString(active_type) + std::to_string(index);
+    }
+
+    /// Returns true if the active type is a float
+    bool IsFloat() const {
+        return active_type == Type::Float;
+    }
+
+    /// Returns true if the active type is an integer
+    bool IsInteger() const {
+        return active_type == Type::Integer;
+    }
+
+    /// Returns the index of the register
+    size_t GetIndex() const {
+        return index;
+    }
+
+    /// Returns a set of the declared types of the register
+    const std::set<Type>& DeclaredTypes() const {
+        return declr_type;
+    }
+
+private:
     const size_t index;
     const std::string float_str;
     const std::string integer_str;
@@ -347,11 +316,10 @@ public:
     /// Add declarations for registers
     void GenerateDeclarations() {
         for (const auto& reg : regs) {
-            if (reg.IsFloatUsed()) {
-                declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;");
-            }
-            if (reg.IsIntegerUsed()) {
-                declarations.AddLine("int " + reg.GetIntegerString() + " = 0;");
+            for (const auto& type : reg.DeclaredTypes()) {
+                declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' +
+                                     GLSLRegister::GetPrefixString(type) +
+                                     std::to_string(reg.GetIndex()) + " = 0;");
             }
         }
         declarations.AddNewLine();

From e73927cfc28307912a01ca311503e9b7769113e7 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sat, 28 Apr 2018 19:59:30 -0400
Subject: [PATCH 4/5] gl_shader_decompiler: More cleanups, etc. with how we
 handle register types.

---
 .../renderer_opengl/gl_shader_decompiler.cpp  | 164 +++++++++++++-----
 1 file changed, 120 insertions(+), 44 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 555aa8cc7d..f90f74a48c 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -156,20 +156,27 @@ public:
     enum class Type {
         Float,
         Integer,
+        UnsignedInteger,
     };
 
     GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {}
 
+    /// Gets the GLSL type string for a register
     static std::string GetTypeString(Type type) {
         switch (type) {
         case Type::Float:
             return "float";
+        case Type::Integer:
+            return "int";
+        case Type::UnsignedInteger:
+            return "uint";
         }
 
         UNREACHABLE();
         return {};
     }
 
+    /// Gets the GLSL register prefix string, used for declarations and referencing
     static std::string GetPrefixString(Type type) {
         return "reg_" + GetTypeString(type) + '_';
     }
@@ -223,18 +230,35 @@ public:
         BuildRegisterList();
     }
 
-    /// Generates code representing a temporary (GPR) register.
-    std::string GetRegister(const Register& reg, unsigned elem = 0) {
-        if (reg == Register::ZeroIndex) {
-            return "0";
-        }
-
-        return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
+    /**
+     * Gets a register as an float.
+     * @param reg The register to get.
+     * @param elem The element to use for the operation.
+     * @returns GLSL string corresponding to the register as a float.
+     */
+    std::string GetRegisterAsFloat(const Register& reg, unsigned elem = 0) {
+        ASSERT(regs[reg].IsFloat());
+        return GetRegister(reg, elem);
     }
 
     /**
-     * Writes code that does a register assignment to float value operation. Should only be used
-     * with shader instructions that deal with floats.
+     * Gets a register as an integer.
+     * @param reg The register to get.
+     * @param elem The element to use for the operation.
+     * @param is_signed Whether to get the register as a signed (or unsigned) integer.
+     * @returns GLSL string corresponding to the register as an integer.
+     */
+    std::string GetRegisterAsInteger(const Register& reg, unsigned elem = 0,
+                                     bool is_signed = true) {
+        const std::string func = GetGLSLConversionFunc(
+            GLSLRegister::Type::Float,
+            is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger);
+
+        return func + '(' + GetRegister(reg, elem) + ')';
+    }
+
+    /**
+     * Writes code that does a register assignment to float value operation.
      * @param reg The destination register to use.
      * @param elem The element to use for the operation.
      * @param value The code representing the value to assign.
@@ -246,21 +270,28 @@ public:
     void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
                             u64 dest_num_components, u64 value_num_components, bool is_abs = false,
                             u64 dest_elem = 0) {
-        ASSERT(regs[reg].IsFloat());
+        SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem);
+    }
 
-        std::string dest = GetRegister(reg, dest_elem);
-        if (dest_num_components > 1) {
-            dest += GetSwizzle(elem);
-        }
+    /**
+     * Writes code that does a register assignment to integer value operation.
+     * @param reg The destination register to use.
+     * @param elem The element to use for the operation.
+     * @param value The code representing the value to assign.
+     * @param dest_num_components Number of components in the destination.
+     * @param value_num_components Number of components in the value.
+     * @param is_abs Optional, when True, applies absolute value to output.
+     * @param dest_elem Optional, the destination element to use for the operation.
+     */
+    void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
+                              const std::string& value, u64 dest_num_components,
+                              u64 value_num_components, bool is_abs = false, u64 dest_elem = 0) {
+        const std::string func = GetGLSLConversionFunc(
+            is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger,
+            GLSLRegister::Type::Float);
 
-        std::string src = '(' + value + ')';
-        if (value_num_components > 1) {
-            src += GetSwizzle(elem);
-        }
-
-        src = is_abs ? "abs(" + src + ')' : src;
-
-        shader.AddLine(dest + " = " + src + ';');
+        SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components,
+                    is_abs, dest_elem);
     }
 
     /**
@@ -271,7 +302,7 @@ public:
      * @param attribute The input attibute to use as the source value.
      */
     void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
-        std::string dest = GetRegister(reg);
+        std::string dest = GetRegisterAsFloat(reg);
         std::string src = GetInputAttribute(attribute) + GetSwizzle(elem);
 
         if (regs[reg].IsFloat()) {
@@ -292,7 +323,7 @@ public:
      */
     void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
         std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
-        std::string src = GetRegister(reg);
+        std::string src = GetRegisterAsFloat(reg);
         ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float");
         shader.AddLine(dest + " = " + src + ';');
     }
@@ -363,6 +394,51 @@ public:
     }
 
 private:
+    /// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc.
+    const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) const {
+        const std::string src_type = GLSLRegister::GetTypeString(src);
+        std::string dest_type = GLSLRegister::GetTypeString(dest);
+        dest_type[0] = toupper(dest_type[0]);
+        return src_type + "BitsTo" + dest_type;
+    }
+
+    /// Generates code representing a temporary (GPR) register.
+    std::string GetRegister(const Register& reg, unsigned elem) {
+        if (reg == Register::ZeroIndex) {
+            return "0";
+        }
+
+        return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
+    }
+
+    /**
+     * Writes code that does a register assignment to value operation.
+     * @param reg The destination register to use.
+     * @param elem The element to use for the operation.
+     * @param value The code representing the value to assign.
+     * @param dest_num_components Number of components in the destination.
+     * @param value_num_components Number of components in the value.
+     * @param is_abs Optional, when True, applies absolute value to output.
+     * @param dest_elem Optional, the destination element to use for the operation.
+     */
+    void SetRegister(const Register& reg, u64 elem, const std::string& value,
+                     u64 dest_num_components, u64 value_num_components, bool is_abs,
+                     u64 dest_elem) {
+        std::string dest = GetRegister(reg, dest_elem);
+        if (dest_num_components > 1) {
+            dest += GetSwizzle(elem);
+        }
+
+        std::string src = '(' + value + ')';
+        if (value_num_components > 1) {
+            src += GetSwizzle(elem);
+        }
+
+        src = is_abs ? "abs(" + src + ')' : src;
+
+        shader.AddLine(dest + " = " + src + ';');
+    }
+
     /// Build the GLSL register list.
     void BuildRegisterList() {
         for (size_t index = 0; index < Register::NumRegisters; ++index) {
@@ -566,7 +642,7 @@ private:
         switch (opcode->GetType()) {
         case OpCode::Type::Arithmetic: {
             std::string op_a = instr.alu.negate_a ? "-" : "";
-            op_a += regs.GetRegister(instr.gpr8);
+            op_a += regs.GetRegisterAsFloat(instr.gpr8);
             if (instr.alu.abs_a) {
                 op_a = "abs(" + op_a + ')';
             }
@@ -577,7 +653,7 @@ private:
                 op_b += GetImmediate19(instr);
             } else {
                 if (instr.is_b_gpr) {
-                    op_b += regs.GetRegister(instr.gpr20);
+                    op_b += regs.GetRegisterAsFloat(instr.gpr20);
                 } else {
                     op_b += regs.GetUniform(instr.uniform, instr.gpr0);
                 }
@@ -602,8 +678,8 @@ private:
             case OpCode::Id::FMUL32_IMM: {
                 // fmul32i doesn't have abs or neg bits.
                 regs.SetRegisterToFloat(
-                    instr.gpr0, 0, regs.GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1,
-                    1);
+                    instr.gpr0, 0,
+                    regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
                 break;
             }
             case OpCode::Id::FADD_C:
@@ -660,29 +736,29 @@ private:
             break;
         }
         case OpCode::Type::Ffma: {
-            std::string op_a = regs.GetRegister(instr.gpr8);
+            std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
             std::string op_b = instr.ffma.negate_b ? "-" : "";
             std::string op_c = instr.ffma.negate_c ? "-" : "";
 
             switch (opcode->GetId()) {
             case OpCode::Id::FFMA_CR: {
                 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
-                op_c += regs.GetRegister(instr.gpr39);
+                op_c += regs.GetRegisterAsFloat(instr.gpr39);
                 break;
             }
             case OpCode::Id::FFMA_RR: {
-                op_b += regs.GetRegister(instr.gpr20);
-                op_c += regs.GetRegister(instr.gpr39);
+                op_b += regs.GetRegisterAsFloat(instr.gpr20);
+                op_c += regs.GetRegisterAsFloat(instr.gpr39);
                 break;
             }
             case OpCode::Id::FFMA_RC: {
-                op_b += regs.GetRegister(instr.gpr39);
+                op_b += regs.GetRegisterAsFloat(instr.gpr39);
                 op_c += regs.GetUniform(instr.uniform, instr.gpr0);
                 break;
             }
             case OpCode::Id::FFMA_IMM: {
                 op_b += GetImmediate19(instr);
-                op_c += regs.GetRegister(instr.gpr39);
+                op_c += regs.GetRegisterAsFloat(instr.gpr39);
                 break;
             }
             default: {
@@ -712,8 +788,8 @@ private:
             }
             case OpCode::Id::TEXS: {
                 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
-                const std::string op_a = regs.GetRegister(instr.gpr8);
-                const std::string op_b = regs.GetRegister(instr.gpr20);
+                const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
+                const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
                 const std::string sampler = GetSampler(instr.sampler);
                 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
                 // Add an extra scope and declare the texture coords inside to prevent overwriting
@@ -738,7 +814,7 @@ private:
         }
         case OpCode::Type::FloatSetPredicate: {
             std::string op_a = instr.fsetp.neg_a ? "-" : "";
-            op_a += regs.GetRegister(instr.gpr8);
+            op_a += regs.GetRegisterAsFloat(instr.gpr8);
 
             if (instr.fsetp.abs_a) {
                 op_a = "abs(" + op_a + ')';
@@ -754,7 +830,7 @@ private:
                 op_b += '(' + GetImmediate19(instr) + ')';
             } else {
                 if (instr.is_b_gpr) {
-                    op_b += regs.GetRegister(instr.gpr20);
+                    op_b += regs.GetRegisterAsFloat(instr.gpr20);
                 } else {
                     op_b += regs.GetUniform(instr.uniform, instr.gpr0);
                 }
@@ -789,7 +865,7 @@ private:
         }
         case OpCode::Type::FloatSet: {
             std::string op_a = instr.fset.neg_a ? "-" : "";
-            op_a += regs.GetRegister(instr.gpr8);
+            op_a += regs.GetRegisterAsFloat(instr.gpr8);
 
             if (instr.fset.abs_a) {
                 op_a = "abs(" + op_a + ')';
@@ -805,7 +881,7 @@ private:
                     op_b += imm;
             } else {
                 if (instr.is_b_gpr) {
-                    op_b += regs.GetRegister(instr.gpr20);
+                    op_b += regs.GetRegisterAsFloat(instr.gpr20);
                 } else {
                     op_b += regs.GetUniform(instr.uniform, instr.gpr0);
                 }
@@ -850,10 +926,10 @@ private:
 
                 // Final color output is currently hardcoded to GPR0-3 for fragment shaders
                 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
-                    shader.AddLine("color.r = " + regs.GetRegister(0) + ';');
-                    shader.AddLine("color.g = " + regs.GetRegister(1) + ';');
-                    shader.AddLine("color.b = " + regs.GetRegister(2) + ';');
-                    shader.AddLine("color.a = " + regs.GetRegister(3) + ';');
+                    shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';');
+                    shader.AddLine("color.g = " + regs.GetRegisterAsFloat(1) + ';');
+                    shader.AddLine("color.b = " + regs.GetRegisterAsFloat(2) + ';');
+                    shader.AddLine("color.a = " + regs.GetRegisterAsFloat(3) + ';');
                 }
 
                 shader.AddLine("return true;");

From 0c01c34eff9456e1341fcc0f7a048325e6929cd3 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sat, 28 Apr 2018 20:01:36 -0400
Subject: [PATCH 5/5] gl_shader_decompiler: Partially implement I2I_R, and
 I2F_R.

---
 src/video_core/engines/shader_bytecode.h      | 16 ++++++------
 .../renderer_opengl/gl_shader_decompiler.cpp  | 26 +++++++++++++++++++
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 0cbe5e94d5..f20c2cd419 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -250,7 +250,7 @@ union Instruction {
         BitField<45, 1, u64> negate_a;
         BitField<49, 1, u64> abs_a;
         BitField<50, 1, u64> saturate_a;
-    } i2i;
+    } conversion;
 
     BitField<61, 1, u64> is_b_imm;
     BitField<60, 1, u64> is_b_gpr;
@@ -330,7 +330,7 @@ public:
         FloatSet,
         FloatSetPredicate,
         IntegerSetPredicate,
-        I2I,
+        Conversion,
         Unknown,
     };
 
@@ -452,9 +452,6 @@ private:
             INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
             INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
             INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
-            INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
-            INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
-            INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
             INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
             INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
             INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
@@ -463,9 +460,12 @@ private:
             INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
             INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
             INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
-            INST("0100110011100---", Id::I2I_C, Type::I2I, "I2I_C"),
-            INST("0101110011100---", Id::I2I_R, Type::I2I, "I2I_R"),
-            INST("01110001-1000---", Id::I2I_IMM, Type::I2I, "I2I_IMM"),
+            INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"),
+            INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"),
+            INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
+            INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"),
+            INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"),
+            INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"),
             INST("01011000--------", Id::FSET_R, Type::FloatSet, "FSET_R"),
             INST("0100100---------", Id::FSET_C, Type::FloatSet, "FSET_C"),
             INST("0011000---------", Id::FSET_IMM, Type::FloatSet, "FSET_IMM"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index f90f74a48c..27190cc450 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -770,6 +770,32 @@ private:
             regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
             break;
         }
+        case OpCode::Type::Conversion: {
+            ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
+            ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
+            ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
+            ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
+
+            switch (opcode->GetId()) {
+            case OpCode::Id::I2I_R:
+            case OpCode::Id::I2F_R: {
+                std::string op_a =
+                    regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
+
+                if (instr.conversion.abs_a) {
+                    op_a = "abs(" + op_a + ')';
+                }
+
+                regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
+                break;
+            }
+            default: {
+                NGLOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName());
+                UNREACHABLE();
+            }
+            }
+            break;
+        }
         case OpCode::Type::Memory: {
             const Attribute::Index attribute = instr.attribute.fmt20.index;