WIP: perf(vk): the 8 GB cards' VRAM budget step mirrors 2 GB of the game's pools, not 1 #724

Closed
Zapiltar wants to merge 2 commits from Zapiltar/Longshot:perf/mirror-8gb into main
First-time contributor

Type: perf · Risk: low · Tested on: Windows 11, RTX 3060 Ti 8 GB · Needs: another 8 GB card (AMD or NVIDIA), Linux

Why

On 8 GB cards the game's memory pools run out of room in VRAM a few minutes into play, and the GPU then reads the new ones over
PCIe every frame: the frame rate drops and swings from one visit of an area to the next (Kokiri Forest 36 or 59 fps with the
same build). The Balanced (8GB) preset, which every 8 GB card gets, gives the mirrors 1024 MB: less than the 6 GB step's 1536
and half of what Auto gives an 8 GB card. The 6 GB step was raised for the same reason (perf/low-vram-mirror-budget, the RTX
3060 Laptop rows of docs/tested-configurations.md); the 8 GB step was left at 1024. See #130, #668.

What changed

The 8 GB step of the VRAM budget row (4.8 GB, the Balanced (8GB) preset's) gives the mirrors 2048 MB, what Auto gives an 8 GB card
(a quarter, mirror_budget.h auto_bytes), in line with the 6 GB step's 1536.

  • vk: kVramMirrorMb[3] in gpu/vk/vk_menu.cpp, 1024 -> 2048, with the measurement beside it.
  • tests: tests/test_vram_budget_row.py's expected mirrors for Balanced and for the row's 4.8 GB step.

Measurements

Verdict: +22% average fps (median of runs 38.5 -> 45.7), 1% lows +26%, no pool read over PCIe, VRAM under what the driver
allows (it went over it at 1024).

Hardware: Windows 11 Home 10.0.26300, RTX 3060 Ti 8 GB (driver 32.0.16.2114), i7-12700F, 64 GB
Scene: Kokiri Forest, Hyrule Field, Castle Town Market (child), teleported in turn; 1920x1080 output and render (Upscaler
"Game's own", 100%), frame generation off, Quality preset Auto (this PC) = Balanced (8GB), VRAM budget 4.8 GB
Method: scripted through the control bridge: per area 10 s settle, 30 s standing, 30 s turning the camera; a warm-up pass, then a
recorded pass; RX_VK_FRAME_LOG frame times; 3 interleaved runs per side (1024, 1536, 2048 in turn); the average of the six
segments per run, and the median of the runs
How to reproduce: any save; the bench script drives scripts/longshot_ctl.py (teleport 0/1/3, stick R 1 0)

Baseline: main @ 1be60eae built on this PC with its own hot list (work/hot_funcs.txt, both columns alike); the After column is
the same build with RX_VK_MIRROR_MB=2048, which is what this PR's table value gives. Confirmed with this PR's renderer @ 53a00824
in a v3.0.0-rc.4 game folder and no mirror switch (RX_VK_WB_MAX_KB=1024 on, as in that folder): 41.7 and 48.3 fps, 1% lows 20.5
and 26.5, 0 bound in guest memory lines, the mirrors past 1024 MB (1218 MB in the Market)

Before: main @ 1be60eae After, RX_VK_MIRROR_MB=2048: main @ 1be60eae
fps, runs 38.5, 32.7, 40.0 48.2, 45.7, 42.0
fps, median 38.5 45.7
1% low, mean of runs 16.4 20.7
Kokiri / Hyrule Field / Market 43.3 / 38.6 / 29.3 51.6 / 48.6 / 35.7
"bound in guest memory" (GPU reads over PCIe) lines 428, 350, 334 0, 0, 0
VRAM max, MB used of allowed 6929/6744, 7249/6747, 6363/6656 6543/6700, 6529/6762, 6383/6575

1536 MB gave the same (45.7 fps mean, 0 PCIe lines): 2048 is chosen as Auto's quarter, the rule the 6 GB step follows.

Across ~180 area visits of the day's runs at 1024: visits where every pool had its mirror ran Kokiri 58.6 fps (9 visits) and
Hyrule Field 58.5 (4); visits with a pool over PCIe 44.7 (51) and 41.8 (56); the host waited 3-5 ms a frame on the GPU's
timelines in those against under 1 ms.

vk: pool 0x102e800000 (52 MB, its mirror 48 MB) stays in system memory: the mirrors have 1022 MB of 1024
vk:   bound in guest memory, by pool (the GPU reads these over PCIe; ...): 0x7fa4800000 (36 MB, state 1): 592 binds, 36 MB;
vk: host time in GPU resource waits: 7.71 ms a frame (fences 0.04, timelines 7.67, ...)          (a slow visit, 1024)
vk: host time in GPU resource waits: 0.96 ms a frame (fences 0.04, timelines 0.92, ...)          (a fast visit)

Flags and settings

No switch added; one menu row's value changes: the VRAM budget row's 4.8 GB step (and so the Balanced (8GB) preset) mirrors 1024 -> 2048 MB.

Flag What it is Before this PR After this PR Effect Helps / doesn't help / untested Recommendation
VRAM budget row, 4.8 GB (Balanced (8GB)) the mirrors' budget 1024 MB 2048 MB the game's pools stay in VRAM; the texture cache gets the rest helps: RTX 3060 Ti 8 GB; untested: other 8 GB cards, AMD, Linux on

Testing

Tested: python -I -B tests/run_all.py on Windows: 502 passed, 17 failed, 74 skipped; the same 17 fail on main @ e090cc48
(test_appimage_player_build, test_cpm_discovery, test_cpp_preflight, test_crash_dialog, test_env_on, test_gpu_hang_watch,
test_lift_cleanup_error, test_linux_preflight, test_make_game_cache, test_make_game_prepare, test_missing_nup, test_oot_state_tap,
test_readback_late, test_tested_configurations (a Windows line-ending sub-test), test_vk_pgo, test_vram_budget_row, test_walk_key). tests/test_vram_budget_row.py fails on main already (its fixture: open PR #622); with #622's fix and this PR it
passes. In game: the runs above, on Windows 11, RTX 3060 Ti.

Not tested: other 8 GB cards (RTX 3070, 4060, RX 6600/7600), Linux, a 6 GB card that picks the 4.8 GB step on the row itself.

Must be tested:

  • Windows or Linux, another 8 GB card, AMD if possible: Balanced (8GB), a few minutes through Hyrule Field and the Market, expecting
    no bound in guest memory lines and VRAM: used under allowed (by hand, or Test Farm: @Beanstalk an 8 GB AMD card, the
    log's mirrors and VRAM lines in Hyrule Field)

Risks

What could break: one VRAM: line of each confirmation run (of 36 and 41) was over what the driver allows (7311 of 6571 MB,
6856 of 6560), at an area change, as one line of an rc.4 run at 2048 by the switch was and as the 1024 runs were more often
(6929/6744, 7249/6747). VRAM over what the driver allows on an 8 GB card with more in VRAM than here (a second monitor at 4K, DLSS
or frame generation on), which would page textures over PCIe instead; the texture cache shrinks first, so it should not.

Turning it off: RX_VK_MIRROR_MB=1024, or the VRAM budget row's 3.6 GB step; reverting the commit.

Compatibility: Nothing changes in saves or caches; a player on Balanced gets the larger budget at the next start.

Issues

See #130 and #668: 8 GB cards (RX 6600, RTX 5050) lost the device or hung at the driver's VRAM limit. Here VRAM went down with
2048 (no longer over what the driver allows), but this has to be checked on an 8 GB AMD card before merge (Must be tested).
See #585: the sparse mirrors' cost on a 6 GB AMD card, the same budget from the other side.

Checklist

Everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description) of the status line's type.
  • Why gives the reason plainly and links the issues that fit (the tracker searched).
  • Measurements has a verdict, or one line saying why there is nothing to measure.
  • Testing names what was tested, what wasn't, and what must still be tested, where and how.
  • Rebased on current main.
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named).
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

When it applies

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • A file in docs/tested/ for each new measured run (format in docs/tested-configurations.md).
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Docs updated.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows built and run; Linux not built here: the change is one constant in a table)

