diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-31 16:05:55 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-31 16:05:55 -0400 |
| commit | 75385e994dc8cc8699a918180ee566e8723b8394 (patch) | |
| tree | 81b948f44a8b7ad366c93bcf592e515fc4bd802f /src/video_core/texture_cache | |
| parent | 9dca3ab2e436e786ab53e862e4d515f620a11669 (diff) | |
texture_cache: don't count deleted images still waiting to be destroyed
The collector deletes images into a ring that destroys them TICKS_TO_DESTROY
frames later, and until then the driver still counts their memory. Reading the
driver's usage every frame, the collector saw no drop after deleting and kept
deleting 40+ images a frame in aggressive mode long after it had freed enough:
once a session reached the critical threshold, frames took over 100 ms for
seconds at a time.
Keep the bytes deleted into each slot of the ring and leave them out of the
reported usage until the ring destroys them.
Diffstat (limited to 'src/video_core/texture_cache')
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 11 | ||||
| -rw-r--r-- | src/video_core/texture_cache/texture_cache_base.h | 4 |
2 files changed, 15 insertions, 0 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index c8aaf8dff5..71f89db367 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -250,6 +250,12 @@ void TextureCache<P>::TickFrame() { // If we can obtain the memory info, use it instead of the estimate. if (runtime.CanReportMemoryUsage()) { total_used_memory = runtime.GetDeviceMemoryUsage(); + // Images the collector deleted keep their memory for TICKS_TO_DESTROY frames: counting + // it kept the collector in aggressive mode, deleting 40+ images a frame for frames after + // it had freed enough (title 1: frames over 100 ms for seconds at a time). + for (const u64 bytes : sentenced_image_bytes) { + total_used_memory -= (std::min)(total_used_memory, 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). @@ -316,6 +322,8 @@ void TextureCache<P>::TickFrame() { RunGarbageCollector(); } sentenced_images.Tick(); + sentenced_image_index = (sentenced_image_index + 1) % TICKS_TO_DESTROY; + sentenced_image_bytes[sentenced_image_index] = 0; sentenced_framebuffers.Tick(); sentenced_image_view.Tick(); TickAsyncDecode(); @@ -2832,6 +2840,8 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) { } // TickFrame sets the total from the driver, which can be under the sum of these estimates. total_used_memory -= (std::min)(total_used_memory, ImageMemoryBytes(slot_images[image_id])); + const u64 freed_bytes = (image.HasScaled() ? GetScaledImageSizeBytes(image) : 0) + + ImageMemoryBytes(slot_images[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()) { @@ -2897,6 +2907,7 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) { 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; } slot_images.erase(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 94102cd261..d51eefeee8 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -552,6 +552,10 @@ private: static constexpr size_t TICKS_TO_DESTROY = 8; #endif DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images; + /// Device memory of the images in each slot of sentenced_images (same index): deleted, but + /// counted in the driver's usage until the ring destroys them. + std::array<u64, TICKS_TO_DESTROY> sentenced_image_bytes{}; + size_t sentenced_image_index = 0; DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view; DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers; |
