From 335df895b9f9e9760ed5cd0d6dfaea8befb94dac Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 18 Dec 2016 17:25:03 -0800
Subject: [PATCH] VideoCore: Consistently use shader configuration to load
 attributes

---
 .../graphics/graphics_vertex_shader.cpp       |  6 +--
 src/video_core/command_processor.cpp          |  4 +-
 src/video_core/pica.h                         | 37 ++++---------------
 src/video_core/shader/shader.cpp              | 11 +++---
 src/video_core/shader/shader.h                |  6 +--
 src/video_core/shader/shader_interpreter.cpp  |  4 +-
 src/video_core/shader/shader_interpreter.h    |  3 +-
 7 files changed, 25 insertions(+), 46 deletions(-)

diff --git a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
index f37524190..489ec5f21 100644
--- a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
@@ -511,7 +511,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
     auto& shader_config = Pica::g_state.regs.vs;
     for (auto instr : shader_setup.program_code)
         info.code.push_back({instr});
-    int num_attributes = Pica::g_state.regs.vertex_attributes.GetNumTotalAttributes();
+    int num_attributes = shader_config.max_input_attribute_index + 1;
 
     for (auto pattern : shader_setup.swizzle_data)
         info.swizzle_info.push_back({pattern});
@@ -522,11 +522,11 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
     // Generate debug information
     Pica::Shader::InterpreterEngine shader_engine;
     shader_engine.SetupBatch(shader_setup, entry_point);
-    debug_data = shader_engine.ProduceDebugInfo(shader_setup, input_vertex, num_attributes);
+    debug_data = shader_engine.ProduceDebugInfo(shader_setup, input_vertex, shader_config);
 
     // Reload widget state
     for (int attr = 0; attr < num_attributes; ++attr) {
-        unsigned source_attr = shader_config.input_register_map.GetRegisterForAttribute(attr);
+        unsigned source_attr = shader_config.GetRegisterForAttribute(attr);
         input_data_mapping[attr]->setText(QString("-> v%1").arg(source_attr));
         input_data_container[attr]->setVisible(true);
     }
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 27b7a023f..fef0b4ceb 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -151,7 +151,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
                         g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
                                                  static_cast<void*>(&immediate_input));
                     Shader::UnitState shader_unit;
-                    shader_unit.LoadInput(immediate_input, regs.vs.max_input_attribute_index + 1);
+                    shader_unit.LoadInput(regs.vs, immediate_input);
                     shader_engine->Run(g_state.vs, shader_unit);
                     auto output_vertex = Shader::OutputVertex::FromRegisters(
                         shader_unit.registers.output, regs, regs.vs.output_mask);
@@ -288,7 +288,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
                 if (g_debug_context)
                     g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
                                              (void*)&input);