🤖 Generated with Claude Code

**Type:** perf · **Risk:** low · **Tested on:** Windows 11, RTX 3060 Ti 8 GB · **Needs:** another 8 GB card (AMD or NVIDIA), Linux ## Why On 8 GB cards the game's memory pools run out of room in VRAM a few minutes into play, and the GPU then reads the new ones over PCIe every frame: the frame rate drops and swings from one visit of an area to the next (Kokiri Forest 36 or 59 fps with the same build). The Balanced (8GB) preset, which every 8 GB card gets, gives the mirrors 1024 MB: less than the 6 GB step's 1536 and half of what Auto gives an 8 GB card. The 6 GB step was raised for the same reason (perf/low-vram-mirror-budget, the RTX 3060 Laptop rows of docs/tested-configurations.md); the 8 GB step was left at 1024. See #130, #668. ## What changed The 8 GB step of the VRAM budget row (4.8 GB, the Balanced (8GB) preset's) gives the mirrors 2048 MB, what Auto gives an 8 GB card (a quarter, `mirror_budget.h` `auto_bytes`), in line with the 6 GB step's 1536. - vk: `kVramMirrorMb[3]` in `gpu/vk/vk_menu.cpp`, 1024 -> 2048, with the measurement beside it. - tests: `tests/test_vram_budget_row.py`'s expected mirrors for Balanced and for the row's 4.8 GB step. ## Measurements **Verdict:** +22% average fps (median of runs 38.5 -> 45.7), 1% lows +26%, no pool read over PCIe, VRAM under what the driver allows (it went over it at 1024). Hardware: Windows 11 Home 10.0.26300, RTX 3060 Ti 8 GB (driver 32.0.16.2114), i7-12700F, 64 GB Scene: Kokiri Forest, Hyrule Field, Castle Town Market (child), teleported in turn; 1920x1080 output and render (Upscaler "Game's own", 100%), frame generation off, Quality preset Auto (this PC) = Balanced (8GB), VRAM budget 4.8 GB Method: scripted through the control bridge: per area 10 s settle, 30 s standing, 30 s turning the camera; a warm-up pass, then a recorded pass; `RX_VK_FRAME_LOG` frame times; 3 interleaved runs per side (1024, 1536, 2048 in turn); the average of the six segments per run, and the median of the runs How to reproduce: any save; the bench script drives `scripts/longshot_ctl.py` (`teleport 0/1/3`, `stick R 1 0`) Baseline: main @ 1be60eae built on this PC with its own hot list (`work/hot_funcs.txt`, both columns alike); the After column is the same build with `RX_VK_MIRROR_MB=2048`, which is what this PR's table value gives. Confirmed with this PR's renderer @ 53a00824 in a v3.0.0-rc.4 game folder and no mirror switch (`RX_VK_WB_MAX_KB=1024` on, as in that folder): 41.7 and 48.3 fps, 1% lows 20.5 and 26.5, 0 `bound in guest memory` lines, the mirrors past 1024 MB (1218 MB in the Market) | | Before: main @ 1be60eae | After, RX_VK_MIRROR_MB=2048: main @ 1be60eae | |---|---|---| | fps, runs | 38.5, 32.7, 40.0 | 48.2, 45.7, 42.0 | | fps, median | 38.5 | 45.7 | | 1% low, mean of runs | 16.4 | 20.7 | | Kokiri / Hyrule Field / Market | 43.3 / 38.6 / 29.3 | 51.6 / 48.6 / 35.7 | | "bound in guest memory" (GPU reads over PCIe) lines | 428, 350, 334 | 0, 0, 0 | | VRAM max, MB used of allowed | 6929/6744, 7249/6747, 6363/6656 | 6543/6700, 6529/6762, 6383/6575 | 1536 MB gave the same (45.7 fps mean, 0 PCIe lines): 2048 is chosen as Auto's quarter, the rule the 6 GB step follows. Across ~180 area visits of the day's runs at 1024: visits where every pool had its mirror ran Kokiri 58.6 fps (9 visits) and Hyrule Field 58.5 (4); visits with a pool over PCIe 44.7 (51) and 41.8 (56); the host waited 3-5 ms a frame on the GPU's timelines in those against under 1 ms. ``` vk: pool 0x102e800000 (52 MB, its mirror 48 MB) stays in system memory: the mirrors have 1022 MB of 1024 vk: bound in guest memory, by pool (the GPU reads these over PCIe; ...): 0x7fa4800000 (36 MB, state 1): 592 binds, 36 MB; vk: host time in GPU resource waits: 7.71 ms a frame (fences 0.04, timelines 7.67, ...) (a slow visit, 1024) vk: host time in GPU resource waits: 0.96 ms a frame (fences 0.04, timelines 0.92, ...) (a fast visit) ``` ### Flags and settings No switch added; one menu row's value changes: the VRAM budget row's 4.8 GB step (and so the Balanced (8GB) preset) mirrors 1024 -> 2048 MB. | Flag | What it is | Before this PR | After this PR | Effect | Helps / doesn't help / untested | Recommendation | |---|---|---|---|---|---|---| | VRAM budget row, 4.8 GB (Balanced (8GB)) | the mirrors' budget | 1024 MB | 2048 MB | the game's pools stay in VRAM; the texture cache gets the rest | helps: RTX 3060 Ti 8 GB; untested: other 8 GB cards, AMD, Linux | on | ## Testing **Tested:** `python -I -B tests/run_all.py` on Windows: 502 passed, 17 failed, 74 skipped; the same 17 fail on main @ e090cc48 (test_appimage_player_build, test_cpm_discovery, test_cpp_preflight, test_crash_dialog, test_env_on, test_gpu_hang_watch, test_lift_cleanup_error, test_linux_preflight, test_make_game_cache, test_make_game_prepare, test_missing_nup, test_oot_state_tap, test_readback_late, test_tested_configurations (a Windows line-ending sub-test), test_vk_pgo, test_vram_budget_row, test_walk_key). `tests/test_vram_budget_row.py` fails on main already (its fixture: open PR #622); with #622's fix and this PR it passes. In game: the runs above, on Windows 11, RTX 3060 Ti. **Not tested:** other 8 GB cards (RTX 3070, 4060, RX 6600/7600), Linux, a 6 GB card that picks the 4.8 GB step on the row itself. **Must be tested:** - Windows or Linux, another 8 GB card, AMD if possible: Balanced (8GB), a few minutes through Hyrule Field and the Market, expecting no `bound in guest memory` lines and `VRAM:` used under allowed (by hand, or Test Farm: @Beanstalk an 8 GB AMD card, the log's mirrors and VRAM lines in Hyrule Field) ## Risks **What could break:** one `VRAM:` line of each confirmation run (of 36 and 41) was over what the driver allows (7311 of 6571 MB, 6856 of 6560), at an area change, as one line of an rc.4 run at 2048 by the switch was and as the 1024 runs were more often (6929/6744, 7249/6747). VRAM over what the driver allows on an 8 GB card with more in VRAM than here (a second monitor at 4K, DLSS or frame generation on), which would page textures over PCIe instead; the texture cache shrinks first, so it should not. **Turning it off:** `RX_VK_MIRROR_MB=1024`, or the VRAM budget row's 3.6 GB step; reverting the commit. **Compatibility:** Nothing changes in saves or caches; a player on Balanced gets the larger budget at the next start. ## Issues See #130 and #668: 8 GB cards (RX 6600, RTX 5050) lost the device or hung at the driver's VRAM limit. Here VRAM went down with 2048 (no longer over what the driver allows), but this has to be checked on an 8 GB AMD card before merge (Must be tested). See #585: the sparse mirrors' cost on a 6 GB AMD card, the same budget from the other side. ## Checklist ### Everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`) of the status line's type. - [x] Why gives the reason plainly and links the issues that fit (the tracker searched). - [x] Measurements has a verdict, or one line saying why there is nothing to measure. - [x] Testing names what was tested, what wasn't, and what must still be tested, where and how. - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### When it applies - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] A file in `docs/tested/` for each new measured run (format in `docs/tested-configurations.md`). - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Docs updated. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows built and run; Linux not built here: the change is one constant in a table) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The Balanced (8GB) preset's step, 4.8 GB, gave the mirrors 1024 MB, less than the 6 GB step's 1536 and half of what
Auto gives an 8 GB card (a quarter). The mirrors filled within minutes of play and each new pool was read by the GPU
over PCIe: on an RTX 3060 Ti 8 GB at native 1080p, 37.1 -> 45.3 fps over three interleaved runs per side.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
docs(tested): the 8 GB step's mirrors at 1024 and 2048 MB, and this branch's renderer, RTX 3060 Ti, Windows 11
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 15s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request) Has been cancelled
b215717d39
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
First-time contributor

Description: Measurements columns name their commits; the menu row listed under Flags; the docs and build boxes added (Linux not built here).

Description: Measurements columns name their commits; the menu row listed under Flags; the docs and build boxes added (Linux not built here).
Author
First-time contributor

Description: the Docs box in the template's own words.

Description: the Docs box in the template's own words.
Author
First-time contributor

Closing: #735 (merged in 511e9b03) gives 8 GB cards the same 2 GB of mirrors this PR asked for, and removes the VRAM budget row whose table this PR changed, so there is nothing left to merge here. This PR's measurements are kept in it and cited by #735.

Closing: #735 (merged in 511e9b03) gives 8 GB cards the same 2 GB of mirrors this PR asked for, and removes the VRAM budget row whose table this PR changed, so there is nothing left to merge here. This PR's measurements are kept in it and cited by #735.
Zapiltar closed this pull request 2026-11-15 08:06:44 +00:00
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 15s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Guide screenshots / Guide images and local UI source review (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!724
No description provided.