diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-31 01:32:04 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-31 01:32:04 -0400 |
| commit | a03e816886f4241309a6e77ba7df1ad922da1fc0 (patch) | |
| tree | 034f04751a0ee44b0ec6840a111adb7553f05174 /src/core | |
| parent | b40ad217ab829226841cb71f6e4c5cb05977a225 (diff) | |
nx2: let the host page out texture pool backing first
Switch 2 sparse blocks and GPU-only regions get guest memory when a game
writes them (Mario Kart World copies 2-4 GB of compressed textures into
its sparse texture pools) and the texture cache reads it again only when
it builds an image there. Every 30 s, mark that backing cold: its pages
leave the working set (VirtualUnlock on Windows, MADV_PAGEOUT on Linux)
so the OS compresses or pages them out before anything else when RAM is
short. The contents stay. Mario Kart World: 8.5 GB of RAM in use at five
minutes instead of 9.0 GB on a machine with RAM to spare, frame times
unchanged.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/service/nx2_gsv.h | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/src/core/hle/service/nx2_gsv.h b/src/core/hle/service/nx2_gsv.h index 9d00b81368..2551a98211 100644 --- a/src/core/hle/service/nx2_gsv.h +++ b/src/core/hle/service/nx2_gsv.h @@ -786,6 +786,46 @@ private: std::array<Kernel::KEvent*, NumIds> m_events{}; std::map<u32, GpuMemory> m_memory; u32 m_next_memory_handle{1}; + + // Every 30 s: the backing of sparse blocks and GPU-only regions is marked cold. The game + // writes it once (texture uploads by 2D blits: title 1 fills 2-4 GB of texture pools) and it + // is read again only when the texture cache builds an image over it, so the OS may compress or + // page it out before anything else. Last member: stops before the regions are destroyed. + void HintColdBacking() { + struct Range { + u64 physical_offset; + u64 virtual_address; + u64 size; + }; + std::vector<Range> ranges; + { + std::scoped_lock lk{m_region_mutex}; + for (const auto& [gpu_address, region] : m_gpu_only_regions) { + u64 virtual_address = region.cpu_address; + for (const auto& block : *region.pages) { + ranges.push_back({GetInteger(block.GetAddress()) - Core::DramMemoryMap::Base, + virtual_address, block.GetSize()}); + virtual_address += block.GetSize(); + } + } + } + auto& buffer = system.DeviceMemory().buffer; + for (const Range& range : ranges) { + buffer.HintCold(range.physical_offset, range.size, range.virtual_address); + } + } + std::jthread m_cold_hint_thread{[this](std::stop_token stop) { + Common::SetCurrentThreadName("nx2:ColdHint"); + Common::SetCurrentThreadPriority(Common::ThreadPriority::Low); + while (!stop.stop_requested()) { + for (int i = 0; i < 30 && !stop.stop_requested(); ++i) { + std::this_thread::sleep_for(std::chrono::seconds{1}); + } + if (!stop.stop_requested()) { + HintColdBacking(); + } + } + }}; }; // Native memory and images handed out by the Switch 2 graphics server (gsv 111/114/423/429/315), |
