diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h
index 9d19ecd5fe..58265e9d39 100644
--- a/src/video_core/texture_cache/surface_base.h
+++ b/src/video_core/texture_cache/surface_base.h
@@ -132,6 +132,10 @@ public:
         return params.pixel_format == pixel_format;
     }
 
+    VideoCore::Surface::PixelFormat GetFormat() const {
+        return params.pixel_format;
+    }
+
     bool MatchTarget(VideoCore::Surface::SurfaceTarget target) const {
         return params.target == target;
     }
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index c95b1b9764..0224167060 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -43,6 +43,8 @@ class RasterizerInterface;
 
 namespace VideoCommon {
 
+using VideoCore::Surface::PixelFormat;
+
 using VideoCore::Surface::SurfaceTarget;
 using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig;
 
@@ -96,7 +98,7 @@ public:
             return {};
         }
         const auto params{SurfaceParams::CreateForTexture(system, config, entry)};
-        return GetSurface(gpu_addr, params, true).second;
+        return GetSurface(gpu_addr, params, true, false).second;
     }
 
     TView GetDepthBufferSurface(bool preserve_contents) {
@@ -118,7 +120,7 @@ public:
             system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
             regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
             regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
-        auto surface_view = GetSurface(gpu_addr, depth_params, preserve_contents);
+        auto surface_view = GetSurface(gpu_addr, depth_params, preserve_contents, true);
         if (depth_buffer.target)
             depth_buffer.target->MarkAsRenderTarget(false);
         depth_buffer.target = surface_view.first;
@@ -152,7 +154,7 @@ public:
         }
 
         auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
-                                       preserve_contents);
+                                       preserve_contents, true);
         if (render_targets[index].target)
             render_targets[index].target->MarkAsRenderTarget(false);
         render_targets[index].target = surface_view.first;
@@ -226,6 +228,11 @@ protected:
         }
         SetEmptyDepthBuffer();
         staging_cache.SetSize(2);
+        siblings_table[PixelFormat::Z16] = PixelFormat::R16F;
+        siblings_table[PixelFormat::Z32F] = PixelFormat::R32F;
+        siblings_table[PixelFormat::Z32FS8] = PixelFormat::RG32F;
+        siblings_table[PixelFormat::R16F] = PixelFormat::Z16;
+        siblings_table[PixelFormat::R32F] = PixelFormat::Z32F;
     }
 
     ~TextureCache() = default;
@@ -289,7 +296,7 @@ protected:
         const Tegra::Engines::Fermi2D::Regs::Surface& config) {
         SurfaceParams params = SurfaceParams::CreateForFermiCopySurface(config);
         const GPUVAddr gpu_addr = config.Address();
-        return GetSurface(gpu_addr, params, true);
+        return GetSurface(gpu_addr, params, true, false);
     }
 
     Core::System& system;
@@ -406,16 +413,22 @@ private:
      * @param params, the new surface params which we want to check.
      **/
     std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface,
-                                                     const SurfaceParams& params) {
+                                                     const SurfaceParams& params, bool is_render) {
         const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
+        const bool matches_target = current_surface->MatchTarget(params.target);
+        auto match_check = ([&]() -> std::pair<TSurface, TView> {
+            if (matches_target) {
+                return {current_surface, current_surface->GetMainView()};
+            }
+            return {current_surface, current_surface->EmplaceOverview(params)};
+        });
         if (is_mirage) {
+            if (!is_render && siblings_table[current_surface->GetFormat()] == params.pixel_format) {
+                return match_check();
+            }
             return RebuildSurface(current_surface, params);
         }
-        const bool matches_target = current_surface->MatchTarget(params.target);
-        if (matches_target) {
-            return {current_surface, current_surface->GetMainView()};
-        }
-        return {current_surface, current_surface->EmplaceOverview(params)};
+        return match_check();
     }
 
     /**
@@ -490,7 +503,7 @@ private:
      * @param preserve_contents, tells if the new surface should be loaded from meory or left blank.
      **/
     std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params,
-                                          bool preserve_contents) {
+                                          bool preserve_contents, bool is_render) {
 
         const auto host_ptr{memory_manager->GetPointer(gpu_addr)};
         const auto cache_addr{ToCacheAddr(host_ptr)};
@@ -524,7 +537,7 @@ private:
                 (params.target != SurfaceTarget::Texture3D ||
                  current_surface->MatchTarget(params.target))) {
                 if (s_result == MatchStructureResult::FullMatch) {
-                    return ManageStructuralMatch(current_surface, params);
+                    return ManageStructuralMatch(current_surface, params, is_render);
                 } else {
                     return RebuildSurface(current_surface, params);
                 }
@@ -724,6 +737,8 @@ private:
     // Guards the cache for protection conflicts.
     bool guard_cache{};
 
+    std::unordered_map<PixelFormat, PixelFormat> siblings_table;
+
     // The internal Cache is different for the Texture Cache. It's based on buckets
     // of 1MB. This fits better for the purpose of this cache as textures are normaly
     // large in size.