-                shader_unit.LoadInput(input, loader.GetNumTotalAttributes());
+                shader_unit.LoadInput(regs.vs, input);
                 shader_engine->Run(g_state.vs, shader_unit);
 
                 // Retrieve vertex from register data
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index c772896e0..ac81a3d0f 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -1225,36 +1225,15 @@ struct Regs {
         // Offset to shader program entry point (in words)
         BitField<0, 16, u32> main_offset;
 
-        union {
-            BitField<0, 4, u64> attribute0_register;
-            BitField<4, 4, u64> attribute1_register;
-            BitField<8, 4, u64> attribute2_register;
-            BitField<12, 4, u64> attribute3_register;
-            BitField<16, 4, u64> attribute4_register;
-            BitField<20, 4, u64> attribute5_register;
-            BitField<24, 4, u64> attribute6_register;
-            BitField<28, 4, u64> attribute7_register;
-            BitField<32, 4, u64> attribute8_register;
-            BitField<36, 4, u64> attribute9_register;
-            BitField<40, 4, u64> attribute10_register;
-            BitField<44, 4, u64> attribute11_register;
-            BitField<48, 4, u64> attribute12_register;
-            BitField<52, 4, u64> attribute13_register;
-            BitField<56, 4, u64> attribute14_register;
-            BitField<60, 4, u64> attribute15_register;
+        /// Maps input attributes to registers. 4-bits per attribute, specifying a register index
+        u32 input_attribute_to_register_map_low;
+        u32 input_attribute_to_register_map_high;
 
-            int GetRegisterForAttribute(int attribute_index) const {
-                u64 fields[] = {
-                    attribute0_register,  attribute1_register,  attribute2_register,
-                    attribute3_register,  attribute4_register,  attribute5_register,
-                    attribute6_register,  attribute7_register,  attribute8_register,
-                    attribute9_register,  attribute10_register, attribute11_register,
-                    attribute12_register, attribute13_register, attribute14_register,
-                    attribute15_register,
-                };
-                return (int)fields[attribute_index];
-            }
-        } input_register_map;
+        unsigned int GetRegisterForAttribute(unsigned int attribute_index) const {
+            u64 map = ((u64)input_attribute_to_register_map_high << 32) |
+                      (u64)input_attribute_to_register_map_low;
+            return (map >> (attribute_index * 4)) & 0b1111;
+        }
 
         BitField<0, 16, u32> output_mask;
 
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 971ce5b7a..dbad167e9 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -71,12 +71,13 @@ OutputVertex OutputVertex::FromRegisters(Math::Vec4<float24> output_regs[16], co
     return ret;
 }
 
-void UnitState::LoadInput(const AttributeBuffer& input, int num_attributes) {
-    // Setup input register table
-    const auto& attribute_register_map = g_state.regs.vs.input_register_map;
+void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input) {
+    const unsigned max_attribute = config.max_input_attribute_index;
 
-    for (int i = 0; i < num_attributes; i++)
-        registers.input[attribute_register_map.GetRegisterForAttribute(i)] = input.attr[i];
+    for (unsigned attr = 0; attr <= max_attribute; ++attr) {
+        unsigned reg = config.GetRegisterForAttribute(attr);
+        registers.input[reg] = input.attr[attr];
+    }
 }
 
 MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index cb38ec0a6..43a8b848c 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -137,10 +137,10 @@ struct UnitState {
     /**
      * Loads the unit state with an input vertex.
      *
-     * @param input Input vertex into the shader
-     * @param num_attributes The number of vertex shader attributes to load
+     * @param config Shader configuration registers corresponding to the unit.
+     * @param input Attribute buffer to load into the input registers.
      */
-    void LoadInput(const AttributeBuffer& input, int num_attributes);
+    void LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input);
 };
 
 struct ShaderSetup {
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp
index d803aebbf..81522b8f5 100644
--- a/src/video_core/shader/shader_interpreter.cpp
+++ b/src/video_core/shader/shader_interpreter.cpp
@@ -669,13 +669,13 @@ void InterpreterEngine::Run(const ShaderSetup& setup, UnitState& state) const {
 
 DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup,
                                                     const AttributeBuffer& input,
-                                                    int num_attributes) const {
+                                                    const Regs::ShaderConfig& config) const {
     UnitState state;
     DebugData<true> debug_data;
 
     // Setup input register table
     boost::fill(state.registers.input, Math::Vec4<float24>::AssignToAll(float24::Zero()));
-    state.LoadInput(input, num_attributes);
+    state.LoadInput(config, input);
     RunInterpreter(setup, state, debug_data, setup.engine_data.entry_point);
     return debug_data;
 }
diff --git a/src/video_core/shader/shader_interpreter.h b/src/video_core/shader/shader_interpreter.h
index 593e02157..d7a61e122 100644
--- a/src/video_core/shader/shader_interpreter.h
+++ b/src/video_core/shader/shader_interpreter.h
@@ -19,12 +19,11 @@ public:
     /**
      * Produce debug information based on the given shader and input vertex
      * @param input Input vertex into the shader
-     * @param num_attributes The number of vertex shader attributes
      * @param config Configuration object for the shader pipeline
      * @return Debug information for this shader with regards to the given vertex
      */
     DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input,
-                                     int num_attributes) const;
+                                     const Regs::ShaderConfig& config) const;
 };
 
 } // namespace