From fd9e2d0073be84deff02a122d5db8d2917309a61 Mon Sep 17 00:00:00 2001
From: FernandoS27 <fsahmkow27@gmail.com>
Date: Mon, 15 Oct 2018 21:04:20 -0400
Subject: [PATCH 1/4] Implement 3D Textures

---
 src/video_core/engines/maxwell_3d.h                     | 5 ++++-
 src/video_core/renderer_opengl/gl_rasterizer_cache.cpp  | 2 ++
 src/video_core/renderer_opengl/gl_rasterizer_cache.h    | 3 +++
 src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 1 +
 4 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index c8d1b6478b..c8af1c6b67 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -448,7 +448,10 @@ public:
                 BitField<8, 3, u32> block_depth;
                 BitField<12, 1, InvMemoryLayout> type;
             } memory_layout;
-            u32 array_mode;
+            union {
+                BitField<0, 16, u32> array_mode;
+                BitField<16, 1, u32> volume;
+            };
             u32 layer_stride;
             u32 base_layer;
             INSERT_PADDING_WORDS(7);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 1cb77aaf28..b20ef8faef 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -155,6 +155,7 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
     params.rt.index = static_cast<u32>(index);
     params.rt.array_mode = config.array_mode;
     params.rt.layer_stride = config.layer_stride;
+    params.rt.volume = config.volume;
     params.rt.base_layer = config.base_layer;
 
     params.InitCacheParameters(config.Address());
@@ -1213,6 +1214,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
     const bool is_blit{old_params.pixel_format == new_params.pixel_format};
 
     switch (new_params.target) {
+    case SurfaceParams::SurfaceTarget::Texture3D:
     case SurfaceParams::SurfaceTarget::Texture2D:
         if (is_blit) {
             BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 7c1cb72d0f..0dd0d90a38 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -132,6 +132,8 @@ struct SurfaceParams {
         case Tegra::Texture::TextureType::Texture2D:
         case Tegra::Texture::TextureType::Texture2DNoMipmap:
             return SurfaceTarget::Texture2D;
+        case Tegra::Texture::TextureType::Texture3D:
+            return SurfaceTarget::Texture3D;
         case Tegra::Texture::TextureType::TextureCubemap:
             return SurfaceTarget::TextureCubemap;
         case Tegra::Texture::TextureType::Texture1DArray:
@@ -791,6 +793,7 @@ struct SurfaceParams {
     struct {
         u32 index;
         u32 array_mode;
+        u32 volume;
         u32 layer_stride;
         u32 base_layer;
     } rt;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 28dba00844..787de4befc 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1142,6 +1142,7 @@ private:
         case Tegra::Shader::TextureType::Texture2D: {
             return 2;
         }
+        case Tegra::Shader::TextureType::Texture3D:
         case Tegra::Shader::TextureType::TextureCube: {
             return 3;
         }

From dbc34db6ce21dfb119bb8756bde41c9e45f8515f Mon Sep 17 00:00:00 2001
From: FernandoS27 <fsahmkow27@gmail.com>
Date: Mon, 15 Oct 2018 21:09:38 -0400
Subject: [PATCH 2/4] Implement GetInRange in the Rasterizer Cache

---
 src/video_core/rasterizer_cache.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 0a3b3951ee..294b7c6ef6 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -105,6 +105,22 @@ protected:
         return nullptr;
     }
 
+    std::vector<T> GetInRange(Tegra::GPUVAddr addr, size_t size) {
+        std::vector<T> objects;
+        if (size == 0)
+            return objects;
+
+        const ObjectInterval interval{addr, addr + size};
+        for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
+            for (auto& cached_object : pair.second) {
+                if (!cached_object)
+                    continue;
+                objects.push_back(cached_object);
+            }
+        }
+        return objects;
+    }
+
     /// Register an object into the cache
     void Register(const T& object) {
         object->SetIsRegistered(true);

From cb9fdc7a26ecbf62b384c9828a3c9cbcc350b76d Mon Sep 17 00:00:00 2001
From: FernandoS27 <fsahmkow27@gmail.com>
Date: Mon, 15 Oct 2018 21:14:04 -0400
Subject: [PATCH 3/4] Implement Reinterpret Surface, to accurately blit 3D
 textures

---
 src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b20ef8faef..9c89253836 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -1123,8 +1123,8 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
         } else if (preserve_contents) {
             // If surface parameters changed and we care about keeping the previous data, recreate
             // the surface from the old one
-            Unregister(surface);
             Surface new_surface{RecreateSurface(surface, params)};
+            Unregister(surface);
             Register(new_surface);
             return new_surface;
         } else {
@@ -1214,7 +1214,6 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
     const bool is_blit{old_params.pixel_format == new_params.pixel_format};
 
     switch (new_params.target) {
-    case SurfaceParams::SurfaceTarget::Texture3D:
     case SurfaceParams::SurfaceTarget::Texture2D:
         if (is_blit) {
             BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
@@ -1222,6 +1221,9 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
             CopySurface(old_surface, new_surface, copy_pbo.handle);
         }
         break;
+    case SurfaceParams::SurfaceTarget::Texture3D:
+        AccurateCopySurface(old_surface, new_surface);
+        break;
     case SurfaceParams::SurfaceTarget::TextureCubemap: {
         if (old_params.rt.array_mode != 1) {
             // TODO(bunnei): This is used by Breath of the Wild, I'm not sure how to implement this

From caaa9914fd359464a3c54c27ea275130c1778d0f Mon Sep 17 00:00:00 2001
From: FernandoS27 <fsahmkow27@gmail.com>
Date: Tue, 16 Oct 2018 08:03:39 -0400
Subject: [PATCH 4/4] Clang format and other fixes

---
 src/video_core/rasterizer_cache.h | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 294b7c6ef6..0a3b3951ee 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -105,22 +105,6 @@ protected:
         return nullptr;
     }
 
-    std::vector<T> GetInRange(Tegra::GPUVAddr addr, size_t size) {
-        std::vector<T> objects;
-        if (size == 0)
-            return objects;
-
-        const ObjectInterval interval{addr, addr + size};
-        for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
-            for (auto& cached_object : pair.second) {
-                if (!cached_object)
-                    continue;
-                objects.push_back(cached_object);
-            }
-        }
-        return objects;
-    }
-
     /// Register an object into the cache
     void Register(const T& object) {
         object->SetIsRegistered(true);