perf(vk): skip write-backs of large GPU-written bindings #1629

Merged
DFN-master merged 1 commit from perf/wb-max into main 2026-11-10 17:03:38 +00:00
DFN-master commented 2026-11-10 11:35:15 +00:00 (Migrated from github.com)

OoT's renderer copies back every GPU-written binding at each submit's memory sync, even the tens of MB of culling lists and per-frame buffers the CPU never reads. On a 10 GB RTX 3080 / i7-11700 at 1080p, Hyrule Field wrote about 66 MB and spent 4.4 ms per submit on the copy, holding the scene at 45-48 fps.

RX_VK_WB_MAX_KB=1024 still copies the small results the CPU does read (the exposure meter and the like) and skips the large write-backs. The same scene runs at 59-60 fps; memory sync falls to about 0.5 ms and the replay from 14-15 ms to 8-10 ms. A 10-minute soak held 60 fps with no growth or crash; a further 300 s run with the compressed program cache also held 59-60 fps. 0 or unset keeps the old behavior.

No visual change: the buffers skipped are write-only from the CPU's point of view (the game never reads them back). Tested in Hyrule Field, the Lost Woods, Lake Hylia and Kakariko.

OoT's renderer copies back every GPU-written binding at each submit's memory sync, even the tens of MB of culling lists and per-frame buffers the CPU never reads. On a 10 GB RTX 3080 / i7-11700 at 1080p, Hyrule Field wrote about 66 MB and spent 4.4 ms per submit on the copy, holding the scene at 45-48 fps. `RX_VK_WB_MAX_KB=1024` still copies the small results the CPU does read (the exposure meter and the like) and skips the large write-backs. The same scene runs at 59-60 fps; memory sync falls to about 0.5 ms and the replay from 14-15 ms to 8-10 ms. A 10-minute soak held 60 fps with no growth or crash; a further 300 s run with the compressed program cache also held 59-60 fps. `0` or unset keeps the old behavior. No visual change: the buffers skipped are write-only from the CPU's point of view (the game never reads them back). Tested in Hyrule Field, the Lost Woods, Lake Hylia and Kakariko.
blushOFF commented 2026-11-10 14:40:48 +00:00 (Migrated from github.com)

Test report: RX_VK_WB_MAX_KB=1024 on an 8 GB card (RTX 3070, driver 610.88, i7-14700KF, Windows 11; v2.0.12 046e37f6 with this PR on top, no hookshot_env.txt, window 5760x2130). Runs alternated, off / on / on / off.

Castle Town Market, Link standing, about 2 900 draws a frame, 6 + 6 runs (with stand-ins for the three damaged dump textures from my comment on #995):

off =1024
mean fps 42.7 (40.5-50.0) 47.2 (38.8-53.1)
GPU time, median of each run 13.4-17.7 ms 12.2-14.2 ms
written back a frame, median of each run 60.8-62.6 MB 9.1-9.3 MB

Kokiri Forest, from a save, 4 + 4 runs: 30 s standing still, then 40 s walking and turning the camera. In the Kokiri runs the binary also held a local switch of mine, off in those runs.

off =1024
median fps while walking, each run 55.5, 46.0, 49.5, 33.6 58.7, 59.3, 54.7, 57.9
median fps standing still, each run 59.0, 50.5, 60.0, 58.8 60.0, 60.0, 60.0, 60.0
flicker frames standing still (frame-log detector) 0, 0, 0, 0 0, 0, 0, 0
flash frames while walking (same detector) 2, 2, 2, 6 4, 4, 4, 2

The walking flash count also picks up sudden camera moves, and the two arms overlap. No device lost in any of these 20 runs.

What I didn't check: I only ran these two places, and I didn't compare the pictures by eye.

**Test report: `RX_VK_WB_MAX_KB=1024` on an 8 GB card** (RTX 3070, driver 610.88, i7-14700KF, Windows 11; v2.0.12 `046e37f6` with this PR on top, no `hookshot_env.txt`, window 5760x2130). Runs alternated, off / on / on / off. **Castle Town Market, Link standing, about 2 900 draws a frame, 6 + 6 runs** (with stand-ins for the three damaged dump textures from my comment on #995): | | off | `=1024` | |---|---|---| | mean fps | 42.7 (40.5-50.0) | 47.2 (38.8-53.1) | | GPU time, median of each run | 13.4-17.7 ms | 12.2-14.2 ms | | written back a frame, median of each run | 60.8-62.6 MB | 9.1-9.3 MB | **Kokiri Forest, from a save, 4 + 4 runs:** 30 s standing still, then 40 s walking and turning the camera. In the Kokiri runs the binary also held a local switch of mine, off in those runs. | | off | `=1024` | |---|---|---| | median fps while walking, each run | 55.5, 46.0, 49.5, 33.6 | 58.7, 59.3, 54.7, 57.9 | | median fps standing still, each run | 59.0, 50.5, 60.0, 58.8 | 60.0, 60.0, 60.0, 60.0 | | flicker frames standing still (frame-log detector) | 0, 0, 0, 0 | 0, 0, 0, 0 | | flash frames while walking (same detector) | 2, 2, 2, 6 | 4, 4, 4, 2 | The walking flash count also picks up sudden camera moves, and the two arms overlap. No device lost in any of these 20 runs. **What I didn't check:** I only ran these two places, and I didn't compare the pictures by eye.
hckrman101 (Migrated from github.com) approved these changes 2026-11-10 16:40:04 +00:00
hckrman101 (Migrated from github.com) left a comment

Looks good. The change is small and opt-in: unset or 0 keeps the old behavior, and when set it only skips queueing the write-back. The rb_hazard_locked call still runs, so tracking is unchanged. It's the same idea as the existing RX_VK_NO_WRITEBACK experiment, but with a size cutoff. The static init is thread-safe, the negative-atoi clamp is fine, and the readme matches the code. Test numbers in the thread look consistent.

Nit: the readme could say that a CPU-read binding above the limit would go stale, so people know why they shouldn't set it too low. No CI is reported on the branch.

Looks good. The change is small and opt-in: unset or 0 keeps the old behavior, and when set it only skips queueing the write-back. The rb_hazard_locked call still runs, so tracking is unchanged. It's the same idea as the existing RX_VK_NO_WRITEBACK experiment, but with a size cutoff. The static init is thread-safe, the negative-atoi clamp is fine, and the readme matches the code. Test numbers in the thread look consistent. Nit: the readme could say that a CPU-read binding above the limit would go stale, so people know why they shouldn't set it too low. No CI is reported on the branch.
Commenting is not possible because the repository is archived.
No description provided.