From 8b4443c966c1f00ca468f41584b74fe22a4580af Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Tue, 10 Apr 2018 01:26:15 -0400
Subject: [PATCH] gl_shader_decompiler: Add support for TEXS instruction.

---
 src/video_core/engines/shader_bytecode.h      | 19 +++++++---
 .../renderer_opengl/gl_shader_decompiler.cpp  | 36 +++++++++++++++----
 2 files changed, 43 insertions(+), 12 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index eff0c35a15..51cf4af9f6 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -16,10 +16,6 @@ struct Register {
 
     constexpr Register(u64 value) : value(value) {}
 
-    constexpr u64 GetIndex() const {
-        return value;
-    }
-
     constexpr operator u64() const {
         return value;
     }
@@ -71,6 +67,19 @@ union Attribute {
     u64 value;
 };
 
+union Sampler {
+    Sampler() = default;
+
+    constexpr Sampler(u64 value) : value(value) {}
+
+    enum class Index : u64 {
+        Sampler_0 = 8,
+    };
+
+    BitField<36, 13, Index> index;
+    u64 value;
+};
+
 union Uniform {
     BitField<20, 14, u64> offset;
     BitField<34, 5, u64> index;
@@ -295,7 +304,6 @@ union Instruction {
     BitField<20, 8, Register> gpr20;
     BitField<20, 7, SubOp> sub_op;
     BitField<28, 8, Register> gpr28;
-    BitField<36, 13, u64> imm36;
     BitField<39, 8, Register> gpr39;
 
     union {
@@ -316,6 +324,7 @@ union Instruction {
 
     Attribute attribute;
     Uniform uniform;
+    Sampler sampler;
 
     u64 hex;
 };
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index ba3aa7dd17..a8f1ac5b56 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -17,6 +17,7 @@ using Tegra::Shader::Attribute;
 using Tegra::Shader::Instruction;
 using Tegra::Shader::OpCode;
 using Tegra::Shader::Register;
+using Tegra::Shader::Sampler;
 using Tegra::Shader::SubOp;
 using Tegra::Shader::Uniform;
 
@@ -186,13 +187,13 @@ private:
     }
 
     /// Generates code representing a temporary (GPR) register.
-    std::string GetRegister(const Register& reg) {
-        if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg.GetIndex() < 4) {
+    std::string GetRegister(const Register& reg, unsigned elem = 0) {
+        if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
             // GPRs 0-3 are output color for the fragment shader
-            return std::string{"color."} + "rgba"[reg.GetIndex()];
+            return std::string{"color."} + "rgba"[reg + elem];
         }
 
-        return *declr_register.insert("register_" + std::to_string(reg)).first;
+        return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
     }
 
     /// Generates code representing a uniform (C buffer) register.
@@ -201,6 +202,15 @@ private:
         return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
     }
 
+    /// Generates code representing a texture sampler.
+    std::string GetSampler(const Sampler& sampler) const {
+        // TODO(Subv): Support more than just texture sampler 0
+        ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
+        const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
+                             static_cast<unsigned>(Sampler::Index::Sampler_0)};
+        return "tex[" + std::to_string(index) + "]";
+    }
+
     /**
      * Adds code that calls a subroutine.
      * @param subroutine the subroutine to call.
@@ -245,7 +255,7 @@ private:
 
         switch (OpCode::GetInfo(instr.opcode).type) {
         case OpCode::Type::Arithmetic: {
-            ASSERT(!instr.alu.abs_d);
+            ASSERT_MSG(!instr.alu.abs_d, "unimplemented");
 
             std::string dest = GetRegister(instr.gpr0);
             std::string op_a = instr.alu.negate_a ? "-" : "";
@@ -330,15 +340,27 @@ private:
 
             switch (instr.opcode.EffectiveOpCode()) {
             case OpCode::Id::LD_A: {
-                ASSERT(instr.attribute.fmt20.size == 0);
+                ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
                 SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
                 break;
             }
             case OpCode::Id::ST_A: {
-                ASSERT(instr.attribute.fmt20.size == 0);
+                ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
                 SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
                 break;
             }
+            case OpCode::Id::TEXS: {
+                ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
+                const std::string op_a = GetRegister(instr.gpr8);
+                const std::string op_b = GetRegister(instr.gpr20);
+                const std::string sampler = GetSampler(instr.sampler);
+                const std::string coord = "vec2(" + op_a + ", " + op_b + ")";
+                const std::string texture = "texture(" + sampler + ", " + coord + ")";
+                for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
+                    SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
+                }
+                break;
+            }
             default: {
                 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: 0x%02x (%s): 0x%08x",
                              static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
-- 
GitLab