diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index 6fe7c85aca..0b2b2b8c43 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -247,7 +247,7 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
     params.height = config.height;
     params.pitch = config.pitch;
     // TODO(Rodrigo): Try to guess texture arrays from parameters
-    params.target = params.block_depth > 0 ? SurfaceTarget::Texture3D : SurfaceTarget::Texture2D;
+    params.target = SurfaceTarget::Texture2D;
     params.depth = 1;
     params.num_levels = 1;
     params.emulated_levels = 1;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index b19eeed664..b543fc8c03 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -724,10 +724,35 @@ private:
      * @param params    The parameters on the new surface.
      * @param gpu_addr  The starting address of the new surface.
      * @param cpu_addr  The starting address of the new surface on physical memory.
+     * @param preserve_contents Indicates that the new surface should be loaded from memory or
+     *                          left blank.
      */
     std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(VectorSurface& overlaps,
                                                                const SurfaceParams& params,
-                                                               GPUVAddr gpu_addr, VAddr cpu_addr) {
+                                                               GPUVAddr gpu_addr, VAddr cpu_addr,
+                                                               bool preserve_contents) {
+        if (params.target != SurfaceTarget::Texture3D) {
+            for (const auto& surface : overlaps) {
+                if (!surface->MatchTarget(params.target)) {
+                    if (overlaps.size() == 1 && surface->GetCpuAddr() == cpu_addr) {
+                        if (Settings::IsGPULevelExtreme()) {
+                            return std::nullopt;
+                        }
+                        Unregister(surface);
+                        return InitializeSurface(gpu_addr, params, preserve_contents);
+                    }
+                    return std::nullopt;
+                }
+                if (surface->GetCpuAddr() != cpu_addr) {
+                    continue;
+                }
+                if (surface->MatchesStructure(params) == MatchStructureResult::FullMatch) {
+                    return std::make_pair(surface, surface->GetMainView());
+                }
+            }
+            return InitializeSurface(gpu_addr, params, preserve_contents);
+        }
+
         if (params.num_levels > 1) {
             // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach
             return std::nullopt;
@@ -748,25 +773,18 @@ private:
             }
         }
 
-        if (params.depth == 1) {
-            return std::nullopt;
-        }
-
         TSurface new_surface = GetUncachedSurface(gpu_addr, params);
-        LoadSurface(new_surface);
-
         bool modified = false;
+
         for (auto& surface : overlaps) {
             const SurfaceParams& src_params = surface->GetSurfaceParams();
-            if (src_params.height != params.height ||
+            if (src_params.target != SurfaceTarget::Texture2D ||
+                src_params.height != params.height ||
                 src_params.block_depth != params.block_depth ||
                 src_params.block_height != params.block_height) {
                 return std::nullopt;
             }
-            if (!surface->IsModified()) {
-                continue;
-            }
-            modified = true;
+            modified |= surface->IsModified();
 
             const u32 offset = static_cast<u32>(surface->GetCpuAddr() - cpu_addr);
             const u32 slice = std::get<2>(params.GetBlockOffsetXYZ(offset));
@@ -781,7 +799,7 @@ private:
         new_surface->MarkAsModified(modified, Tick());
         Register(new_surface);
 
-        auto view = new_surface->GetMainView();
+        TView view = new_surface->GetMainView();
         return std::make_pair(std::move(new_surface), std::move(view));
     }
 
@@ -861,8 +879,9 @@ private:
         }
 
         // Manage 3D textures
-        if (params.target == SurfaceTarget::Texture3D) {
-            auto surface = Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr);
+        if (params.block_depth > 0) {
+            auto surface =
+                Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr, preserve_contents);
             if (surface) {
                 return *surface;
             }