From 446c34aa8b305deb9f0870721d2126da8c186368 Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Sat, 31 Oct 2026 23:24:25 -0400 Subject: texture_cache: free deleted images once the GPU is past them Deleted images kept their device memory for TICKS_TO_DESTROY (8) frames. While the collector deletes dozens a frame that held 1-1.5 GB of VRAM on top of its threshold, which the collector does not count (Mario Kart World on an 8 GB card: 6.6-7.0 GB in use against 5 GiB). On runtimes that report GPU progress (Vulkan) an image is destroyed as soon as the GPU is past it. Title screen, 10 minutes: VRAM in use 6.75 -> 6.34 GB on average, frames over 100 ms 22 -> 15. (cherry picked from commit 8c899541baf398deb892a857a932590f32d2aa4f) --- src/video_core/texture_cache/texture_cache.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/video_core/texture_cache/texture_cache.h') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 71f89db367..46ebf6a25f 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -247,6 +247,13 @@ void TextureCache

::TickFrame() { } } } + if constexpr (requires { runtime.CurrentTick(); }) { + while (!gpu_sentenced_images.empty() && + runtime.IsFree(gpu_sentenced_images.front().tick)) { + gpu_sentenced_bytes -= gpu_sentenced_images.front().bytes; + gpu_sentenced_images.pop_front(); + } + } // If we can obtain the memory info, use it instead of the estimate. if (runtime.CanReportMemoryUsage()) { total_used_memory = runtime.GetDeviceMemoryUsage(); @@ -256,6 +263,7 @@ void TextureCache

::TickFrame() { for (const u64 bytes : sentenced_image_bytes) { total_used_memory -= (std::min)(total_used_memory, bytes); } + total_used_memory -= (std::min)(total_used_memory, gpu_sentenced_bytes); } // Every 600 frames: device memory in use against the collector's thresholds, and what the // images themselves account for (VRAM pressure makes the collector thrash). @@ -2906,8 +2914,14 @@ void TextureCache

::DeleteImage(ImageId image_id, bool immediate_delete) { if (retained) { LOG_INFO(Render_Vulkan, "Retained image for queued download: id={}", image_id.Value()); } else if (!immediate_delete) { - sentenced_images.Push(std::move(slot_images[image_id])); - sentenced_image_bytes[sentenced_image_index] += freed_bytes; + if constexpr (requires { runtime.CurrentTick(); }) { + gpu_sentenced_images.push_back( + {runtime.CurrentTick(), freed_bytes, std::move(slot_images[image_id])}); + gpu_sentenced_bytes += freed_bytes; + } else { + sentenced_images.Push(std::move(slot_images[image_id])); + sentenced_image_bytes[sentenced_image_index] += freed_bytes; + } } slot_images.erase(image_id); -- cgit v1.2.3