feat: Refresh memory in the Insert menu, and keep the game's memory in RAM #888

Open
yassine-milal wants to merge 1 commit from yassine-milal/feat/refresh-memory into main
yassine-milal commented 2026-11-09 00:21:29 +00:00 (Migrated from github.com)

With other programs in front (a browser, a chat app), Windows took the game's pages away:

  • on a 32 GB PC the working set fell from 13-15 GB to 6.3 GB;
  • 18,000 page faults a second, 3 fps with every thread idle and VRAM within its limit;
  • only a restart brought it back.

Changes:

  • At start-up (after vma_init): a working-set minimum of a third of the RAM, at most 10 GB
    (RX_VK_MIN_WORKING_SET_MB=<MB>, 0 = off). A hard minimum, a soft one if refused, and logged. On that PC the log
    said: "at least 10240 MB ... kept (hard minimum)".
  • Graphics tab, "Refresh memory" (A / Enter): the next texture housekeeping lets go of every texture not drawn for
    60 frames, whatever the budget, and asks for the working set again. The existing protections stay. It does for
    memory what a restart does, without leaving the game.

Testing. Played on a Quadro P4000 (Pascal, 8 GB, no mesh shaders), NVIDIA 582.16, Xeon W-2133, 32 GB, Windows 11, with Hookshot v2.0.2 and the same change. On main this branch compiles (RX_VK_ONLY=1 nx2/build.py --standalone, llvm-mingw) and tests/run_all.py gives the same result as untouched main on this PC: 98 passed, 12 skipped, 1 failed (tests/test_fps_overlay_order.py, which fails on main here too with llvm-mingw's clang). The game itself was not rebuilt on main.

🤖 Generated with Claude Code

With other programs in front (a browser, a chat app), Windows took the game's pages away: - on a 32 GB PC the working set fell from 13-15 GB to 6.3 GB; - 18,000 page faults a second, 3 fps with every thread idle and VRAM within its limit; - only a restart brought it back. Changes: - **At start-up** (after `vma_init`): a working-set minimum of a third of the RAM, at most 10 GB (`RX_VK_MIN_WORKING_SET_MB=<MB>`, 0 = off). A hard minimum, a soft one if refused, and logged. On that PC the log said: "at least 10240 MB ... kept (hard minimum)". - **Graphics tab, "Refresh memory"** (A / Enter): the next texture housekeeping lets go of every texture not drawn for 60 frames, whatever the budget, and asks for the working set again. The existing protections stay. It does for memory what a restart does, without leaving the game. **Testing.** Played on a Quadro P4000 (Pascal, 8 GB, no mesh shaders), NVIDIA 582.16, Xeon W-2133, 32 GB, Windows 11, with Hookshot v2.0.2 and the same change. On `main` this branch compiles (`RX_VK_ONLY=1 nx2/build.py --standalone`, llvm-mingw) and `tests/run_all.py` gives the same result as untouched `main` on this PC: 98 passed, 12 skipped, 1 failed (`tests/test_fps_overlay_order.py`, which fails on `main` here too with llvm-mingw's clang). The game itself was not rebuilt on `main`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hckrman101 (Migrated from github.com) approved these changes 2026-11-09 23:07:47 +00:00
hckrman101 (Migrated from github.com) left a comment

Looks good to me. I read through it and nothing blocks the merge.

  • The Refresh row goes before the pad_layout/preset chain in menu_tick, so pressing it doesn't flip the preset to Custom. It also resets itself to 0 before save(), so the ini value is harmless.
  • The forced path in texture_frame still respects all the existing protections (rendered/baked/finalized, last_value > completed), as the description says.
  • working_set_keep() falls back from a hard to a soft minimum and logs which one it got. Its default (a third of RAM, at most 10 GB) is sensible, and RX_VK_MIN_WORKING_SET_MB=0 turns it off.
  • CI is green, including the Windows llvm-mingw build.

