From 20e6c163a62316647b67a2f4298a4bd8e9bd3ee8 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 18 Jul 2026 17:49:22 -0400 Subject: [PATCH] [TEST] Extend coalescing to more gpu to cpu regions --- src/video_core/buffer_cache/buffer_cache.h | 8 +++++++- .../buffer_cache/buffer_cache_base.h | 2 ++ .../buffer_cache/memory_tracker_base.h | 18 ++++++++++++++++++ src/video_core/buffer_cache/word_manager.h | 18 ++++++++++++++++++ .../renderer_vulkan/vk_rasterizer.cpp | 8 +++++--- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 641e38934b..7dbecb4fe1 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -791,6 +791,11 @@ bool BufferCache

::IsRegionGpuModified(DAddr addr, size_t size) { return is_dirty; } +template +bool BufferCache

::IsRegionGpuModifiedCheap(DAddr addr, size_t size) { + return memory_tracker.IsRegionGpuModifiedCheap(addr, size); +} + template bool BufferCache

::IsRegionRegistered(DAddr addr, size_t size) { const DAddr end_addr = addr + size; @@ -1025,7 +1030,8 @@ void BufferCache

::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 }(); const bool use_fast_buffer = needs_alignment_stream || (has_host_buffer && size <= channel_state->uniform_buffer_skip_cache_size - && !memory_tracker.IsRegionGpuModified(device_addr, size)); + && !(memory_tracker.IsRegionGpuModifiedCheap(device_addr, size) + && memory_tracker.IsRegionGpuModified(device_addr, size))); if (use_fast_buffer) { if constexpr (IS_OPENGL) { if (runtime.HasFastBufferSubData()) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 3b900b95f9..622f222f2b 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -300,6 +300,8 @@ public: /// Return true when a CPU region is modified from the GPU [[nodiscard]] bool IsRegionGpuModified(DAddr addr, size_t size); + [[nodiscard]] bool IsRegionGpuModifiedCheap(DAddr addr, size_t size); + /// Return true when a region is registered on the cache [[nodiscard]] bool IsRegionRegistered(DAddr addr, size_t size); diff --git a/src/video_core/buffer_cache/memory_tracker_base.h b/src/video_core/buffer_cache/memory_tracker_base.h index 4c9e978484..329c7e890d 100644 --- a/src/video_core/buffer_cache/memory_tracker_base.h +++ b/src/video_core/buffer_cache/memory_tracker_base.h @@ -69,6 +69,24 @@ public: return false; } + [[nodiscard]] bool IsRegionGpuModifiedCheap(VAddr query_cpu_addr, u64 query_size) noexcept { + std::size_t remaining_size{query_size}; + std::size_t page_index{query_cpu_addr >> HIGHER_PAGE_BITS}; + u64 page_offset{query_cpu_addr & HIGHER_PAGE_MASK}; + while (remaining_size > 0) { + const std::size_t copy_amount{ + std::min(HIGHER_PAGE_SIZE - page_offset, remaining_size)}; + const Manager* manager = top_tier[page_index].load(std::memory_order_acquire); + if (manager != nullptr && manager->GpuModifiedPageCount() != 0) { + return true; + } + page_index++; + page_offset = 0; + remaining_size -= copy_amount; + } + return false; + } + /// Returns true if a region has been modified from the CPU [[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept { return IteratePages(query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) { diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h index 2e8717f195..0779adbd35 100644 --- a/src/video_core/buffer_cache/word_manager.h +++ b/src/video_core/buffer_cache/word_manager.h @@ -127,6 +127,7 @@ struct WordManager { [[maybe_unused]] std::span cached_words = Span(Type::CachedCPU); std::vector> ranges; s64 cpu_delta = 0; + s64 gpu_delta = 0; IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) { if (type == Type::CPU || type == Type::CachedCPU) { CollectChangedRanges(!enable, index, untracked_words[index], mask, ranges); @@ -134,6 +135,9 @@ struct WordManager { if (type == Type::CPU) { const u64 old = state_words[index]; cpu_delta += enable ? std::popcount(~old & mask) : -std::popcount(old & mask); + } else if (type == Type::GPU) { + const u64 old = state_words[index]; + gpu_delta += enable ? std::popcount(~old & mask) : -std::popcount(old & mask); } if (enable) { state_words[index] |= mask; @@ -152,6 +156,9 @@ struct WordManager { if (cpu_delta != 0) { cpu_modified_pages.fetch_add(static_cast(cpu_delta), std::memory_order_release); } + if (gpu_delta != 0) { + gpu_modified_pages.fetch_add(static_cast(gpu_delta), std::memory_order_release); + } if (!ranges.empty()) { ApplyCollectedRanges(ranges, (!enable) ? 1 : -1); } @@ -180,6 +187,7 @@ struct WordManager { }; std::vector> ranges; s64 cpu_delta = 0; + s64 gpu_delta = 0; IterateWords(offset, size, [&](size_t index, u64 mask) { if (type == Type::GPU) mask &= ~untracked_words[index]; @@ -190,6 +198,8 @@ struct WordManager { } if (type == Type::CPU) cpu_delta -= std::popcount(word); + else if (type == Type::GPU) + gpu_delta -= std::popcount(word); state_words[index] &= ~mask; if (type == Type::CPU || type == Type::CachedCPU) untracked_words[index] &= ~mask; @@ -214,6 +224,9 @@ struct WordManager { if (cpu_delta != 0) { cpu_modified_pages.fetch_add(static_cast(cpu_delta), std::memory_order_release); } + if (gpu_delta != 0) { + gpu_modified_pages.fetch_add(static_cast(gpu_delta), std::memory_order_release); + } if (pending) { release(); } @@ -348,10 +361,15 @@ struct WordManager { return cpu_modified_pages.load(std::memory_order_acquire); } + [[nodiscard]] u32 GpuModifiedPageCount() const noexcept { + return gpu_modified_pages.load(std::memory_order_acquire); + } + std::array heap = {}; DeviceTracker* tracker = nullptr; VAddr cpu_addr = 0; std::atomic cpu_modified_pages{0}; + std::atomic gpu_modified_pages{0}; }; } // namespace VideoCommon diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index e7120fe8bb..b6664f93a4 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -684,9 +684,11 @@ void RasterizerVulkan::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType bool RasterizerVulkan::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) { if ((True(which & VideoCommon::CacheType::BufferCache))) { - std::scoped_lock lock{buffer_cache.mutex}; - if (buffer_cache.IsRegionGpuModified(addr, size)) { - return true; + if (buffer_cache.IsRegionGpuModifiedCheap(addr, size)) { + std::scoped_lock lock{buffer_cache.mutex}; + if (buffer_cache.IsRegionGpuModified(addr, size)) { + return true; + } } } if (!Settings::IsGPULevelHigh()) {