From d294001f414944ef668f867b9e82c95ccdcb7340 Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Wed, 28 Oct 2026 23:46:53 -0400 Subject: vulkan: 64 MiB VMA blocks; device memory usage without VMA block slack Title 1's texture cache deleted 1,400-2,600 textures per 600 frames and created them again: device memory sat at the collector's critical line, but ~38% of it was empty space in 256 MiB VMA blocks. Freeing an image returns that space only once its whole block is empty, so the caches kept collecting without the usage dropping (one mass purge deleted 4,300 textures). - 64 MiB blocks on discrete GPUs too (as on integrated ones). - GetDeviceMemoryUsage subtracts the unused bytes in VMA blocks, so each eviction counts at once. Now 0-224 deletions per 600 frames, ~4,400 textures resident, and driver usage 6.24 GB of a 6.97 GB budget. --- src/video_core/vulkan_common/vulkan_device.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'src/video_core/vulkan_common/vulkan_device.cpp') diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 454e5d4e02..69c3ba14fa 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -5,6 +5,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include #include @@ -752,9 +753,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR .flags = flags, .physicalDevice = physical, .device = *logical, - .preferredLargeHeapBlockSize = is_integrated - ? (64u * 1024u * 1024u) - : (256u * 1024u * 1024u), + // 64 MiB blocks on discrete GPUs too: with 256 MiB ones, Switch 2 titles' mix of + // texture sizes left ~38% of the image blocks empty (2 GB of an 8 GB card in title + // 1), which the texture cache counted as used and kept evicting textures for. + .preferredLargeHeapBlockSize = 64u * 1024u * 1024u, .pAllocationCallbacks = nullptr, .pDeviceMemoryCallbacks = nullptr, .pHeapSizeLimit = nullptr, @@ -1609,6 +1611,19 @@ u64 Device::GetDeviceMemoryUsage() const { for (const size_t heap : valid_heap_memory) { result += budget.heapUsage[heap]; } + // Space in VMA's blocks that no allocation uses counts as used, but freeing an image gives + // its share back only once its whole block is empty: the caches, collecting until this drops, + // evicted thousands of textures in a row without lowering it (title 1). Count only what + // allocations use. + if (allocator != nullptr) { + std::array heap_budgets{}; + vmaGetHeapBudgets(allocator, heap_budgets.data()); + for (const size_t heap : valid_heap_memory) { + const VmaStatistics& statistics = heap_budgets[heap].statistics; + const u64 unused = statistics.blockBytes - statistics.allocationBytes; + result -= (std::min)(result, unused); + } + } return result; } -- cgit v1.2.3