From da28623315b3a25e5eff5fef429694d9302b7cfb Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Sun, 24 Nov 2024 22:37:54 +0300 Subject: [PATCH] untrack only first page of the image in case of head access --- src/video_core/page_manager.cpp | 12 ++++- src/video_core/page_manager.h | 3 ++ src/video_core/texture_cache/image.h | 3 +- .../texture_cache/texture_cache.cpp | 52 +++++++++++++++++-- src/video_core/texture_cache/texture_cache.h | 6 +++ 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/video_core/page_manager.cpp b/src/video_core/page_manager.cpp index d5c374657..d26a7067a 100644 --- a/src/video_core/page_manager.cpp +++ b/src/video_core/page_manager.cpp @@ -114,7 +114,7 @@ struct PageManager::Impl { // Notify rasterizer about the fault. const VAddr addr = msg.arg.pagefault.address; - const VAddr addr_page = Common::AlignDown(addr, PAGESIZE); + const VAddr addr_page = GetPageAddr(addr); rasterizer->InvalidateMemory(addr, addr_page, PAGESIZE); } } @@ -157,7 +157,7 @@ struct PageManager::Impl { const auto addr = reinterpret_cast(fault_address); const bool is_write = Common::IsWriteError(context); if (is_write && owned_ranges.find(addr) != owned_ranges.end()) { - const VAddr addr_aligned = Common::AlignDown(addr, PAGESIZE); + const VAddr addr_aligned = GetPageAddr(addr); rasterizer->InvalidateMemory(addr, addr_aligned, PAGESIZE); return true; } @@ -174,6 +174,14 @@ PageManager::PageManager(Vulkan::Rasterizer* rasterizer_) PageManager::~PageManager() = default; +VAddr PageManager::GetPageAddr(VAddr addr) { + return Common::AlignDown(addr, PAGESIZE); +} + +VAddr PageManager::GetNextPageAddr(VAddr addr) { + return Common::AlignUp(addr + 1, PAGESIZE); +} + void PageManager::OnGpuMap(VAddr address, size_t size) { impl->OnMap(address, size); } diff --git a/src/video_core/page_manager.h b/src/video_core/page_manager.h index 0dc022aa5..29a946a8f 100644 --- a/src/video_core/page_manager.h +++ b/src/video_core/page_manager.h @@ -28,6 +28,9 @@ public: /// Increase/decrease the number of surface in pages touching the specified region void UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta); + static VAddr GetPageAddr(VAddr addr); + static VAddr GetNextPageAddr(VAddr addr); + private: struct Impl; std::unique_ptr impl; diff --git a/src/video_core/texture_cache/image.h b/src/video_core/texture_cache/image.h index fdf536fd7..abead1411 100644 --- a/src/video_core/texture_cache/image.h +++ b/src/video_core/texture_cache/image.h @@ -25,9 +25,10 @@ enum ImageFlagBits : u32 { MaybeCpuDirty = 1 << 0, ///< The page this image is in was touched before the image address CpuDirty = 1 << 1, ///< Contents have been modified from the CPU GpuDirty = 1 << 2, ///< Contents have been modified from the GPU (valid data in buffer cache) - Dirty = CpuDirty | GpuDirty | MaybeCpuDirty, + Dirty = MaybeCpuDirty | CpuDirty | GpuDirty, GpuModified = 1 << 3, ///< Contents have been modified from the GPU Tracked = 1 << 4, ///< Writes and reads are being hooked from the CPU + TailTracked = 1 << 5, ///< Writes and reads to the image tail are being hooked from the CPU Registered = 1 << 6, ///< True when the image is registered Picked = 1 << 7, ///< Temporary flag to mark the image as picked MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 129c1af8c..248372ec4 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -56,8 +56,15 @@ void TextureCache::InvalidateMemory(VAddr addr, VAddr addr_aligned, size_t size) // Image ends on this page so it can not receive any more invalidations. // We will check it's hash later to see if it really was modified. image.flags |= ImageFlagBits::MaybeCpuDirty; + UntrackImage(image_id); + } else { + // Remove tracking from this page only. + UntrackImageHead(image_id); } - } else if (addr < image_end) { + return; + } + + if (addr < image_end) { // Ensure image is reuploaded when accessed again. image.flags |= ImageFlagBits::CpuDirty; } @@ -436,6 +443,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule const u8* addr = std::bit_cast(image.info.guest_address); const u64 hash = XXH3_64bits(addr, image.info.guest_size_bytes); if (image.hash == hash) { + image.flags &= ~ImageFlagBits::MaybeCpuDirty; return; } image.hash = hash; @@ -481,6 +489,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule } if (image_copy.empty()) { + image.flags &= ~ImageFlagBits::Dirty; return; } @@ -556,22 +565,59 @@ void TextureCache::TrackImage(ImageId image_id) { if (True(image.flags & ImageFlagBits::Tracked)) { return; } + if (True(image.flags & ImageFlagBits::TailTracked)) { + // Re-track only image head + TrackImageHead(image_id); + } else { + // Re-track the whole image + image.flags |= ImageFlagBits::Tracked; + tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, 1); + } +} + +void TextureCache::TrackImageHead(ImageId image_id) { + auto& image = slot_images[image_id]; + if (True(image.flags & ImageFlagBits::Tracked)) { + return; + } + ASSERT(True(image.flags & ImageFlagBits::TailTracked)); image.flags |= ImageFlagBits::Tracked; - tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, 1); + image.flags &= ~ImageFlagBits::TailTracked; + const auto size = tracker.GetNextPageAddr(image.cpu_addr) - image.cpu_addr; + tracker.UpdatePagesCachedCount(image.cpu_addr, size, 1); } void TextureCache::UntrackImage(ImageId image_id) { + auto& image = slot_images[image_id]; + ASSERT(!True(image.flags & ImageFlagBits::Tracked) || + !True(image.flags & ImageFlagBits::TailTracked)); + if (True(image.flags & ImageFlagBits::Tracked)) { + image.flags &= ~ImageFlagBits::Tracked; + tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, -1); + } + if (True(image.flags & ImageFlagBits::TailTracked)) { + image.flags &= ~ImageFlagBits::TailTracked; + const auto addr = tracker.GetNextPageAddr(image.cpu_addr); + const auto size = image.info.guest_size_bytes - (addr - image.cpu_addr); + tracker.UpdatePagesCachedCount(addr, size, -1); + } +} + +void TextureCache::UntrackImageHead(ImageId image_id) { auto& image = slot_images[image_id]; if (False(image.flags & ImageFlagBits::Tracked)) { return; } + image.flags |= ImageFlagBits::TailTracked; image.flags &= ~ImageFlagBits::Tracked; - tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, -1); + const auto size = tracker.GetNextPageAddr(image.cpu_addr) - image.cpu_addr; + tracker.UpdatePagesCachedCount(image.cpu_addr, size, -1); } void TextureCache::DeleteImage(ImageId image_id) { Image& image = slot_images[image_id]; ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked"); + ASSERT_MSG(False(image.flags & ImageFlagBits::TailTracked), "Image was not untracked"); ASSERT_MSG(False(image.flags & ImageFlagBits::Registered), "Image was not unregistered"); // Remove any registered meta areas. diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index fd792bc96..0dc14a2c6 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -243,9 +243,15 @@ private: /// Track CPU reads and writes for image void TrackImage(ImageId image_id); + /// Track CPU reads and writes for image + void TrackImageHead(ImageId image_id); + /// Stop tracking CPU reads and writes for image void UntrackImage(ImageId image_id); + /// Stop tracking CPU reads and writes for the first page of the image + void UntrackImageHead(ImageId image_id); + /// Removes the image and any views/surface metas that reference it. void DeleteImage(ImageId image_id);