OoT exposure flashes: CPU reads of GPU results wait for the work that writes them #296

Merged
evilmfkr merged 2 commits from pr/exposure-flicker into main 2026-11-07 22:51:15 +00:00
evilmfkr commented 2026-11-07 19:30:38 +00:00 (Migrated from github.com)

Fixes the white flashes / fog pulsing at Kokiri Forest (several times a second, while standing still).

What it was. Not the fog: OoT's auto-exposure hunting in 0.2 EV steps (~15% brightness each). The game meters the
scene on the GPU: a pass adds the frame's brightness into a small buffer, and the CPU reads it after an invalidate and
stores 0 back (f_80357060). On the console that memory is coherent. Here the GPU's result reaches guest memory only with
the write-back at the end of its submission, and the game read it as soon as it had handed the work over: one frame it
read 0, then the old sum came back over the CPU's 0 (a whole-page sync of the captured page) and the next frame added to
it (2x). The exposure logic saw 0 / 1x / 2x and kept correcting.

The fix. The pages each submission writes into guest memory (write-backs from a mirror, small bindings written in
place) are noted with its timeline value; invalidate waits (replay caught up, then that value) before the CPU reads a
range a GPU write ever reached. RX_VK_NO_READBACK_WAIT=1 restores the old behaviour.

Measured at the Kokiri rock, 300 screen captures in ~4.5 s at normal speed (GDI, so the game isn't slowed): 17-84
brightness jumps before, 0-1 after; ~46 fps both ways (RTX 4060 Ti). Confirmed in play: the flashes are gone.

Diagnostics added: RX_VK_LOG_READBACK=<present> (what the CPU is about to read at each invalidate),
RX_VK_LOG_READBACK_WAITS=1, RX_VK_WATCH_CPU=<present>:<addr>[,...] (CPU writes to those pages with the writer's stack;
the host page watch now also logs the host pc, which hookshot.map turns into the guest function),
RX_VK_READBACK_NO_CATCHUP=1 (A/B).

Also adds EvilBoyce (Discord: evilmfkr) to the README credits.

🤖 Generated with Claude Code

Fixes the white flashes / fog pulsing at Kokiri Forest (several times a second, while standing still). **What it was.** Not the fog: OoT's auto-exposure hunting in 0.2 EV steps (~15% brightness each). The game meters the scene on the GPU: a pass adds the frame's brightness into a small buffer, and the CPU reads it after an invalidate and stores 0 back (f_80357060). On the console that memory is coherent. Here the GPU's result reaches guest memory only with the write-back at the end of its submission, and the game read it as soon as it had handed the work over: one frame it read 0, then the old sum came back over the CPU's 0 (a whole-page sync of the captured page) and the next frame added to it (2x). The exposure logic saw 0 / 1x / 2x and kept correcting. **The fix.** The pages each submission writes into guest memory (write-backs from a mirror, small bindings written in place) are noted with its timeline value; `invalidate` waits (replay caught up, then that value) before the CPU reads a range a GPU write ever reached. `RX_VK_NO_READBACK_WAIT=1` restores the old behaviour. **Measured** at the Kokiri rock, 300 screen captures in ~4.5 s at normal speed (GDI, so the game isn't slowed): 17-84 brightness jumps before, 0-1 after; ~46 fps both ways (RTX 4060 Ti). Confirmed in play: the flashes are gone. **Diagnostics added:** `RX_VK_LOG_READBACK=<present>` (what the CPU is about to read at each invalidate), `RX_VK_LOG_READBACK_WAITS=1`, `RX_VK_WATCH_CPU=<present>:<addr>[,...]` (CPU writes to those pages with the writer's stack; the host page watch now also logs the host pc, which hookshot.map turns into the guest function), `RX_VK_READBACK_NO_CATCHUP=1` (A/B). Also adds EvilBoyce (Discord: evilmfkr) to the README credits. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
shayderrr commented 2026-11-07 22:51:11 +00:00 (Migrated from github.com)

Thanks

Thanks
Commenting is not possible because the repository is archived.
No description provided.