From 55d315c644fdf36405daaf71f75942553a267a6e Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Wed, 28 Oct 2026 17:08:43 -0400 Subject: ASTC: re-compress to BC3 except huge arrays, which stay RGBA8 and trimmed Title 1 has ~700 ASTC 8x8 textures (~280 MB as stored); decoded to RGBA8 they took ~4.5 GB, pushing Eden past the 8 GB of an RTX 4070 Laptop (8.4-9.8 GB in use) and the texture cache into permanent aggressive collection. With astc_recompression=Bc3 (CPU, asynchronous) they fit (4.6-5.6 GB). The two 8192x8192x68 terrain arrays would still not fit as BC3, so ASTC 2D arrays over 1 GiB as RGBA8 always use the GPU decoder with trimmed levels (RGBA8 host image, UNORM/sRGB views), and the decoder pass now exists whenever the GPU lacks native ASTC. Also logs every 600 frames: device memory against the collector thresholds, the largest images, totals by format, and buffer cache totals. Title screen 65-150 s: 10.1 -> 16.0 fps. --- src/video_core/texture_cache/texture_cache.h | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (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 e1cb493697..11de37eb6b 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -6,7 +6,10 @@ #pragma once +#include #include +#include +#include #include #include #include "common/container/unordered_map.h" @@ -173,6 +176,43 @@ void TextureCache

::TickFrame() { if (runtime.CanReportMemoryUsage()) { total_used_memory = runtime.GetDeviceMemoryUsage(); } + // 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). + if (static u64 frames{}; ++frames % 600 == 0) { + u64 image_bytes{}; + size_t images{}; + std::vector> largest; + std::map> by_format; + for (const auto [image_id, image] : slot_images) { + const u64 bytes = GetScaledImageSizeBytes(*image); + image_bytes += bytes; + ++images; + largest.emplace_back(bytes, image); + auto& format = by_format[static_cast(image->info.format)]; + format.first += bytes; + ++format.second; + } + LOG_INFO(HW_GPU, "Texture cache: device memory {} MiB (expected {} MiB, critical {} MiB), {} images {} MiB", + total_used_memory >> 20, expected_memory >> 20, critical_memory >> 20, images, + image_bytes >> 20); + std::partial_sort(largest.begin(), largest.begin() + std::min(12, largest.size()), + largest.end(), [](const auto& a, const auto& b) { return a.first > b.first; }); + for (size_t i = 0; i < std::min(12, largest.size()); ++i) { + const Image& image = *largest[i].second; + LOG_INFO(HW_GPU, " {} MiB: {:#x} {}x{}x{} layers {} levels {} format {} type {} flags {:#x}", + largest[i].first >> 20, image.gpu_addr, image.info.size.width, image.info.size.height, + image.info.size.depth, image.info.resources.layers, image.info.resources.levels, + static_cast(image.info.format), static_cast(image.info.type), + static_cast(image.flags)); + } + std::vector> formats; + for (const auto& [format, total] : by_format) formats.emplace_back(total.first, format); + std::sort(formats.rbegin(), formats.rend()); + for (size_t i = 0; i < std::min(8, formats.size()); ++i) { + LOG_INFO(HW_GPU, " format {}: {} MiB in {} images", formats[i].second, formats[i].first >> 20, + by_format[formats[i].second].second); + } + } if (total_used_memory > minimum_memory) { RunGarbageCollector(); } -- cgit v1.2.3