From fefb003b23ab4a7be28e7bb0e8a8fa9802b3cb1a Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 14 Sep 2018 11:42:28 -0400
Subject: [PATCH] gl_rasterizer_cache: Workaround for Texture2D ->
 Texture2DArray scenario.

---
 .../renderer_opengl/gl_rasterizer.cpp          |  2 +-
 .../renderer_opengl/gl_rasterizer_cache.cpp    | 18 +++++++++++++++---
 .../renderer_opengl/gl_rasterizer_cache.h      |  7 +++++--
 3 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 1fcd13f048..14d82a7bcc 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -738,7 +738,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
         }
 
         texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
-        Surface surface = res_cache.GetTextureSurface(texture);
+        Surface surface = res_cache.GetTextureSurface(texture, entry);
         if (surface != nullptr) {
             state.texture_units[current_bindpoint].texture = surface->Texture().handle;
             state.texture_units[current_bindpoint].target = surface->Target();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b112069251..00351d743d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -41,7 +41,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
 }
 
 /*static*/ SurfaceParams SurfaceParams::CreateForTexture(
-    const Tegra::Texture::FullTextureInfo& config) {
+    const Tegra::Texture::FullTextureInfo& config, const GLShader::SamplerEntry& entry) {
     SurfaceParams params{};
     params.addr = TryGetCpuAddr(config.tic.Address());
     params.is_tiled = config.tic.IsTiled();
@@ -61,8 +61,19 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
         params.depth = 1;
         break;
     case SurfaceTarget::Texture3D:
+        params.depth = config.tic.Depth();
+        break;
     case SurfaceTarget::Texture2DArray:
         params.depth = config.tic.Depth();
+        if (!entry.IsArray()) {
+            // TODO(bunnei): We have seen games re-use a Texture2D as Texture2DArray with depth of
+            // one, but sample the texture in the shader as if it were not an array texture. This
+            // probably is valid on hardware, but we still need to write a test to confirm this. In
+            // emulation, the workaround here is to continue to treat this as a Texture2D. An
+            // example game that does this is Super Mario Odyssey (in Cloud Kingdom).
+            ASSERT(params.depth == 1);
+            params.target = SurfaceTarget::Texture2D;
+        }
         break;
     default:
         LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target));
@@ -726,8 +737,9 @@ RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
     copy_pbo.Create();
 }
 
-Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
-    return GetSurface(SurfaceParams::CreateForTexture(config));
+Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
+                                                 const GLShader::SamplerEntry& entry) {
+    return GetSurface(SurfaceParams::CreateForTexture(config, entry));
 }
 
 Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 9df909d013..6474d91298 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -15,6 +15,7 @@
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/rasterizer_cache.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
+#include "video_core/renderer_opengl/gl_shader_gen.h"
 #include "video_core/textures/texture.h"
 
 namespace OpenGL {
@@ -704,7 +705,8 @@ struct SurfaceParams {
     }
 
     /// Creates SurfaceParams from a texture configuration
-    static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config);
+    static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config,
+                                          const GLShader::SamplerEntry& entry);
 
     /// Creates SurfaceParams from a framebuffer configuration
     static SurfaceParams CreateForFramebuffer(std::size_t index);
@@ -806,7 +808,8 @@ public:
     RasterizerCacheOpenGL();
 
     /// Get a surface based on the texture configuration
-    Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config);
+    Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
+                              const GLShader::SamplerEntry& entry);
 
     /// Get the depth surface based on the framebuffer configuration
     Surface GetDepthBufferSurface(bool preserve_contents);