diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 5d8d126c18..3224531162 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -202,11 +202,12 @@ const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
 }
 
 bool MemoryManager::IsBlockContinuous(const GPUVAddr start, const std::size_t size) const {
-    const GPUVAddr end = start + size;
+    const std::size_t inner_size = size - 1;
+    const GPUVAddr end = start + inner_size;
     const auto host_ptr_start = reinterpret_cast<std::uintptr_t>(GetPointer(start));
     const auto host_ptr_end = reinterpret_cast<std::uintptr_t>(GetPointer(end));
     const auto range = static_cast<std::size_t>(host_ptr_end - host_ptr_start);
-    return range == size;
+    return range == inner_size;
 }
 
 void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const {
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp
index d4aa2c54be..7e90960f79 100644
--- a/src/video_core/texture_cache/surface_base.cpp
+++ b/src/video_core/texture_cache/surface_base.cpp
@@ -68,12 +68,27 @@ void SurfaceBaseImpl::SwizzleFunc(MortonSwizzleMode mode, u8* memory, const Surf
 }
 
 void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager,
-                                 std::vector<u8>& staging_buffer) {
+                                 StagingCache& staging_cache) {
     MICROPROFILE_SCOPE(GPU_Load_Texture);
-    const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
-    if (!host_ptr) {
-        return;
+    auto& staging_buffer = staging_cache.GetBuffer(0);
+    u8* host_ptr;
+    is_continuous = memory_manager.IsBlockContinuous(gpu_addr, guest_memory_size);
+
+    // Handle continuouty
+    if (is_continuous) {
+        // Use physical memory directly
+        host_ptr = memory_manager.GetPointer(gpu_addr);
+        if (!host_ptr) {
+            return;
+        }
+    } else {
+        // Use an extra temporal buffer
+        auto& tmp_buffer = staging_cache.GetBuffer(1);
+        tmp_buffer.resize(guest_memory_size);
+        host_ptr = tmp_buffer.data();
+        memory_manager.ReadBlockUnsafe(gpu_addr, host_ptr, guest_memory_size);
     }
+
     if (params.is_tiled) {
         ASSERT_MSG(params.block_width == 0, "Block width is defined as {} on texture target {}",
                    params.block_width, static_cast<u32>(params.target));
@@ -123,12 +138,25 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager,
 }
 
 void SurfaceBaseImpl::FlushBuffer(Tegra::MemoryManager& memory_manager,
-                                  std::vector<u8>& staging_buffer) {
+                                  StagingCache& staging_cache) {
     MICROPROFILE_SCOPE(GPU_Flush_Texture);
-    const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
-    if (!host_ptr) {
-        return;
+    auto& staging_buffer = staging_cache.GetBuffer(0);
+    u8* host_ptr;
+
+    // Handle continuouty
+    if (is_continuous) {
+        // Use physical memory directly
+        host_ptr = memory_manager.GetPointer(gpu_addr);
+        if (!host_ptr) {
+            return;
+        }
+    } else {
+        // Use an extra temporal buffer
+        auto& tmp_buffer = staging_cache.GetBuffer(1);
+        tmp_buffer.resize(guest_memory_size);
+        host_ptr = tmp_buffer.data();
     }
+
     if (params.is_tiled) {
         ASSERT_MSG(params.block_width == 0, "Block width is defined as {}", params.block_width);
         for (u32 level = 0; level < params.num_levels; ++level) {
@@ -154,6 +182,9 @@ void SurfaceBaseImpl::FlushBuffer(Tegra::MemoryManager& memory_manager,
             }
         }
     }
+    if (!is_continuous) {
+        memory_manager.WriteBlockUnsafe(gpu_addr, host_ptr, guest_memory_size);
+    }
 }
 
 } // namespace VideoCommon
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h
index 210f279075..dacbc97c74 100644
--- a/src/video_core/texture_cache/surface_base.h
+++ b/src/video_core/texture_cache/surface_base.h
@@ -32,11 +32,28 @@ enum class MatchStructureResult : u32 {
     None = 2,
 };
 
+class StagingCache {
+public:
+    StagingCache() {}
+    ~StagingCache() = default;
+
+    std::vector<u8>& GetBuffer(std::size_t index) {
+        return staging_buffer[index];
+    }
+
+    void SetSize(std::size_t size) {
+        staging_buffer.resize(size);
+    }
+
+private:
+    std::vector<std::vector<u8>> staging_buffer;
+};
+
 class SurfaceBaseImpl {
 public:
-    void LoadBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
+    void LoadBuffer(Tegra::MemoryManager& memory_manager, StagingCache& staging_cache);
 
-    void FlushBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
+    void FlushBuffer(Tegra::MemoryManager& memory_manager, StagingCache& staging_cache);
 
     GPUVAddr GetGpuAddr() const {
         return gpu_addr;
@@ -93,6 +110,14 @@ public:
         return mipmap_sizes[level];
     }
 
+    void MarkAsContinuous(const bool is_continuous) {
+        this->is_continuous = is_continuous;
+    }
+
+    bool IsContinuous() const {
+        return is_continuous;
+    }
+
     bool IsLinear() const {
         return !params.is_tiled;
     }
@@ -122,8 +147,8 @@ public:
     MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const {
         // Buffer surface Check
         if (params.IsBuffer()) {
-            const std::size_t wd1 = params.width*params.GetBytesPerPixel();
-            const std::size_t wd2 = rhs.width*rhs.GetBytesPerPixel();
+            const std::size_t wd1 = params.width * params.GetBytesPerPixel();
+            const std::size_t wd2 = rhs.width * rhs.GetBytesPerPixel();
             if (wd1 == wd2) {
                 return MatchStructureResult::FullMatch;
             }
@@ -193,6 +218,7 @@ protected:
     CacheAddr cache_addr{};
     CacheAddr cache_addr_end{};
     VAddr cpu_addr{};
+    bool is_continuous{};
 
     std::vector<std::size_t> mipmap_sizes;
     std::vector<std::size_t> mipmap_offsets;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 24c87127d9..ab4e094ea4 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -220,6 +220,7 @@ protected:
             SetEmptyColorBuffer(i);
         }
         SetEmptyDepthBuffer();
+        staging_cache.SetSize(2);
     }
 
     ~TextureCache() = default;
@@ -244,6 +245,8 @@ protected:
                          gpu_addr);
             return;
         }
+        bool continuouty = memory_manager->IsBlockContinuous(gpu_addr, size);
+        surface->MarkAsContinuous(continuouty);
         surface->SetCacheAddr(cache_ptr);
         surface->SetCpuAddr(*cpu_addr);
         RegisterInnerCache(surface);
@@ -611,9 +614,9 @@ private:
     }
 
     void LoadSurface(const TSurface& surface) {
-        staging_buffer.resize(surface->GetHostSizeInBytes());
-        surface->LoadBuffer(*memory_manager, staging_buffer);
-        surface->UploadTexture(staging_buffer);
+        staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
+        surface->LoadBuffer(*memory_manager, staging_cache);
+        surface->UploadTexture(staging_cache.GetBuffer(0));
         surface->MarkAsModified(false, Tick());
     }
 
@@ -621,9 +624,9 @@ private:
         if (!surface->IsModified()) {
             return;
         }
-        staging_buffer.resize(surface->GetHostSizeInBytes());
-        surface->DownloadTexture(staging_buffer);
-        surface->FlushBuffer(*memory_manager, staging_buffer);
+        staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
+        surface->DownloadTexture(staging_cache.GetBuffer(0));
+        surface->FlushBuffer(*memory_manager, staging_cache);
         surface->MarkAsModified(false, Tick());
     }
 
@@ -723,7 +726,7 @@ private:
         render_targets;
     FramebufferTargetInfo depth_buffer;
 
-    std::vector<u8> staging_buffer;
+    StagingCache staging_cache;
     std::recursive_mutex mutex;
 };