Repository navigation
perf(vk): with frame generation, the replay no longer waits behind each present, and a capture waits for less of the frame before - #2633
Conversation
… queue's lock let go NVIDIA's driver on Linux waits inside vkQueuePresentKHR until the frame's copy into the window is done on the GPU. A present made on the replay's queue held dev.present_mu through that wait, and every submit of the replay waited behind it. With frame interpolation the display thread presents four times a game frame: the game's presentation thread was in submit_recording's wait for the lock at 17 % of all instants, 3.8 ms a frame (Hyrule Field, DLSS + interpolation 4x + Reflex, RTX 3090). present_out now waits for the copy's fence first, with the lock let go, and takes it again for the present. This covers frame generation's presents and the game's own. The present goes out when the driver would have let it: it waited for the same copy. On by default only with NVIDIA's driver on Linux, where the wait was seen; RX_VK_PRESENT_COPY_WAIT=0 / 1 over it. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
A capture finds pages the CPU wrote that work still on the GPU writes back (OoT's exposure meter page) and waits for them before the replay uses it. The wait was for the page's submission value, which is done only with that submission's last part. With frame generation on the game's threads run ahead of the GPU, so the wait happens every frame (97 of 600 takes, 2.4 ms each, Hyrule Field with DLSS + interpolation 4x) and at times runs for tens of ms up to its 250 ms limit, when the submission waited for is stopped at an event that the waiting game thread's own work would let on. A page written back from a mirror is in guest memory once the part that copies it back is done, and the page table keeps that part (wb_parts, as the readbacks use it since NotRexed#2602). So a page whose part is done is not late at all, and the others wait for the newest of their parts. A late page written in place keeps the wait for the submission's value, for the whole capture. RX_VK_CAPTURE_PART=0 restores the value always. The 600-take log line now counts the takes that waited for a whole submission and the pages a part had already written back; RX_VK_LOG_CAPTURE_LATE=1 logs each late wait. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Tested in the game on NVIDIA Linux with frame generation, A/B against the same build with Setup: RTX 4070, NVIDIA 615.71.09, Ryzen 7 5800X3D, Ubuntu 26.04.1 (kernel 7.0), GNOME Wayland, 2560x1440 at 144 Hz. CI AppImage Log lines asked for: with the PR, 2x, DLSS Frame Gen making every frame, uncapped, 60 s standing still, same spot and facing. Run order: PR on, PR off, PR on.
The first run was about 10% slower in both places, and the PR-on repeat matched PR off, so I read that as warm-up. Standing still, the fps is the same with and without the PR. Change 2 took whole-submission waits to 0 and removed almost all late waits in Hyrule Field. In Kokiri the count and the time per wait stayed about the same, which matches your note about the exposure page. Free play, 2x uncapped (about 19 min PR off, about 14 min PR on; Kokiri, Hyrule Field, load zones):
The routes weren't identical, but every measure leaned slightly toward the PR. The PR-on run's one Also seen: about one No 4x, cap 144: the game held 36.0 fps with and without the PR, with no Not tested: frame pacing off, V-Sync On, Windows, AMD/Intel. |
|
Timing result with frame generation on: no gain in the first pair, so this stays a draft. One pair, standing in Hyrule Field, RTX 3090 + Ryzen 9 7900X, Linux (NVIDIA, Wayland), 2560x1440 window, DLSS, frame generation 4x, Reflex on, cap 120. DLSS, 4x interpolation and Reflex were active in both logs:
|
|
Steam Deck data for part 2 (a capture's late pages wait for the part that writes them back). It probably doesn't change much on GPUs without mirrors. Setup: Steam Deck OLED (Galileo, APU 0932, RADV, Game Mode, handheld profile, docked), main
So on mirrorless iGPUs, the late-page wait isn't where the Deck's frame time goes. I won't open a PR for the deferral. Your part-based wait looks right for the mirrored case it targets. |
…he capture's late-page wait Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Tested in the game on Linux + NVIDIA with frame interpolation on: no change in frame rate here. Hardware: RTX 3060 12 GB, NVIDIA 615.71.09, Manjaro (kernel 6.12), Core Ultra 7 265KF (8 P-cores + 12 E-cores), Wayland. Built on main
(replay columns: medians of the last 20
|
…he capture's late-page wait Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Draft, not yet run in the game. With frame generation on, the game's replay spends several milliseconds of every frame waiting on things that are not its own work: a lock the display thread holds while the driver waits inside each present, and a wait for the whole of the frame before's GPU work. This removes the first and narrows the second.
Measured on
mainwith DLSS, frame interpolation 4x and NVIDIA Reflex on, cap 120, Hyrule Field (RTX 3090, Ryzen 9 7900X, Linux, NVIDIA 620.70.06): the replay'ssubmitis 11.5 ms a frame against 6.8 ms with default options in the same place. 3.8 ms of the difference is the lock, 2.3 ms the capture's wait.1. A present on the replay's queue waits for its copy with the queue's lock let go
143b5e54vkQueuePresentKHR, on the CPU, until the frame's copy into the window is done on the GPU.dev.present_muthrough that wait. Every submit of the replay takes the same lock.submit_recording's wait for the lock at 17.2 % of all instants, while the display thread was insidepresent_out, in the driver's wait, at 34.5 %.present_outwaits for the copy's fence first, with the lock let go, and takes it again for the present itself. The present goes out when the driver would have let it: it waited for the same copy.RX_VK_PRESENT_COPY_WAIT=0/=1. On by default only with NVIDIA's driver on Linux, where the wait was seen. Off on Windows, where a note in the code says the same idea was tried and was worse, and off for other Linux drivers, which were not seen to wait for the copy in the present.2. A capture's late pages wait for the part that writes them back
d533cd18RX_VK_CAPTURE_WAIT=0has none.RX_VK_CAPTURE_PART=0restores the old wait.RX_VK_LOG_CAPTURE_LATE=1logs each late wait.What change 2 does and does not do (measured on the #2622 stack, which makes the game run ahead in the same way; default options, Hyrule Field and Kokiri Forest,
RX_VK_LOG_CAPTURE_LATE=1):Tests
tests/test_present_copy_wait.py: both callers givepresent_outtheir copy's fence and take it away; a failed submit gives none; the lock is let go for the wait and taken again before the present; the wait has a limit and sees a lost device; the default per platform and vendor; the presenter thread's hand-off is unchanged.tests/test_capture_part.py: the choice of a wait, cut from the source and run (a page whose part is done; the newest part; a page in place; a part not known; the switch), and the order incapture_makeandtake_capture.tests/test_present_semaphores.pyupdated for the changed function.tests/test_present_device_loss.pynow covers the new fence wait (ten sites).python -I -B tests/run_all.py): every failure it has is also a failure onmainitself at7297d93d, checked by running each one there:test_readback_part,test_dlss_checks,test_framegen_preset,test_hdr_encode,test_audio_biquad,test_audio_aux,test_mods_size_table,test_rumble_menu,test_mouse_native,test_linux_docker_packages,test_wayland_libdecor_hint,test_display_startup_failure,test_texel_buffer_ownership, and three known on this PC (test_bake_portability,test_builder_log_read_only,test_env_on).hookshot_vk.sobuilds onmainata016b7a6with both commits and passes the ABI check.Not yet tested in the game
Nothing here has been run with frame generation yet. For testers with frame generation on (any multiplier, DLSS-G or the renderer's own), NVIDIA on Linux first:
RX_VK_PRESENT_COPY_WAIT=0 RX_VK_CAPTURE_PART=0, same place, same settings.slow submitlines (how many, and how many saymemory sync).vk: presents on the replay's queue ...andvk: a capture taken (ms): ...(the late pages' numbers).RX_VK_PRESENT_COPY_WAIT=1there would say whether it helps.