Skip to content

vk: capture: pages still being written back are copied again by the replay - #936

Merged
NotRexed merged 1 commit into
NotRexed:mainfrom
azlekayn:perf/capture-late-copy
Nov 9, 2026
Merged

NotRexed merged 1 commit into
NotRexed:mainfrom
azlekayn:perf/capture-late-copy

Conversation

@azlekayn

@azlekayn azlekayn commented Nov 9, 2026 •

Copy link
Copy Markdown

ea78039 made a capture wait for the GPU when it copies a page that a running submission still writes back, which fixed the exposure flashes. That wait runs on the game's main thread, about 8% of its time at a busy scene.

With this change the capture no longer waits. It records those pages, and the replay thread, which is idle about 45% of the time, waits for the submission and copies just those pages again before it uses the capture. Typically about 130 pages in a capture, and the replay waits 1.3-3 ms for them.

RX_VK_CAPTURE_WAIT=1 restores the wait on the game's thread, and =0 still removes it.

Measurements

Ryzen 7 7800X3D, RX 7800 XT, RADV, Fedora 44, 2560x1440, Kokiri Forest at the same ~2150-draw spot, runs alternating between modes (RX_VK_CAPTURE_THREADS=4 in all of them, see #876):

RX_VK_CAPTURE_WAIT fps per run mean big flashes
1 (current behaviour) 43.3, 43.5, 42.5, 43.0, 43.9, 41.8, 45.1 43.2 0 in ~32,000 frames
2 (this PR) 46.8, 46.6, 46.8, 48.0, 47.3, 44.8, 45.9, 47.8 46.8 1 in ~41,000 frames
0 (no wait, 1 run) 47.7 575 a minute

A big flash is a frame where at least 20 of 144 screen blocks jump and return. The =0 row shows this scene does expose the original bug. Smaller artifacts would not be counted.

Known risk: please review this part

The late copy reads guest memory after the game's thread has moved on, so if the game writes to one of those pages between the capture and the late copy, the replay sees that newer data, a page from slightly later than the submit. The wait on the game's thread made that impossible. I saw one flash across about 41,000 frames, and I don't know whether this race caused it.

If you'd rather not change the default, flipping it to 1 keeps this as an opt-in.

What was and wasn't tested

🤖 Generated with Claude Code

…eplay

The wait for the write-back held the game's thread. The capture now goes on without it and the replay,
which has time to spare, waits and copies those pages again before it uses the capture.
RX_VK_CAPTURE_WAIT=1: the wait on the game's thread as before, 0: no wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@azlekayn

azlekayn commented Nov 9, 2026

Copy link
Copy Markdown
Author

Re-measured on current main (3b4347d, which has #689), with this PR and #876 merged on top. Both merge cleanly.

RX 7800 XT, RADV (Mesa 26.2.6), Ryzen 7 7800X3D, Linux. Same ~2150-draw Kokiri Forest balcony view, runs alternated between builds, default settings. Only the renderer .so differs. Frames were presented through a headless weston on the same GPU; a check run with this PR's mode gave the same fps as the real display (47.0 vs 46.8).

build fps per run big flashes
main 42.5, 42.5, 40.7, 42.3 0
main + #876 + #936 46.2, 47.2, 47.1 0
main + #876 + #936 + #896 + #948 + #989 48.8, 48.5, 49.0, 49.8, 48.0, 48.0, 48.4 0

Picture brightness matched across all builds in the screenshots (mean 80-82 of 255), so 0 flashes isn't hiding a broken image. I didn't measure #876 and #936 separately on this base, and I didn't separate #896, #948 and #989 from each other. This is one scene on one GPU. The race described in the PR body (the game writing a page before the late copy) still applies.

@NotRexed
NotRexed merged commit a542714 into NotRexed:main Nov 9, 2026
9 checks passed
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