Nits, none blocking:

  • The Graphics tab now has 12 rows, so the menu is one row taller on every tab (max_tab_rows()). Fine, but worth a glance on a small window.
  • On Linux the row only does the texture half; working_set_keep() is a no-op there. Maybe say so in the help text, or leave it.
  • A hard working-set minimum means Windows can't trim those pages for other programs, even under pressure. At most 10 GB and opt-out via the env var looks like a fair trade, just worth knowing.
Looks good to me. I read through it and nothing blocks the merge. - The Refresh row goes before the `pad_layout`/preset chain in `menu_tick`, so pressing it doesn't flip the preset to Custom. It also resets itself to 0 before `save()`, so the ini value is harmless. - The `forced` path in `texture_frame` still respects all the existing protections (rendered/baked/finalized, `last_value > completed`), as the description says. - `working_set_keep()` falls back from a hard to a soft minimum and logs which one it got. Its default (a third of RAM, at most 10 GB) is sensible, and `RX_VK_MIN_WORKING_SET_MB=0` turns it off. - CI is green, including the Windows llvm-mingw build. Nits, none blocking: - The Graphics tab now has 12 rows, so the menu is one row taller on every tab (`max_tab_rows()`). Fine, but worth a glance on a small window. - On Linux the row only does the texture half; `working_set_keep()` is a no-op there. Maybe say so in the help text, or leave it. - A hard working-set minimum means Windows can't trim those pages for other programs, even under pressure. At most 10 GB and opt-out via the env var looks like a fair trade, just worth knowing.
hckrman101 commented 2026-11-10 17:48:54 +00:00 (Migrated from github.com)

Heads-up: this conflicts with main now (a lot landed today). Could you merge main into the branch (or rebase) and resolve the conflicts? Thanks!

Heads-up: this conflicts with main now (a lot landed today). Could you merge main into the branch (or rebase) and resolve the conflicts? Thanks!
Joey-Magnus (Migrated from github.com) reviewed 2026-11-11 21:45:47 +00:00
Joey-Magnus (Migrated from github.com) left a comment

This feature isn't on main yet: main has no working-set code and no Refresh row. The branch is about 1350 commits behind, though. It conflicts in vk_internal.h, vk_menu.cpp, vk_menu.h and vk_texture.cpp, and the vk_texture.cpp part is more than a text conflict.

On main, texture_frame now works out evict_to and hold_to for the compaction hold, after the budget is set. It also returns early on the dead-targets cadence (every 10 frames), not every 600. If you only move budget = 0; (vk_texture.cpp:3023 here) across, the hold can still cap what a forced pass evicts. Please set forced after the compaction block, clear evict_to and hold_to when it's set, and check that "not drawn for 60 frames" still holds under main's ordering.

The other point is for the maintainer, not a blocker. The hard working-set minimum is on by default for every Windows user: a third of RAM, so about 2.7 GB on an 8 GB machine. A short note in the readme about RX_VK_MIN_WORKING_SET_MB=0 would help people on small machines.

This feature isn't on main yet: main has no working-set code and no Refresh row. The branch is about 1350 commits behind, though. It conflicts in vk_internal.h, vk_menu.cpp, vk_menu.h and vk_texture.cpp, and the vk_texture.cpp part is more than a text conflict. On main, texture_frame now works out `evict_to` and `hold_to` for the compaction hold, after the budget is set. It also returns early on the dead-targets cadence (every 10 frames), not every 600. If you only move `budget = 0;` (vk_texture.cpp:3023 here) across, the hold can still cap what a forced pass evicts. Please set `forced` after the compaction block, clear `evict_to` and `hold_to` when it's set, and check that "not drawn for 60 frames" still holds under main's ordering. The other point is for the maintainer, not a blocker. The hard working-set minimum is on by default for every Windows user: a third of RAM, so about 2.7 GB on an 8 GB machine. A short note in the readme about `RX_VK_MIN_WORKING_SET_MB=0` would help people on small machines.
Commenting is not possible because the repository is archived.
No description provided.