From 5f3d6c85db8e90b9ea9f113821befc8edaa4b875 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sat, 9 Jun 2018 02:36:33 -0400
Subject: [PATCH] gl_shader_decompiler: Implement saturate for float
 instructions.

---
 src/video_core/engines/shader_bytecode.h      |  3 +-
 .../renderer_opengl/gl_shader_decompiler.cpp  | 68 +++++++++----------
 2 files changed, 32 insertions(+), 39 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index ec8dbd370b..c158ffed2b 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -213,7 +213,6 @@ union Instruction {
     BitField<28, 8, Register> gpr28;
     BitField<39, 8, Register> gpr39;
     BitField<48, 16, u64> opcode;
-    BitField<50, 1, u64> saturate_a;
 
     union {
         BitField<20, 19, u64> imm20_19;
@@ -222,7 +221,7 @@ union Instruction {
         BitField<46, 1, u64> abs_a;
         BitField<48, 1, u64> negate_a;
         BitField<49, 1, u64> abs_b;
-        BitField<50, 1, u64> abs_d;
+        BitField<50, 1, u64> saturate_d;
         BitField<56, 1, u64> negate_imm;
 
         union {
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 67726e7c6b..b94b793842 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -299,13 +299,15 @@ public:
      * @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 is_saturated Optional, when True, saturates the provided value.
      * @param dest_elem Optional, the destination element to use for the operation.
      */
     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) {
-        SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem);
+                            u64 dest_num_components, u64 value_num_components,
+                            bool is_saturated = false, u64 dest_elem = 0) {
+
+        SetRegister(reg, elem, is_saturated ? "clamp(" + value + ", 0.0, 1.0)" : value,
+                    dest_num_components, value_num_components, dest_elem);
     }
 
     /**
@@ -315,18 +317,21 @@ public:
      * @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 is_saturated Optional, when True, saturates the provided value.
      * @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) {
+                              u64 value_num_components, bool is_saturated = false,
+                              u64 dest_elem = 0) {
+        ASSERT_MSG(!is_saturated, "Unimplemented");
+
         const std::string func = GetGLSLConversionFunc(
             is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger,
             GLSLRegister::Type::Float);
 
         SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components,
-                    is_abs, dest_elem);
+                    dest_elem);
     }
 
     /**
@@ -500,12 +505,10 @@ private:
      * @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) {
+                     u64 dest_num_components, u64 value_num_components, u64 dest_elem) {
         std::string dest = GetRegister(reg, dest_elem);
         if (dest_num_components > 1) {
             dest += GetSwizzle(elem);
@@ -516,8 +519,6 @@ private:
             src += GetSwizzle(elem);
         }
 
-        src = is_abs ? "abs(" + src + ')' : src;
-
         shader.AddLine(dest + " = " + src + ';');
     }
 
@@ -808,9 +809,8 @@ private:
             case OpCode::Id::FMUL_C:
             case OpCode::Id::FMUL_R:
             case OpCode::Id::FMUL_IMM: {
-                ASSERT_MSG(!instr.saturate_a, "Unimplemented");
-
-                regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
+                regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
+                                        instr.alu.saturate_d);
                 break;
             }
             case OpCode::Id::FMUL32_IMM: {
@@ -823,41 +823,39 @@ private:
             case OpCode::Id::FADD_C:
             case OpCode::Id::FADD_R:
             case OpCode::Id::FADD_IMM: {
-                ASSERT_MSG(!instr.saturate_a, "Unimplemented");
-
-                regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
+                regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
+                                        instr.alu.saturate_d);
                 break;
             }
             case OpCode::Id::MUFU: {
-                ASSERT_MSG(!instr.saturate_a, "Unimplemented");
-
                 switch (instr.sub_op) {
                 case SubOp::Cos:
                     regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1,
-                                            instr.alu.abs_d);
+                                            instr.alu.saturate_d);
                     break;
                 case SubOp::Sin:
                     regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1,
-                                            instr.alu.abs_d);
+                                            instr.alu.saturate_d);
                     break;
                 case SubOp::Ex2:
                     regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1,
-                                            instr.alu.abs_d);
+                                            instr.alu.saturate_d);
                     break;
                 case SubOp::Lg2:
                     regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1,
-                                            instr.alu.abs_d);
+                                            instr.alu.saturate_d);
                     break;
                 case SubOp::Rcp:
-                    regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
+                    regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1,
+                                            instr.alu.saturate_d);
                     break;
                 case SubOp::Rsq:
                     regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1,
-                                            instr.alu.abs_d);
+                                            instr.alu.saturate_d);
                     break;
                 case SubOp::Min:
                     regs.SetRegisterToFloat(instr.gpr0, 0, "min(" + op_a + "," + op_b + ')', 1, 1,
-                                            instr.alu.abs_d);
+                                            instr.alu.saturate_d);
                     break;
                 default:
                     NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}",
@@ -1028,8 +1026,8 @@ private:
             case OpCode::Id::IADD_C:
             case OpCode::Id::IADD_R:
             case OpCode::Id::IADD_IMM: {
-                ASSERT_MSG(!instr.saturate_a, "Unimplemented");
-                regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1);
+                regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
+                                          instr.alu.saturate_d);
                 break;
             }
             case OpCode::Id::ISCADD_C:
@@ -1051,8 +1049,6 @@ private:
             break;
         }
         case OpCode::Type::Ffma: {
-            ASSERT_MSG(!instr.saturate_a, "Unimplemented");
-
             std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
             std::string op_b = instr.ffma.negate_b ? "-" : "";
             std::string op_c = instr.ffma.negate_c ? "-" : "";
@@ -1086,13 +1082,13 @@ private:
             }
             }
 
-            regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
+            regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1,
+                                    instr.alu.saturate_d);
             break;
         }
         case OpCode::Type::Conversion: {
             ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
             ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
-            ASSERT_MSG(!instr.saturate_a, "Unimplemented");
 
             switch (opcode->GetId()) {
             case OpCode::Id::I2I_R: {
@@ -1106,7 +1102,7 @@ private:
                 }
 
                 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
-                                          1);
+                                          1, instr.alu.saturate_d);
                 break;
             }
             case OpCode::Id::I2F_R: {
@@ -1122,8 +1118,6 @@ private:
                 break;
             }
             case OpCode::Id::F2F_R: {
-                ASSERT_MSG(!instr.saturate_a, "Unimplemented");
-
                 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
 
                 switch (instr.conversion.f2f.rounding) {
@@ -1149,7 +1143,7 @@ private:
                     op_a = "abs(" + op_a + ')';
                 }
 
-                regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
+                regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
                 break;
             }
             case OpCode::Id::F2I_R: {