From 7a9d9e575b4d85ca30fc119dfb73c1b22a6dbe63 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 24 Mar 2022 21:30:54 +0100 Subject: [PATCH 1/2] Texture Cache: Add Cached CPU system. --- .../renderer_opengl/gl_rasterizer.cpp | 6 ++- .../renderer_vulkan/vk_rasterizer.cpp | 6 ++- src/video_core/texture_cache/image_base.h | 3 ++ src/video_core/texture_cache/texture_cache.h | 41 ++++++++++++++++++- .../texture_cache/texture_cache_base.h | 11 +++++ 5 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 4d632d2113..7e06d00696 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -352,7 +352,7 @@ void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) { shader_cache.OnCPUWrite(addr, size); { std::scoped_lock lock{texture_cache.mutex}; - texture_cache.WriteMemory(addr, size); + texture_cache.CachedWriteMemory(addr, size); } { std::scoped_lock lock{buffer_cache.mutex}; @@ -363,6 +363,10 @@ void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) { void RasterizerOpenGL::SyncGuestHost() { MICROPROFILE_SCOPE(OpenGL_CacheManagement); shader_cache.SyncGuestHost(); + { + std::scoped_lock lock{texture_cache.mutex}; + texture_cache.FlushCachedWrites(); + } { std::scoped_lock lock{buffer_cache.mutex}; buffer_cache.FlushCachedWrites(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index fa87d37f85..dd6e0027e1 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -408,7 +408,7 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { pipeline_cache.OnCPUWrite(addr, size); { std::scoped_lock lock{texture_cache.mutex}; - texture_cache.WriteMemory(addr, size); + texture_cache.CachedWriteMemory(addr, size); } { std::scoped_lock lock{buffer_cache.mutex}; @@ -418,6 +418,10 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { void RasterizerVulkan::SyncGuestHost() { pipeline_cache.SyncGuestHost(); + { + std::scoped_lock lock{texture_cache.mutex}; + texture_cache.FlushCachedWrites(); + } { std::scoped_lock lock{buffer_cache.mutex}; buffer_cache.FlushCachedWrites(); diff --git a/src/video_core/texture_cache/image_base.h b/src/video_core/texture_cache/image_base.h index dd01064324..cc79990279 100644 --- a/src/video_core/texture_cache/image_base.h +++ b/src/video_core/texture_cache/image_base.h @@ -39,6 +39,9 @@ enum class ImageFlagBits : u32 { Rescaled = 1 << 13, CheckingRescalable = 1 << 14, IsRescalable = 1 << 15, + + // Cached CPU + CachedCpuModified = 1 << 16, ///< Contents have been modified from the CPU }; DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index efc1c45257..099b2ae1ba 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -437,6 +437,23 @@ void TextureCache

::WriteMemory(VAddr cpu_addr, size_t size) { }); } +template +void TextureCache

::CachedWriteMemory(VAddr cpu_addr, size_t size) { + const VAddr new_cpu_addr = Common::AlignDown(cpu_addr, CPU_PAGE_SIZE); + const size_t new_size = Common::AlignUp(size + cpu_addr - new_cpu_addr, CPU_PAGE_SIZE); + ForEachImageInRegion(new_cpu_addr, new_size, [this](ImageId image_id, Image& image) { + if (True(image.flags & ImageFlagBits::CachedCpuModified)) { + return; + } + image.flags |= ImageFlagBits::CachedCpuModified; + cached_cpu_invalidate.insert(image_id); + + if (True(image.flags & ImageFlagBits::Tracked)) { + UntrackImage(image, image_id); + } + }); +} + template void TextureCache

::DownloadMemory(VAddr cpu_addr, size_t size) { std::vector images; @@ -494,6 +511,18 @@ void TextureCache

::UnmapGPUMemory(GPUVAddr gpu_addr, size_t size) { } } +template +void TextureCache

::FlushCachedWrites() { + for (ImageId image_id : cached_cpu_invalidate) { + Image& image = slot_images[image_id]; + if (True(image.flags & ImageFlagBits::CachedCpuModified)) { + image.flags &= ~ImageFlagBits::CachedCpuModified; + image.flags |= ImageFlagBits::CpuModified; + } + } + cached_cpu_invalidate.clear(); +} + template void TextureCache

::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, @@ -1560,6 +1589,9 @@ void TextureCache

::UnregisterImage(ImageId image_id) { template void TextureCache

::TrackImage(ImageBase& image, ImageId image_id) { ASSERT(False(image.flags & ImageFlagBits::Tracked)); + if (True(image.flags & ImageFlagBits::CachedCpuModified)) { + return; + } image.flags |= ImageFlagBits::Tracked; if (False(image.flags & ImageFlagBits::Sparse)) { rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1); @@ -1616,6 +1648,9 @@ void TextureCache

::DeleteImage(ImageId image_id, bool immediate_delete) { tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format); } total_used_memory -= Common::AlignUp(tentative_size, 1024); + if (True(image.flags & ImageFlagBits::CachedCpuModified)) { + cached_cpu_invalidate.erase(image_id); + } const GPUVAddr gpu_addr = image.gpu_addr; const auto alloc_it = image_allocs_table.find(gpu_addr); if (alloc_it == image_allocs_table.end()) { @@ -1782,7 +1817,11 @@ template void TextureCache

::PrepareImage(ImageId image_id, bool is_modification, bool invalidate) { Image& image = slot_images[image_id]; if (invalidate) { - image.flags &= ~(ImageFlagBits::CpuModified | ImageFlagBits::GpuModified); + if (True(image.flags & ImageFlagBits::CachedCpuModified)) { + cached_cpu_invalidate.erase(image_id); + } + image.flags &= ~(ImageFlagBits::CpuModified | ImageFlagBits::GpuModified | + ImageFlagBits::CachedCpuModified); if (False(image.flags & ImageFlagBits::Tracked)) { TrackImage(image, image_id); } diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index b1324edf31..ad5978a333 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,9 @@ class TextureCache { /// Address shift for caching images into a hash table static constexpr u64 PAGE_BITS = 20; + static constexpr u64 CPU_PAGE_BITS = 12; + static constexpr u64 CPU_PAGE_SIZE = 1ULL << CPU_PAGE_BITS; + /// Enables debugging features to the texture cache static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION; /// Implement blits as copies between framebuffers @@ -136,6 +140,9 @@ public: /// Mark images in a range as modified from the CPU void WriteMemory(VAddr cpu_addr, size_t size); + /// Mark images in a range as modified from the CPU + void CachedWriteMemory(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); @@ -145,6 +152,8 @@ public: /// Remove images in a region void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size); + void FlushCachedWrites(); + /// Blit an image with the given parameters void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, @@ -366,6 +375,8 @@ private: std::unordered_map> sparse_views; + std::unordered_set cached_cpu_invalidate; + VAddr virtual_invalid_space{}; bool has_deleted_images = false; From a2d7b2f905eef379f6412ef043100a98845aefb1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 24 Mar 2022 21:54:48 +0100 Subject: [PATCH 2/2] Memory: Don't protect reads on Normal accuracy. --- src/core/memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 28d30eee29..3fed514008 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -322,7 +322,7 @@ struct Memory::Impl { } if (Settings::IsFastmemEnabled()) { - const bool is_read_enable = Settings::IsGPULevelHigh() || !cached; + const bool is_read_enable = !Settings::IsGPULevelExtreme() || !cached; system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached); }