From 0f664ef89d68bb008c386680a7b1d747d50ac698 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Wed, 3 May 2017 19:59:48 +0300
Subject: [PATCH 1/2] pica: use correct coordinates for texture 2

---
 src/video_core/regs_texturing.h                 |  4 ++++
 .../renderer_opengl/gl_shader_gen.cpp           | 17 ++++++++++++++---
 src/video_core/renderer_opengl/gl_shader_gen.h  |  1 +
 src/video_core/swrasterizer/rasterizer.cpp      |  5 +++--
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/src/video_core/regs_texturing.h b/src/video_core/regs_texturing.h
index 0b62da1457..515848bd69 100644
--- a/src/video_core/regs_texturing.h
+++ b/src/video_core/regs_texturing.h
@@ -122,6 +122,10 @@ struct TexturingRegs {
         BitField<0, 1, u32> texture0_enable;
         BitField<1, 1, u32> texture1_enable;
         BitField<2, 1, u32> texture2_enable;
+        BitField<8, 2, u32> texture3_coordinates; // TODO: unimplemented
+        BitField<10, 1, u32> texture3_enable;     // TODO: unimplemented
+        BitField<13, 1, u32> texture2_use_coord1;
+        BitField<16, 1, u32> clear_texture_cache; // TODO: unimplemented
     };
     TextureConfig texture0;
     INSERT_PADDING_WORDS(0x8);
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 0f889b1725..5077e38b7e 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -40,6 +40,8 @@ PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) {
 
     state.texture0_type = regs.texturing.texture0.type;
 
+    state.texture2_use_coord1 = regs.texturing.texture2_use_coord1 != 0;
+
     // Copy relevant tev stages fields.
     // We don't sync const_color here because of the high variance, it is a
     // shader uniform instead.
@@ -126,6 +128,15 @@ static bool IsPassThroughTevStage(const TevStageConfig& stage) {
             stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
 }
 
+static std::string TexCoord(const PicaShaderConfig& config, int texture_unit) {
+    if (texture_unit == 2 && config.state.texture2_use_coord1) {
+        return "texcoord[1]";
+    }
+    // TODO: if texture unit 3 (procedural texture) implementation also uses this function,
+    //       config.state.texture3_coordinates should be repected here.
+    return "texcoord[" + std::to_string(texture_unit) + "]";
+}
+
 /// Writes the specified TEV stage source component(s)
 static void AppendSource(std::string& out, const PicaShaderConfig& config,
                          TevStageConfig::Source source, const std::string& index_name) {
@@ -162,7 +173,7 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config,
         out += "texture(tex[1], texcoord[1])";
         break;
     case Source::Texture2:
-        out += "texture(tex[2], texcoord[2])";
+        out += "texture(tex[2], " + TexCoord(config, 2) + ")";
         break;
     case Source::PreviousBuffer:
         out += "combiner_buffer";
@@ -473,8 +484,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
         // Bump mapping is enabled using a normal map, read perturbation vector from the selected
         // texture
         std::string bump_selector = std::to_string(lighting.bump_selector);
-        out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" +
-               bump_selector + "]).rgb - 1.0;\n";
+        out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], " +
+               TexCoord(config, lighting.bump_selector) + ").rgb - 1.0;\n";
 
         // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher
         // precision result
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index 921d976a10..3fb046b76e 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -79,6 +79,7 @@ union PicaShaderConfig {
         Pica::FramebufferRegs::CompareFunc alpha_test_func;
         Pica::RasterizerRegs::ScissorMode scissor_test_mode;
         Pica::TexturingRegs::TextureConfig::TextureType texture0_type;
+        bool texture2_use_coord1;
         std::array<TevStageConfigRaw, 6> tev_stages;
         u8 combiner_buffer_input;
 
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index cb1b90a817..fa8377f80e 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -276,8 +276,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
 
                 DEBUG_ASSERT(0 != texture.config.address);
 
-                float24 u = uv[i].u();
-                float24 v = uv[i].v();
+                int coordinate_i = (i == 2 && regs.texturing.texture2_use_coord1) ? 1 : i;
+                float24 u = uv[coordinate_i].u();
+                float24 v = uv[coordinate_i].v();
 
                 // Only unit 0 respects the texturing type (according to 3DBrew)
                 // TODO: Refactor so cubemaps and shadowmaps can be handled

From 039b2930928c34c011fcc236d7f8c32599077ad0 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Fri, 5 May 2017 15:29:35 +0300
Subject: [PATCH 2/2] pica: shader_dirty if texture2 coord changed

---
 src/video_core/regs.h                            | 2 +-
 src/video_core/regs_texturing.h                  | 8 ++++----
 src/video_core/renderer_opengl/gl_rasterizer.cpp | 4 ++++
 src/video_core/renderer_opengl/gl_shader_gen.cpp | 2 +-
 src/video_core/swrasterizer/rasterizer.cpp       | 3 ++-
 5 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/video_core/regs.h b/src/video_core/regs.h
index 86826088b0..1776dad89b 100644
--- a/src/video_core/regs.h
+++ b/src/video_core/regs.h
@@ -93,7 +93,7 @@ ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68);
 ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D);
 
 ASSERT_REG_POSITION(texturing, 0x80);
