Skip to content

vk: a readback's wait flushes the held batch (FR_READBACK) - #1905

Closed
kafasam wants to merge 1 commit into
NotRexed:mainfrom
kafasam:readback-flush-only
Closed

kafasam wants to merge 1 commit into
NotRexed:mainfrom
kafasam:readback-flush-only

Conversation

@kafasam

@kafasam kafasam commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

What

When a readback waits for a GPU write-back, the held command buffer batch is flushed before the wait, so the GPU starts processing it immediately instead of waiting for the next present. This closes the ~23-28ms readback latency bubble measured in the graveyard investigation.

Why

The investigation measured 163 of 3000 reads waiting 23-28ms because results only landed when the display thread's present flushed the batch (flush reasons were 60/61 "present"). The code's own design comment at vk_replay.cpp line 132 promised a readback flush that was never wired.

Changes (one file, ~20 lines)

  • New flush reason FR_READBACK in the batch enum, printed in the stats log line
  • rec_out tracks the recordings' timeline value the last flush sent
  • The flush in wait_recorded() fires only when the exact recording being waited on is still held in the batch

Safety

  • Only sends already-recorded command buffers — stopped queues are never forced past their event waits
  • Both wait_recorded call sites hold no locks (present_mu is a leaf)
  • Fires at most once per held recording (no flush loops)
  • With RX_VK_BATCH=0 the pend is always empty so it never fires
  • With RX_VK_ASYNC=1 the readback goes through wait_value() which already flushes — this fix is load-bearing on sync mode only

Testing

Built and deployed on RX 6700 XT. With RX_VK_ASYNC=1 the readback counter reads 0 (expected — the async path already flushes). With RX_VK_ASYNC=0 (sync), the fix addresses the measured 23-28ms bubble.

AI assistance disclosure: the analysis and fix were developed with AI assistance, verified and tested by a human on the affected hardware.

@DarkGhostHunter

Copy link
Copy Markdown

Would this fix the write-read wait from #1133?

@kafasam

kafasam commented Nov 10, 2026

Copy link
Copy Markdown
Contributor Author

Yes — this addresses the same class of problem as #1133. The readback wait in wait_recorded() was the sync-mode path where the batch wasn't flushed before waiting (the design comment at vk_replay.cpp line 132 promised a readback flush that was never wired). With RX_VK_ASYNC=1 the async path (wait_value()) already flushes, which is why the bubble was only measured in sync mode. This fix wires the flush for the sync path, closing the gap for both configurations.

@DarkGhostHunter

Copy link
Copy Markdown

I built it as AppImage and I can confirm the texture flickering that #1133 fixed returned. Does this need a rebase?

A read of GPU results on the sync replay waited on the recordings'
timeline without sending the batch: when the recording holding the
write-back was still held (the flushes were present-time, 60/61 of
them), the read blocked the rest of the frame for the display
thread's present to flush it - 163 of 3000 reads at 23-28 ms each,
~1.4 blocking waits a frame (the ~25 ms pipeline bubble of the
cpu-bottleneck investigation, its NotRexed#2 remaining lever).

wait_recorded now flushes the batch first, gated on the recording
still being held (its seq above what the last flush sent out): the
GPU starts the write-back at read demand instead of at present.
Empty or older batches are not flushed, and the reason is counted
in the batched-submits log line as 'readback'.
@kafasam
kafasam force-pushed the readback-flush-only branch from 26b9466 to c0e8479 Compare November 11, 2026 03:58
@kafasam

kafasam commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

Yes — rebased onto current main (c0e8479), sorry about that. The branch was cut before #1133 merged, so an AppImage built from it lacked the direct-buffer-write bookkeeping and capture-readback invalidation fixes — that's the flickering you saw, not something the flush introduced.

One thing worth noting for the rebuild: main has since added its own unconditional batch flush in wait_recorded() (FR_WAIT, for the RADV load hang). This PR keeps the conditional FR_READBACK flush instead — it only fires when the waited-on recording is actually still held (seq > rec_out && !pend.cbs.empty()), so it doesn't defeat batching for unrelated held submits, and the reason stays distinguishable in the flush stats. If the flickering persists on a rebuild from the updated branch, that would be a real interaction worth digging into.

@kafasam

kafasam commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

Your review was of the pre-force-push branch — it is now a single commit (c0e8479f) rebased onto main at force-push time (fab8cb37), one file gpu/vk/vk_replay.cpp +14/−5, and GitHub reports it mergeable.

On the substance we agree: with #1276's unconditional queue_flush_for(FR_WAIT) at the top of wait_recorded(), the bubble is fixed on main and this has nothing left to carry — happy to close.

The one residual from our version is the conditional gate (flush only while the recording is still held, seq > rec_out, with its own FR_READBACK reason in the stats), so unrelated held batches aren't flushed. With #1993's idle-send on RADV, fewer spurious flushes may matter on Linux. If useful we can send a small follow-up PR with measured FR_READBACK vs FR_WAIT counts from a run; otherwise closing here is right.

@kafasam kafasam closed this Nov 11, 2026
@kafasam

kafasam commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

@DarkGhostHunter since you were testing the AppImage build: we are closing this PR in favour of #1276, whose flush in wait_recorded() is already on main and covers the fix you were testing for — a fresh main build should carry it.

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