From 6912d650f7d0b47dfec9705ca6c400f90ada5bef Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Thu, 29 Oct 2026 07:05:03 -0400 Subject: texture_cache: count evictions that download; EDEN_NX2_TC_MIN_AGE knob The collector's periodic log now also counts evictions that downloaded the image first (each a full GPU wait). EDEN_NX2_TC_MIN_AGE= keeps images used more recently than that (a VRAM thrash test on 8 GB: 120 frames made no difference over three runs). --- src/video_core/texture_cache/texture_cache.h | 12 ++++++++++-- 1 file changed, 10 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 fb8adef161..b95d9d8a39 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -129,6 +129,12 @@ void TextureCache

::RunGarbageCollector() { high_priority_mode = total_used_memory >= expected_memory; aggressive_mode = allow_aggressive && total_used_memory >= critical_memory; ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 50ULL; + // EDEN_NX2_TC_MIN_AGE=: never evict images used more recently (thrash tests). + static const u64 min_age = [] { + const char* value = std::getenv("EDEN_NX2_TC_MIN_AGE"); + return value != nullptr ? std::strtoull(value, nullptr, 10) : 0ULL; + }(); + ticks_to_destroy = (std::max)(ticks_to_destroy, min_age); num_iterations = aggressive_mode ? 40 : (high_priority_mode ? 20 : 10); }; const auto Cleanup = [this, &num_iterations, &high_priority_mode, &aggressive_mode](ImageId image_id) { @@ -150,6 +156,7 @@ void TextureCache

::RunGarbageCollector() { image.DownloadMemory(map, copies); runtime.Finish(); SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span, swizzle_data_buffer); + ++gc_download_deletes; } if (True(image.flags & ImageFlagBits::Tracked)) { UntrackImage(image, image_id); @@ -269,8 +276,9 @@ void TextureCache

::TickFrame() { if constexpr (requires { runtime.LogMemoryStatistics(); }) { runtime.LogMemoryStatistics(); } - LOG_INFO(HW_GPU, "Texture cache last 600 frames: created {} images, deleted {} (collector {}, {} costly), {} async decodes, ASTC {} opaque / {} alpha", + LOG_INFO(HW_GPU, "Texture cache last 600 frames: created {} images, deleted {} (collector {}, {} costly, {} downloaded), {} async decodes, ASTC {} opaque / {} alpha", images_created, images_deleted, gc_deletes + gc_costly_deletes, gc_costly_deletes, + gc_download_deletes, async_decodes_queued, astc_opaque_images, astc_alpha_images); astc_opaque_images = astc_alpha_images = 0; std::vector> shapes; @@ -284,7 +292,7 @@ void TextureCache

::TickFrame() { created_shapes[key].second); } created_shapes.clear(); - gc_deletes = gc_costly_deletes = async_decodes_queued = 0; + gc_deletes = gc_costly_deletes = gc_download_deletes = async_decodes_queued = 0; images_created = images_deleted = 0; } if (total_used_memory > minimum_memory) { -- cgit v1.2.3 From a1d47717ae7f0445fb9d491a4d548aec17b1c053 Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Fri, 30 Oct 2026 00:20:05 -0400 Subject: nx2: log per-call and periodic diagnostic lines at debug level A 9-minute Mario Kart World session wrote 36k log lines at the default level, most of them one per GPU call: nx2:syncpt 201/202 (12k), gpu submit jobs (7k), memory registrations (7k), "Lowered native shader" (1.6k), and 4.7k "Storage buffer tracked without bias" warnings, which every Switch 2 shader hits. These, the texture cache's per-image and per-format detail lines, the 3D image shapes and the per-type VMA lines are now debug level. The once-a-report summary lines (texture cache memory, images created/deleted, VMA heap budget) stay at info. --- .../ir_opt/global_memory_to_storage_buffer_pass.cpp | 2 +- src/video_core/texture_cache/texture_cache.h | 8 ++++---- src/video_core/vulkan_common/vulkan_memory_allocator.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/video_core/texture_cache/texture_cache.h') diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index bdb4494a15..6aee241dc2 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp @@ -414,7 +414,7 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageInfo& info) LOG_WARNING(Shader, "Storage buffer failed to track, using global memory fallbacks"); return; } - LOG_WARNING(Shader, "Storage buffer tracked without bias, index {} offset {}", + LOG_DEBUG(Shader, "Storage buffer tracked without bias, index {} offset {}", storage_buffer->index, storage_buffer->offset); } // Collect storage buffer and the instruction diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index b95d9d8a39..62cd523073 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -260,7 +260,7 @@ void TextureCache

::TickFrame() { 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}", + LOG_DEBUG(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), @@ -270,7 +270,7 @@ void TextureCache

::TickFrame() { 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, + LOG_DEBUG(HW_GPU, " format {}: {} MiB in {} images", formats[i].second, formats[i].first >> 20, by_format[formats[i].second].second); } if constexpr (requires { runtime.LogMemoryStatistics(); }) { @@ -286,7 +286,7 @@ void TextureCache

::TickFrame() { std::sort(shapes.rbegin(), shapes.rend()); for (size_t i = 0; i < std::min(10, shapes.size()); ++i) { const u64 key = shapes[i].second; - LOG_INFO(HW_GPU, " created {}x: format {} type {} levels {} layers {} {}x{} (last at {:#x})", + LOG_DEBUG(HW_GPU, " created {}x: format {} type {} levels {} layers {} {}x{} (last at {:#x})", shapes[i].first, key >> 56, (key >> 52) & 0xF, (key >> 48) & 0xF, (key >> 36) & 0xFFF, (key >> 18) & 0x3FFFF, key & 0x3FFFF, created_shapes[key].second); @@ -1763,7 +1763,7 @@ ImageId TextureCache

::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr, storage_info.native_tiling = gpu_memory->UsesNativeTiling(); if (storage_info.native_tiling && info.type == ImageType::e3D) { // Switch 2 3D images (lighting/fog volumes) are rare: log each one's shape. - LOG_INFO(HW_GPU, "3D image at {:#x}: {}x{}x{} levels {} format {} block {}x{}x{}", + LOG_DEBUG(HW_GPU, "3D image at {:#x}: {}x{}x{} levels {} format {} block {}x{}x{}", gpu_addr, info.size.width, info.size.height, info.size.depth, info.resources.levels, static_cast(info.format), info.block.width, info.block.height, info.block.depth); } diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 27f8fa6b4c..8bf692b00e 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -465,7 +465,7 @@ void LogMemoryStatistics(const Device& device) { if (s.blockCount == 0) { continue; } - LOG_INFO(Render_Vulkan, "VMA type {} (heap {}, flags {:#x}): {} blocks {} MiB, {} allocations {} MiB", + LOG_DEBUG(Render_Vulkan, "VMA type {} (heap {}, flags {:#x}): {} blocks {} MiB, {} allocations {} MiB", type, properties->memoryTypes[type].heapIndex, static_cast(properties->memoryTypes[type].propertyFlags), s.blockCount, s.blockBytes >> 20, s.allocationCount, s.allocationBytes >> 20); -- cgit v1.2.3