-ASSERT_REG_POSITION(texturing.texture0_enable, 0x80);
+ASSERT_REG_POSITION(texturing.main_config, 0x80);
 ASSERT_REG_POSITION(texturing.texture0, 0x81);
 ASSERT_REG_POSITION(texturing.texture0_format, 0x8e);
 ASSERT_REG_POSITION(texturing.fragment_lighting_enable, 0x8f);
diff --git a/src/video_core/regs_texturing.h b/src/video_core/regs_texturing.h
index 515848bd69..8a7c6efe4e 100644
--- a/src/video_core/regs_texturing.h
+++ b/src/video_core/regs_texturing.h
@@ -126,7 +126,7 @@ struct TexturingRegs {
         BitField<10, 1, u32> texture3_enable;     // TODO: unimplemented
         BitField<13, 1, u32> texture2_use_coord1;
         BitField<16, 1, u32> clear_texture_cache; // TODO: unimplemented
-    };
+    } main_config;
     TextureConfig texture0;
     INSERT_PADDING_WORDS(0x8);
     BitField<0, 4, TextureFormat> texture0_format;
@@ -146,9 +146,9 @@ struct TexturingRegs {
     };
     const std::array<FullTextureConfig, 3> GetTextures() const {
         return {{
-            {texture0_enable.ToBool(), texture0, texture0_format},
-            {texture1_enable.ToBool(), texture1, texture1_format},
-            {texture2_enable.ToBool(), texture2, texture2_format},
+            {main_config.texture0_enable.ToBool(), texture0, texture0_format},
+            {main_config.texture1_enable.ToBool(), texture1, texture1_format},
+            {main_config.texture2_enable.ToBool(), texture2, texture2_format},
         }};
     }
 
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a473070991..12ac9bbd97 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -402,6 +402,10 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
         SyncLogicOp();
         break;
 
+    case PICA_REG_INDEX(texturing.main_config):
+        shader_dirty = true;
+        break;
+
     // Texture 0 type
     case PICA_REG_INDEX(texturing.texture0.type):
         shader_dirty = true;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 5077e38b7e..7b44dade81 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -40,7 +40,7 @@ PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) {
 
     state.texture0_type = regs.texturing.texture0.type;
 
-    state.texture2_use_coord1 = regs.texturing.texture2_use_coord1 != 0;
+    state.texture2_use_coord1 = regs.texturing.main_config.texture2_use_coord1 != 0;
 
     // Copy relevant tev stages fields.
     // We don't sync const_color here because of the high variance, it is a
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index fa8377f80e..20addf0bdb 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -276,7 +276,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
 
                 DEBUG_ASSERT(0 != texture.config.address);
 
-                int coordinate_i = (i == 2 && regs.texturing.texture2_use_coord1) ? 1 : i;
+                int coordinate_i =
+                    (i == 2 && regs.texturing.main_config.texture2_use_coord1) ? 1 : i;
                 float24 u = uv[coordinate_i].u();
                 float24 v = uv[coordinate_i].v();