Skip to content

vk: imports given back under system-heap pressure on 16 GB PCs - #479

Merged
NotRexed merged 1 commit into
NotRexed:mainfrom
imbahzor:feat/16gb-import-giveback
Nov 8, 2026
Merged

NotRexed merged 1 commit into
NotRexed:mainfrom
imbahzor:feat/16gb-import-giveback

Conversation

@imbahzor

@imbahzor imbahzor commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Imports given back under system-heap pressure (16 GB PCs)

Problem

The renderer imports the game's memory pools with VK_EXT_external_memory_host. The driver pins those pages and counts them in the system heap the GPU reaches, whose budget is about half the PC's RAM: 7503 MB on an RTX 3060 with 16 GB. Imports are kept for the whole session, so on a 16 GB PC that heap fills up:

  • a vanilla session (no-visual-studio) climbed to 7199 of 7503 MB in under 20 minutes (2320 → 5267 → 6289 → 6796 → 7199 MB);
  • past the budget, new imports fail with VK_ERROR_OUT_OF_DEVICE_MEMORY (seen at 7758 of 7503 MB): terrain left out, load zones stuck while the import is retried.

Change

Every 16 submissions, memory_begin_submission asks VMA for the system heaps' use and budget (system_heap_usage, a fresh frame index so the driver is asked again). Past RX_VK_IMPORT_HIGH percent of the budget (default 85), the pools bound least lately give their imports back down to RX_VK_IMPORT_LOW percent (default 75):

  • only pools without a mirror (MIRROR_NONE / MIRROR_REFUSED), not bound for 600 submissions and done on the GPU (last_value <= mem_completed);
  • they leave the table as a retired pool does (page table entries 0, pools_gen bumped, the pool caches emptied) and are imported again at their next binding;
  • their buffer and memory are freed only once everything recorded until then is done (retired_value = mem_rec_value, checked against mem_completed), the same rule as the dead mirrors;
  • gpu_buffer() (texture uploads) now marks the pool in use too, so a pool only touched by uploads is not given back under them.

On by default only where the system heap's budget is under 12 GB (16 GB PCs and less), where it ran out; larger PCs are unchanged. RX_VK_IMPORT_HIGH=0 turns it off, RX_VK_IMPORT_HIGH=85 turns it on anywhere.

Caveat

last_value counts bindings, not shaders that reach a pool through the guest page table. A pool reached only that way could be given back while idle by bindings and would read zeros until it is bound again. I have not seen it in play (the pools given back were long unbound), but it is the reason this stays limited to small budgets and to pools idle for 600 submissions. If you know a better "in use" signal for page-table reads, I'd happily switch to it.

Testing

  • RTX 3060 12 GB, 16 GB RAM, Windows 11: this logic has run for several hours of play on the foliage and no-visual-studio releases (applied locally): the heap stays at or under ~85%, no terrain loss, no stuck load zones, no device lost attributable to it (the device losses seen came from other changes and were bisected away).
  • On current main the port builds cleanly (RX_VK_ONLY=1); I could not run it there, because MKWVK_API_VERSION went to 4 and my installed game is the release build. Happy to do a full build from main and test if you'd like.

🤖 Generated with Claude Code

The driver pins every imported pool and counts it in the system heap the GPU reaches, whose budget is about half the
PC's RAM (7.5 GB with 16 GB). Imports were kept for the session: on an RTX 3060 with 16 GB the heap went past its
budget (7758 of 7503 MB) and new imports failed with VK_ERROR_OUT_OF_DEVICE_MEMORY (terrain left out, load zones
stuck); a vanilla session climbed to 7199 of 7503 MB in under 20 minutes.

Past RX_VK_IMPORT_HIGH percent of the budget (85) the pools bound least lately give their imports back down to
RX_VK_IMPORT_LOW percent (75): only pools without a mirror, unbound for 600 submissions and done on the GPU. They leave
the table as a retired pool does and are imported again at their next binding; their memory is freed once everything
recorded until then is done. On by default only where that budget is under 12 GB; RX_VK_IMPORT_HIGH=0: off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@NotRexed
NotRexed merged commit d1e741d into NotRexed:main Nov 8, 2026
NotRexed added a commit that referenced this pull request Nov 8, 2026
Off by default on _WIN32 (RX_VK_IMPORT_HIGH=85 turns it on), as giving retired
imports back is (RX_VK_KEEP_RETIRED); on Linux the default stays the PR's.
A pool given back also frees its dma-buf pieces (#448's sparse pools).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants