Bläddra i källkod

Merge pull request #6820 from yzct12345/split-cache

texture_cache: Split out template definitions
Fernando S 5 år sedan
förälder
incheckning
6a082df427

+ 3 - 0
src/video_core/CMakeLists.txt

@@ -97,6 +97,7 @@ add_library(video_core STATIC
     renderer_opengl/gl_stream_buffer.h
     renderer_opengl/gl_texture_cache.cpp
     renderer_opengl/gl_texture_cache.h
+    renderer_opengl/gl_texture_cache_base.cpp
     renderer_opengl/gl_query_cache.cpp
     renderer_opengl/gl_query_cache.h
     renderer_opengl/maxwell_to_gl.h
@@ -155,6 +156,7 @@ add_library(video_core STATIC
     renderer_vulkan/vk_swapchain.h
     renderer_vulkan/vk_texture_cache.cpp
     renderer_vulkan/vk_texture_cache.h
+    renderer_vulkan/vk_texture_cache_base.cpp
     renderer_vulkan/vk_update_descriptor.cpp
     renderer_vulkan/vk_update_descriptor.h
     shader_cache.cpp
@@ -186,6 +188,7 @@ add_library(video_core STATIC
     texture_cache/samples_helper.h
     texture_cache/slot_vector.h
     texture_cache/texture_cache.h
+    texture_cache/texture_cache_base.h
     texture_cache/types.h
     texture_cache/util.cpp
     texture_cache/util.h

+ 1 - 1
src/video_core/renderer_opengl/gl_graphics_pipeline.cpp

@@ -15,7 +15,7 @@
 #include "video_core/renderer_opengl/gl_shader_util.h"
 #include "video_core/renderer_opengl/gl_state_tracker.h"
 #include "video_core/shader_notify.h"
-#include "video_core/texture_cache/texture_cache.h"
+#include "video_core/texture_cache/texture_cache_base.h"
 
 #if defined(_MSC_VER) && defined(NDEBUG)
 #define LAMBDA_FORCEINLINE [[msvc::forceinline]]

+ 1 - 1
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -32,7 +32,7 @@
 #include "video_core/renderer_opengl/maxwell_to_gl.h"
 #include "video_core/renderer_opengl/renderer_opengl.h"
 #include "video_core/shader_cache.h"
-#include "video_core/texture_cache/texture_cache.h"
+#include "video_core/texture_cache/texture_cache_base.h"
 
 namespace OpenGL {
 

+ 1 - 3
src/video_core/renderer_opengl/gl_texture_cache.cpp

@@ -18,10 +18,8 @@
 #include "video_core/renderer_opengl/maxwell_to_gl.h"
 #include "video_core/renderer_opengl/util_shaders.h"
 #include "video_core/surface.h"
-#include "video_core/texture_cache/format_lookup_table.h"
+#include "video_core/texture_cache/formatter.h"
 #include "video_core/texture_cache/samples_helper.h"
-#include "video_core/texture_cache/texture_cache.h"
-#include "video_core/textures/decoders.h"
 
 namespace OpenGL {
 namespace {

+ 1 - 1
src/video_core/renderer_opengl/gl_texture_cache.h

@@ -12,7 +12,7 @@
 #include "shader_recompiler/shader_info.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
 #include "video_core/renderer_opengl/util_shaders.h"
-#include "video_core/texture_cache/texture_cache.h"
+#include "video_core/texture_cache/texture_cache_base.h"
 
 namespace OpenGL {
 

+ 10 - 0
src/video_core/renderer_opengl/gl_texture_cache_base.cpp

@@ -0,0 +1,10 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "video_core/renderer_opengl/gl_texture_cache.h"
+#include "video_core/texture_cache/texture_cache.h"
+
+namespace VideoCommon {
+template class VideoCommon::TextureCache<OpenGL::TextureCacheParams>;
+}

+ 1 - 1
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@@ -32,7 +32,7 @@
 #include "video_core/renderer_vulkan/vk_texture_cache.h"
 #include "video_core/renderer_vulkan/vk_update_descriptor.h"
 #include "video_core/shader_cache.h"
-#include "video_core/texture_cache/texture_cache.h"
+#include "video_core/texture_cache/texture_cache_base.h"
 #include "video_core/vulkan_common/vulkan_device.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
 

+ 2 - 0
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@@ -19,6 +19,8 @@
 #include "video_core/renderer_vulkan/vk_scheduler.h"
 #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
 #include "video_core/renderer_vulkan/vk_texture_cache.h"
+#include "video_core/texture_cache/formatter.h"
+#include "video_core/texture_cache/samples_helper.h"
 #include "video_core/vulkan_common/vulkan_device.h"
 #include "video_core/vulkan_common/vulkan_memory_allocator.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"

+ 1 - 1
src/video_core/renderer_vulkan/vk_texture_cache.h

@@ -9,7 +9,7 @@
 
 #include "shader_recompiler/shader_info.h"
 #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
-#include "video_core/texture_cache/texture_cache.h"
+#include "video_core/texture_cache/texture_cache_base.h"
 #include "video_core/vulkan_common/vulkan_memory_allocator.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
 

+ 10 - 0
src/video_core/renderer_vulkan/vk_texture_cache_base.cpp

@@ -0,0 +1,10 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "video_core/renderer_vulkan/vk_texture_cache.h"
+#include "video_core/texture_cache/texture_cache.h"
+
+namespace VideoCommon {
+template class VideoCommon::TextureCache<Vulkan::TextureCacheParams>;
+}

+ 3 - 1
src/video_core/texture_cache/image_view_info.cpp

@@ -6,7 +6,7 @@
 
 #include "common/assert.h"
 #include "video_core/texture_cache/image_view_info.h"
-#include "video_core/texture_cache/texture_cache.h"
+#include "video_core/texture_cache/texture_cache_base.h"
 #include "video_core/texture_cache/types.h"
 #include "video_core/textures/texture.h"
 
@@ -14,6 +14,8 @@ namespace VideoCommon {
 
 namespace {
 
+using Tegra::Texture::TextureType;
+
 constexpr u8 RENDER_TARGET_SWIZZLE = std::numeric_limits<u8>::max();
 
 [[nodiscard]] u8 CastSwizzle(SwizzleSource source) {

+ 1 - 418
src/video_core/texture_cache/texture_cache.h

@@ -4,48 +4,11 @@
 
 #pragma once
 
-#include <algorithm>
-#include <array>
-#include <bit>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <span>
-#include <type_traits>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-#include <boost/container/small_vector.hpp>
-
 #include "common/alignment.h"
-#include "common/common_types.h"
-#include "common/literals.h"
-#include "common/logging/log.h"
 #include "common/settings.h"
-#include "video_core/compatible_formats.h"
-#include "video_core/delayed_destruction_ring.h"
 #include "video_core/dirty_flags.h"
-#include "video_core/engines/fermi_2d.h"
-#include "video_core/engines/kepler_compute.h"
-#include "video_core/engines/maxwell_3d.h"
-#include "video_core/memory_manager.h"
-#include "video_core/rasterizer_interface.h"
-#include "video_core/surface.h"
-#include "video_core/texture_cache/descriptor_table.h"
-#include "video_core/texture_cache/format_lookup_table.h"
-#include "video_core/texture_cache/formatter.h"
-#include "video_core/texture_cache/image_base.h"
-#include "video_core/texture_cache/image_info.h"
-#include "video_core/texture_cache/image_view_base.h"
-#include "video_core/texture_cache/image_view_info.h"
-#include "video_core/texture_cache/render_targets.h"
 #include "video_core/texture_cache/samples_helper.h"
-#include "video_core/texture_cache/slot_vector.h"
-#include "video_core/texture_cache/types.h"
-#include "video_core/texture_cache/util.h"
-#include "video_core/textures/texture.h"
+#include "video_core/texture_cache/texture_cache_base.h"
 
 namespace VideoCommon {
 
@@ -61,352 +24,6 @@ using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
 using VideoCore::Surface::SurfaceType;
 using namespace Common::Literals;
 
-template <class P>
-class TextureCache {
-    /// Address shift for caching images into a hash table
-    static constexpr u64 PAGE_BITS = 20;
-
-    /// Enables debugging features to the texture cache
-    static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION;
-    /// Implement blits as copies between framebuffers
-    static constexpr bool FRAMEBUFFER_BLITS = P::FRAMEBUFFER_BLITS;
-    /// True when some copies have to be emulated
-    static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES;
-    /// True when the API can provide info about the memory of the device.
-    static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
-
-    /// Image view ID for null descriptors
-    static constexpr ImageViewId NULL_IMAGE_VIEW_ID{0};
-    /// Sampler ID for bugged sampler ids
-    static constexpr SamplerId NULL_SAMPLER_ID{0};
-
-    static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
-    static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
-
-    using Runtime = typename P::Runtime;
-    using Image = typename P::Image;
-    using ImageAlloc = typename P::ImageAlloc;
-    using ImageView = typename P::ImageView;
-    using Sampler = typename P::Sampler;
-    using Framebuffer = typename P::Framebuffer;
-
-    struct BlitImages {
-        ImageId dst_id;
-        ImageId src_id;
-        PixelFormat dst_format;
-        PixelFormat src_format;
-    };
-
-    template <typename T>
-    struct IdentityHash {
-        [[nodiscard]] size_t operator()(T value) const noexcept {
-            return static_cast<size_t>(value);
-        }
-    };
-
-public:
-    explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&, Tegra::Engines::Maxwell3D&,
-                          Tegra::Engines::KeplerCompute&, Tegra::MemoryManager&);
-
-    /// Notify the cache that a new frame has been queued
-    void TickFrame();
-
-    /// Return a constant reference to the given image view id
-    [[nodiscard]] const ImageView& GetImageView(ImageViewId id) const noexcept;
-
-    /// Return a reference to the given image view id
-    [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
-
-    /// Mark an image as modified from the GPU
-    void MarkModification(ImageId id) noexcept;
-
-    /// Fill image_view_ids with the graphics images in indices
-    void FillGraphicsImageViews(std::span<const u32> indices,
-                                std::span<ImageViewId> image_view_ids);
-
-    /// Fill image_view_ids with the compute images in indices
-    void FillComputeImageViews(std::span<const u32> indices, std::span<ImageViewId> image_view_ids);
-
-    /// Get the sampler from the graphics descriptor table in the specified index
-    Sampler* GetGraphicsSampler(u32 index);
-
-    /// Get the sampler from the compute descriptor table in the specified index
-    Sampler* GetComputeSampler(u32 index);
-
-    /// Refresh the state for graphics image view and sampler descriptors
-    void SynchronizeGraphicsDescriptors();
-
-    /// Refresh the state for compute image view and sampler descriptors
-    void SynchronizeComputeDescriptors();
-
-    /// Update bound render targets and upload memory if necessary
-    /// @param is_clear True when the render targets are being used for clears
-    void UpdateRenderTargets(bool is_clear);
-
-    /// Find a framebuffer with the currently bound render targets
-    /// UpdateRenderTargets should be called before this
-    Framebuffer* GetFramebuffer();
-
-    /// Mark images in a range as modified from the CPU
-    void WriteMemory(VAddr cpu_addr, size_t size);
-
-    /// Download contents of host images to guest memory in a region
-    void DownloadMemory(VAddr cpu_addr, size_t size);
-
-    /// Remove images in a region
-    void UnmapMemory(VAddr cpu_addr, size_t size);
-
-    /// Remove images in a region
-    void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size);
-
-    /// Blit an image with the given parameters
-    void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
-                   const Tegra::Engines::Fermi2D::Surface& src,
-                   const Tegra::Engines::Fermi2D::Config& copy);
-
-    /// Invalidate the contents of the color buffer index
-    /// These contents become unspecified, the cache can assume aggressive optimizations.
-    void InvalidateColorBuffer(size_t index);
-
-    /// Invalidate the contents of the depth buffer
-    /// These contents become unspecified, the cache can assume aggressive optimizations.
-    void InvalidateDepthBuffer();
-
-    /// Try to find a cached image view in the given CPU address
-    [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr);
-
-    /// Return true when there are uncommitted images to be downloaded
-    [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
-
-    /// Return true when the caller should wait for async downloads
-    [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
-
-    /// Commit asynchronous downloads
-    void CommitAsyncFlushes();
-
-    /// Pop asynchronous downloads
-    void PopAsyncFlushes();
-
-    /// Return true when a CPU region is modified from the GPU
-    [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
-
-    std::mutex mutex;
-
-private:
-    /// Iterate over all page indices in a range
-    template <typename Func>
-    static void ForEachCPUPage(VAddr addr, size_t size, Func&& func) {
-        static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
-        const u64 page_end = (addr + size - 1) >> PAGE_BITS;
-        for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
-            if constexpr (RETURNS_BOOL) {
-                if (func(page)) {
-                    break;
-                }
-            } else {
-                func(page);
-            }
-        }
-    }
-
-    template <typename Func>
-    static void ForEachGPUPage(GPUVAddr addr, size_t size, Func&& func) {
-        static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
-        const u64 page_end = (addr + size - 1) >> PAGE_BITS;
-        for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
-            if constexpr (RETURNS_BOOL) {
-                if (func(page)) {
-                    break;
-                }
-            } else {
-                func(page);
-            }
-        }
-    }
-
-    /// Runs the Garbage Collector.
-    void RunGarbageCollector();
-
-    /// Fills image_view_ids in the image views in indices
-    void FillImageViews(DescriptorTable<TICEntry>& table,
-                        std::span<ImageViewId> cached_image_view_ids, std::span<const u32> indices,
-                        std::span<ImageViewId> image_view_ids);
-
-    /// Find or create an image view in the guest descriptor table
-    ImageViewId VisitImageView(DescriptorTable<TICEntry>& table,
-                               std::span<ImageViewId> cached_image_view_ids, u32 index);
-
-    /// Find or create a framebuffer with the given render target parameters
-    FramebufferId GetFramebufferId(const RenderTargets& key);
-
-    /// Refresh the contents (pixel data) of an image
-    void RefreshContents(Image& image, ImageId image_id);
-
-    /// Upload data from guest to an image
-    template <typename StagingBuffer>
-    void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
-
-    /// Find or create an image view from a guest descriptor
-    [[nodiscard]] ImageViewId FindImageView(const TICEntry& config);
-
-    /// Create a new image view from a guest descriptor
-    [[nodiscard]] ImageViewId CreateImageView(const TICEntry& config);
-
-    /// Find or create an image from the given parameters
-    [[nodiscard]] ImageId FindOrInsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
-                                            RelaxedOptions options = RelaxedOptions{});
-
-    /// Find an image from the given parameters
-    [[nodiscard]] ImageId FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
-                                    RelaxedOptions options);
-
-    /// Create an image from the given parameters
-    [[nodiscard]] ImageId InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
-                                      RelaxedOptions options);
-
-    /// Create a new image and join perfectly matching existing images
-    /// Remove joined images from the cache
-    [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr);
-
-    /// Return a blit image pair from the given guest blit parameters
-    [[nodiscard]] BlitImages GetBlitImages(const Tegra::Engines::Fermi2D::Surface& dst,
-                                           const Tegra::Engines::Fermi2D::Surface& src);
-
-    /// Find or create a sampler from a guest descriptor sampler
-    [[nodiscard]] SamplerId FindSampler(const TSCEntry& config);
-
-    /// Find or create an image view for the given color buffer index
-    [[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear);
-
-    /// Find or create an image view for the depth buffer
-    [[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear);
-
-    /// Find or create a view for a render target with the given image parameters
-    [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr,
-                                                   bool is_clear);
-
-    /// Iterates over all the images in a region calling func
-    template <typename Func>
-    void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func);
-
-    template <typename Func>
-    void ForEachImageInRegionGPU(GPUVAddr gpu_addr, size_t size, Func&& func);
-
-    template <typename Func>
-    void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func);
-
-    /// Iterates over all the images in a region calling func
-    template <typename Func>
-    void ForEachSparseSegment(ImageBase& image, Func&& func);
-
-    /// Find or create an image view in the given image with the passed parameters
-    [[nodiscard]] ImageViewId FindOrEmplaceImageView(ImageId image_id, const ImageViewInfo& info);
-
-    /// Register image in the page table
-    void RegisterImage(ImageId image);
-
-    /// Unregister image from the page table
-    void UnregisterImage(ImageId image);
-
-    /// Track CPU reads and writes for image
-    void TrackImage(ImageBase& image, ImageId image_id);
-
-    /// Stop tracking CPU reads and writes for image
-    void UntrackImage(ImageBase& image, ImageId image_id);
-
-    /// Delete image from the cache
-    void DeleteImage(ImageId image);
-
-    /// Remove image views references from the cache
-    void RemoveImageViewReferences(std::span<const ImageViewId> removed_views);
-
-    /// Remove framebuffers using the given image views from the cache
-    void RemoveFramebuffers(std::span<const ImageViewId> removed_views);
-
-    /// Mark an image as modified from the GPU
-    void MarkModification(ImageBase& image) noexcept;
-
-    /// Synchronize image aliases, copying data if needed
-    void SynchronizeAliases(ImageId image_id);
-
-    /// Prepare an image to be used
-    void PrepareImage(ImageId image_id, bool is_modification, bool invalidate);
-
-    /// Prepare an image view to be used
-    void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate);
-
-    /// Execute copies from one image to the other, even if they are incompatible
-    void CopyImage(ImageId dst_id, ImageId src_id, std::span<const ImageCopy> copies);
-
-    /// Bind an image view as render target, downloading resources preemtively if needed
-    void BindRenderTarget(ImageViewId* old_id, ImageViewId new_id);
-
-    /// Create a render target from a given image and image view parameters
-    [[nodiscard]] std::pair<FramebufferId, ImageViewId> RenderTargetFromImage(
-        ImageId, const ImageViewInfo& view_info);
-
-    /// Returns true if the current clear parameters clear the whole image of a given image view
-    [[nodiscard]] bool IsFullClear(ImageViewId id);
-
-    Runtime& runtime;
-    VideoCore::RasterizerInterface& rasterizer;
-    Tegra::Engines::Maxwell3D& maxwell3d;
-    Tegra::Engines::KeplerCompute& kepler_compute;
-    Tegra::MemoryManager& gpu_memory;
-
-    DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
-    DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
-    std::vector<SamplerId> graphics_sampler_ids;
-    std::vector<ImageViewId> graphics_image_view_ids;
-
-    DescriptorTable<TICEntry> compute_image_table{gpu_memory};
-    DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory};
-    std::vector<SamplerId> compute_sampler_ids;
-    std::vector<ImageViewId> compute_image_view_ids;
-
-    RenderTargets render_targets;
-
-    std::unordered_map<TICEntry, ImageViewId> image_views;
-    std::unordered_map<TSCEntry, SamplerId> samplers;
-    std::unordered_map<RenderTargets, FramebufferId> framebuffers;
-
-    std::unordered_map<u64, std::vector<ImageMapId>, IdentityHash<u64>> page_table;
-    std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> gpu_page_table;
-    std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> sparse_page_table;
-
-    std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views;
-
-    VAddr virtual_invalid_space{};
-
-    bool has_deleted_images = false;
-    u64 total_used_memory = 0;
-    u64 minimum_memory;
-    u64 expected_memory;
-    u64 critical_memory;
-
-    SlotVector<Image> slot_images;
-    SlotVector<ImageMapView> slot_map_views;
-    SlotVector<ImageView> slot_image_views;
-    SlotVector<ImageAlloc> slot_image_allocs;
-    SlotVector<Sampler> slot_samplers;
-    SlotVector<Framebuffer> slot_framebuffers;
-
-    // TODO: This data structure is not optimal and it should be reworked
-    std::vector<ImageId> uncommitted_downloads;
-    std::queue<std::vector<ImageId>> committed_downloads;
-
-    static constexpr size_t TICKS_TO_DESTROY = 6;
-    DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
-    DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
-    DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers;
-
-    std::unordered_map<GPUVAddr, ImageAllocId> image_allocs_table;
-
-    u64 modification_tick = 0;
-    u64 frame_tick = 0;
-    typename SlotVector<Image>::Iterator deletion_iterator;
-};
-
 template <class P>
 TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& rasterizer_,
                               Tegra::Engines::Maxwell3D& maxwell3d_,
@@ -820,40 +437,6 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
     }
 }
 
-template <class P>
-void TextureCache<P>::InvalidateColorBuffer(size_t index) {
-    ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index];
-    color_buffer_id = FindColorBuffer(index, false);
-    if (!color_buffer_id) {
-        LOG_ERROR(HW_GPU, "Invalidating invalid color buffer in index={}", index);
-        return;
-    }
-    // When invalidating a color buffer, the old contents are no longer relevant
-    ImageView& color_buffer = slot_image_views[color_buffer_id];
-    Image& image = slot_images[color_buffer.image_id];
-    image.flags &= ~ImageFlagBits::CpuModified;
-    image.flags &= ~ImageFlagBits::GpuModified;
-
-    runtime.InvalidateColorBuffer(color_buffer, index);
-}
-
-template <class P>
-void TextureCache<P>::InvalidateDepthBuffer() {
-    ImageViewId& depth_buffer_id = render_targets.depth_buffer_id;
-    depth_buffer_id = FindDepthBuffer(false);
-    if (!depth_buffer_id) {
-        LOG_ERROR(HW_GPU, "Invalidating invalid depth buffer");
-        return;
-    }
-    // When invalidating the depth buffer, the old contents are no longer relevant
-    ImageBase& image = slot_images[slot_image_views[depth_buffer_id].image_id];
-    image.flags &= ~ImageFlagBits::CpuModified;
-    image.flags &= ~ImageFlagBits::GpuModified;
-
-    ImageView& depth_buffer = slot_image_views[depth_buffer_id];
-    runtime.InvalidateDepthBuffer(depth_buffer);
-}
-
 template <class P>
 typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) {
     // TODO: Properly implement this

+ 385 - 0
src/video_core/texture_cache/texture_cache_base.h

@@ -0,0 +1,385 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <mutex>
+#include <span>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "common/common_types.h"
+#include "common/literals.h"
+#include "video_core/compatible_formats.h"
+#include "video_core/delayed_destruction_ring.h"
+#include "video_core/engines/fermi_2d.h"
+#include "video_core/engines/kepler_compute.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/memory_manager.h"
+#include "video_core/rasterizer_interface.h"
+#include "video_core/surface.h"
+#include "video_core/texture_cache/descriptor_table.h"
+#include "video_core/texture_cache/image_base.h"
+#include "video_core/texture_cache/image_info.h"
+#include "video_core/texture_cache/image_view_info.h"
+#include "video_core/texture_cache/render_targets.h"
+#include "video_core/texture_cache/slot_vector.h"
+#include "video_core/texture_cache/types.h"
+#include "video_core/texture_cache/util.h"
+#include "video_core/textures/texture.h"
+
+namespace VideoCommon {
+
+using Tegra::Texture::SwizzleSource;
+using Tegra::Texture::TICEntry;
+using Tegra::Texture::TSCEntry;
+using VideoCore::Surface::GetFormatType;
+using VideoCore::Surface::IsCopyCompatible;
+using VideoCore::Surface::PixelFormat;
+using VideoCore::Surface::PixelFormatFromDepthFormat;
+using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
+using namespace Common::Literals;
+
+template <class P>
+class TextureCache {
+    /// Address shift for caching images into a hash table
+    static constexpr u64 PAGE_BITS = 20;
+
+    /// Enables debugging features to the texture cache
+    static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION;
+    /// Implement blits as copies between framebuffers
+    static constexpr bool FRAMEBUFFER_BLITS = P::FRAMEBUFFER_BLITS;
+    /// True when some copies have to be emulated
+    static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES;
+    /// True when the API can provide info about the memory of the device.
+    static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
+
+    /// Image view ID for null descriptors
+    static constexpr ImageViewId NULL_IMAGE_VIEW_ID{0};
+    /// Sampler ID for bugged sampler ids
+    static constexpr SamplerId NULL_SAMPLER_ID{0};
+
+    static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
+    static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
+
+    using Runtime = typename P::Runtime;
+    using Image = typename P::Image;
+    using ImageAlloc = typename P::ImageAlloc;
+    using ImageView = typename P::ImageView;
+    using Sampler = typename P::Sampler;
+    using Framebuffer = typename P::Framebuffer;
+
+    struct BlitImages {
+        ImageId dst_id;
+        ImageId src_id;
+        PixelFormat dst_format;
+        PixelFormat src_format;
+    };
+
+    template <typename T>
+    struct IdentityHash {
+        [[nodiscard]] size_t operator()(T value) const noexcept {
+            return static_cast<size_t>(value);
+        }
+    };
+
+public:
+    explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&, Tegra::Engines::Maxwell3D&,
+                          Tegra::Engines::KeplerCompute&, Tegra::MemoryManager&);
+
+    /// Notify the cache that a new frame has been queued
+    void TickFrame();
+
+    /// Return a constant reference to the given image view id
+    [[nodiscard]] const ImageView& GetImageView(ImageViewId id) const noexcept;
+
+    /// Return a reference to the given image view id
+    [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
+
+    /// Mark an image as modified from the GPU
+    void MarkModification(ImageId id) noexcept;
+
+    /// Fill image_view_ids with the graphics images in indices
+    void FillGraphicsImageViews(std::span<const u32> indices,
+                                std::span<ImageViewId> image_view_ids);
+
+    /// Fill image_view_ids with the compute images in indices
+    void FillComputeImageViews(std::span<const u32> indices, std::span<ImageViewId> image_view_ids);
+
+    /// Get the sampler from the graphics descriptor table in the specified index
+    Sampler* GetGraphicsSampler(u32 index);
+
+    /// Get the sampler from the compute descriptor table in the specified index
+    Sampler* GetComputeSampler(u32 index);
+
+    /// Refresh the state for graphics image view and sampler descriptors
+    void SynchronizeGraphicsDescriptors();
+
+    /// Refresh the state for compute image view and sampler descriptors
+    void SynchronizeComputeDescriptors();
+
+    /// Update bound render targets and upload memory if necessary
+    /// @param is_clear True when the render targets are being used for clears
+    void UpdateRenderTargets(bool is_clear);
+
+    /// Find a framebuffer with the currently bound render targets
+    /// UpdateRenderTargets should be called before this
+    Framebuffer* GetFramebuffer();
+
+    /// Mark images in a range as modified from the CPU
+    void WriteMemory(VAddr cpu_addr, size_t size);
+
+    /// Download contents of host images to guest memory in a region
+    void DownloadMemory(VAddr cpu_addr, size_t size);
+
+    /// Remove images in a region
+    void UnmapMemory(VAddr cpu_addr, size_t size);
+
+    /// Remove images in a region
+    void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size);
+
+    /// Blit an image with the given parameters
+    void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
+                   const Tegra::Engines::Fermi2D::Surface& src,
+                   const Tegra::Engines::Fermi2D::Config& copy);
+
+    /// Try to find a cached image view in the given CPU address
+    [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr);
+
+    /// Return true when there are uncommitted images to be downloaded
+    [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
+
+    /// Return true when the caller should wait for async downloads
+    [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
+
+    /// Commit asynchronous downloads
+    void CommitAsyncFlushes();
+
+    /// Pop asynchronous downloads
+    void PopAsyncFlushes();
+
+    /// Return true when a CPU region is modified from the GPU
+    [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
+
+    std::mutex mutex;
+
+private:
+    /// Iterate over all page indices in a range
+    template <typename Func>
+    static void ForEachCPUPage(VAddr addr, size_t size, Func&& func) {
+        static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
+        const u64 page_end = (addr + size - 1) >> PAGE_BITS;
+        for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
+            if constexpr (RETURNS_BOOL) {
+                if (func(page)) {
+                    break;
+                }
+            } else {
+                func(page);
+            }
+        }
+    }
+
+    template <typename Func>
+    static void ForEachGPUPage(GPUVAddr addr, size_t size, Func&& func) {
+        static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
+        const u64 page_end = (addr + size - 1) >> PAGE_BITS;
+        for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
+            if constexpr (RETURNS_BOOL) {
+                if (func(page)) {
+                    break;
+                }
+            } else {
+                func(page);
+            }
+        }
+    }
+
+    /// Runs the Garbage Collector.
+    void RunGarbageCollector();
+
+    /// Fills image_view_ids in the image views in indices
+    void FillImageViews(DescriptorTable<TICEntry>& table,
+                        std::span<ImageViewId> cached_image_view_ids, std::span<const u32> indices,
+                        std::span<ImageViewId> image_view_ids);
+
+    /// Find or create an image view in the guest descriptor table
+    ImageViewId VisitImageView(DescriptorTable<TICEntry>& table,
+                               std::span<ImageViewId> cached_image_view_ids, u32 index);
+
+    /// Find or create a framebuffer with the given render target parameters
+    FramebufferId GetFramebufferId(const RenderTargets& key);
+
+    /// Refresh the contents (pixel data) of an image
+    void RefreshContents(Image& image, ImageId image_id);
+
+    /// Upload data from guest to an image
+    template <typename StagingBuffer>
+    void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
+
+    /// Find or create an image view from a guest descriptor
+    [[nodiscard]] ImageViewId FindImageView(const TICEntry& config);
+
+    /// Create a new image view from a guest descriptor
+    [[nodiscard]] ImageViewId CreateImageView(const TICEntry& config);
+
+    /// Find or create an image from the given parameters
+    [[nodiscard]] ImageId FindOrInsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
+                                            RelaxedOptions options = RelaxedOptions{});
+
+    /// Find an image from the given parameters
+    [[nodiscard]] ImageId FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
+                                    RelaxedOptions options);
+
+    /// Create an image from the given parameters
+    [[nodiscard]] ImageId InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
+                                      RelaxedOptions options);
+
+    /// Create a new image and join perfectly matching existing images
+    /// Remove joined images from the cache
+    [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr);
+
+    /// Return a blit image pair from the given guest blit parameters
+    [[nodiscard]] BlitImages GetBlitImages(const Tegra::Engines::Fermi2D::Surface& dst,
+                                           const Tegra::Engines::Fermi2D::Surface& src);
+
+    /// Find or create a sampler from a guest descriptor sampler
+    [[nodiscard]] SamplerId FindSampler(const TSCEntry& config);
+
+    /// Find or create an image view for the given color buffer index
+    [[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear);
+
+    /// Find or create an image view for the depth buffer
+    [[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear);
+
+    /// Find or create a view for a render target with the given image parameters
+    [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr,
+                                                   bool is_clear);
+
+    /// Iterates over all the images in a region calling func
+    template <typename Func>
+    void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func);
+
+    template <typename Func>
+    void ForEachImageInRegionGPU(GPUVAddr gpu_addr, size_t size, Func&& func);
+
+    template <typename Func>
+    void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func);
+
+    /// Iterates over all the images in a region calling func
+    template <typename Func>
+    void ForEachSparseSegment(ImageBase& image, Func&& func);
+
+    /// Find or create an image view in the given image with the passed parameters
+    [[nodiscard]] ImageViewId FindOrEmplaceImageView(ImageId image_id, const ImageViewInfo& info);
+
+    /// Register image in the page table
+    void RegisterImage(ImageId image);
+
+    /// Unregister image from the page table
+    void UnregisterImage(ImageId image);
+
+    /// Track CPU reads and writes for image
+    void TrackImage(ImageBase& image, ImageId image_id);
+
+    /// Stop tracking CPU reads and writes for image
+    void UntrackImage(ImageBase& image, ImageId image_id);
+
+    /// Delete image from the cache
+    void DeleteImage(ImageId image);
+
+    /// Remove image views references from the cache
+    void RemoveImageViewReferences(std::span<const ImageViewId> removed_views);
+
+    /// Remove framebuffers using the given image views from the cache
+    void RemoveFramebuffers(std::span<const ImageViewId> removed_views);
+
+    /// Mark an image as modified from the GPU
+    void MarkModification(ImageBase& image) noexcept;
+
+    /// Synchronize image aliases, copying data if needed
+    void SynchronizeAliases(ImageId image_id);
+
+    /// Prepare an image to be used
+    void PrepareImage(ImageId image_id, bool is_modification, bool invalidate);
+
+    /// Prepare an image view to be used
+    void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate);
+
+    /// Execute copies from one image to the other, even if they are incompatible
+    void CopyImage(ImageId dst_id, ImageId src_id, std::span<const ImageCopy> copies);
+
+    /// Bind an image view as render target, downloading resources preemtively if needed
+    void BindRenderTarget(ImageViewId* old_id, ImageViewId new_id);
+
+    /// Create a render target from a given image and image view parameters
+    [[nodiscard]] std::pair<FramebufferId, ImageViewId> RenderTargetFromImage(
+        ImageId, const ImageViewInfo& view_info);
+
+    /// Returns true if the current clear parameters clear the whole image of a given image view
+    [[nodiscard]] bool IsFullClear(ImageViewId id);
+
+    Runtime& runtime;
+    VideoCore::RasterizerInterface& rasterizer;
+    Tegra::Engines::Maxwell3D& maxwell3d;
+    Tegra::Engines::KeplerCompute& kepler_compute;
+    Tegra::MemoryManager& gpu_memory;
+
+    DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
+    DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
+    std::vector<SamplerId> graphics_sampler_ids;
+    std::vector<ImageViewId> graphics_image_view_ids;
+
+    DescriptorTable<TICEntry> compute_image_table{gpu_memory};
+    DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory};
+    std::vector<SamplerId> compute_sampler_ids;
+    std::vector<ImageViewId> compute_image_view_ids;
+
+    RenderTargets render_targets;
+
+    std::unordered_map<TICEntry, ImageViewId> image_views;
+    std::unordered_map<TSCEntry, SamplerId> samplers;
+    std::unordered_map<RenderTargets, FramebufferId> framebuffers;
+
+    std::unordered_map<u64, std::vector<ImageMapId>, IdentityHash<u64>> page_table;
+    std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> gpu_page_table;
+    std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> sparse_page_table;
+
+    std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views;
+
+    VAddr virtual_invalid_space{};
+
+    bool has_deleted_images = false;
+    u64 total_used_memory = 0;
+    u64 minimum_memory;
+    u64 expected_memory;
+    u64 critical_memory;
+
+    SlotVector<Image> slot_images;
+    SlotVector<ImageMapView> slot_map_views;
+    SlotVector<ImageView> slot_image_views;
+    SlotVector<ImageAlloc> slot_image_allocs;
+    SlotVector<Sampler> slot_samplers;
+    SlotVector<Framebuffer> slot_framebuffers;
+
+    // TODO: This data structure is not optimal and it should be reworked
+    std::vector<ImageId> uncommitted_downloads;
+    std::queue<std::vector<ImageId>> committed_downloads;
+
+    static constexpr size_t TICKS_TO_DESTROY = 6;
+    DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
+    DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
+    DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers;
+
+    std::unordered_map<GPUVAddr, ImageAllocId> image_allocs_table;
+
+    u64 modification_tick = 0;
+    u64 frame_tick = 0;
+    typename SlotVector<Image>::Iterator deletion_iterator;
+};
+
+} // namespace VideoCommon