Kaynağa Gözat

gl_shader_decompiler: Implement FMUL/FADD/FFMA immediate instructions.

bunnei 8 yıl önce
ebeveyn
işleme
5a28dce9eb

+ 14 - 0
src/video_core/engines/shader_bytecode.h

@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <cstring>
 #include <map>
 #include <string>
 #include "common/bit_field.h"
@@ -289,6 +290,7 @@ enum class SubOp : u64 {
     Lg2 = 0x3,
     Rcp = 0x4,
     Rsq = 0x5,
+    Min = 0x8,
 };
 
 union Instruction {
@@ -307,11 +309,22 @@ union Instruction {
     BitField<39, 8, Register> gpr39;
 
     union {
+        BitField<20, 19, u64> imm20;
         BitField<45, 1, u64> negate_b;
         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<56, 1, u64> negate_imm;
+
+        float GetImm20() const {
+            float result{};
+            u32 imm{static_cast<u32>(imm20)};
+            imm <<= 12;
+            imm |= negate_imm ? 0x80000000 : 0;
+            std::memcpy(&result, &imm, sizeof(imm));
+            return result;
+        }
     } alu;
 
     union {
@@ -319,6 +332,7 @@ union Instruction {
         BitField<49, 1, u64> negate_c;
     } ffma;
 
+    BitField<61, 1, u64> is_b_imm;
     BitField<60, 1, u64> is_b_gpr;
     BitField<59, 1, u64> is_c_gpr;
 

+ 39 - 12
src/video_core/renderer_opengl/gl_shader_decompiler.cpp

@@ -190,6 +190,11 @@ private:
         }
     }
 
+    /// Generates code representing an immediate value
+    static std::string GetImmediate(const Instruction& instr) {
+        return std::to_string(instr.alu.GetImm20());
+    }
+
     /// Generates code representing a temporary (GPR) register.
     std::string GetRegister(const Register& reg, unsigned elem = 0) {
         if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
@@ -269,24 +274,32 @@ private:
             }
 
             std::string op_b = instr.alu.negate_b ? "-" : "";
-            if (instr.is_b_gpr) {
-                op_b += GetRegister(instr.gpr20);
+
+            if (instr.is_b_imm) {
+                op_b += GetImmediate(instr);
             } else {
-                op_b += GetUniform(instr.uniform);
+                if (instr.is_b_gpr) {
+                    op_b += GetRegister(instr.gpr20);
+                } else {
+                    op_b += GetUniform(instr.uniform);
+                }
             }
+
             if (instr.alu.abs_b) {
                 op_b = "abs(" + op_b + ")";
             }
 
             switch (instr.opcode.EffectiveOpCode()) {
             case OpCode::Id::FMUL_C:
-            case OpCode::Id::FMUL_R: {
-                SetDest(0, dest, op_a + " * " + op_b, 1, 1);
+            case OpCode::Id::FMUL_R:
+            case OpCode::Id::FMUL_IMM: {
+                SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
                 break;
             }
             case OpCode::Id::FADD_C:
-            case OpCode::Id::FADD_R: {
-                SetDest(0, dest, op_a + " + " + op_b, 1, 1);
+            case OpCode::Id::FADD_R:
+            case OpCode::Id::FADD_IMM: {
+                SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
                 break;
             }
             case OpCode::Id::MUFU: {
@@ -316,16 +329,28 @@ private:
 
             std::string dest = GetRegister(instr.gpr0);
             std::string op_a = GetRegister(instr.gpr8);
-
             std::string op_b = instr.ffma.negate_b ? "-" : "";
-            op_b += GetUniform(instr.uniform);
-
             std::string op_c = instr.ffma.negate_c ? "-" : "";
-            op_c += GetRegister(instr.gpr39);
 
             switch (instr.opcode.EffectiveOpCode()) {
             case OpCode::Id::FFMA_CR: {
-                SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
+                op_b += GetUniform(instr.uniform);
+                op_c += GetRegister(instr.gpr39);
+                break;
+            }
+            case OpCode::Id::FFMA_RR: {
+                op_b += GetRegister(instr.gpr20);
+                op_c += GetRegister(instr.gpr39);
+                break;
+            }
+            case OpCode::Id::FFMA_RC: {
+                op_b += GetRegister(instr.gpr39);
+                op_c += GetUniform(instr.uniform);
+                break;
+            }
+            case OpCode::Id::FFMA_IMM: {
+                op_b += GetImmediate(instr);
+                op_c += GetRegister(instr.gpr39);
                 break;
             }
             default: {
@@ -336,6 +361,8 @@ private:
                 break;
             }
             }
+
+            SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
             break;
         }
         case OpCode::Type::Memory: {