An Honest Readback
Heavy scenes now export reliably on NVIDIA hardware, and a failed frame capture says so out loud instead of handing you an empty image. The GPU readback path stops returning nothing and calling it success.

Export a frame of a thousand-light scene with a long warmup on an NVIDIA card and, until this release, the app would reliably fall over somewhere past warmup frame 250. Not a glitch, not sometimes: three runs, three crashes, same place. The kind of reproducibility you wish your good features had.
A queue with no drain
The warmup loop renders a few hundred frames before the capture so oscillators, smoothers and particle systems arrive at the captured moment with their history intact. The old loop submitted those frames to the GPU as fast as the CPU could issue them and never once stopped to let the driver retire finished work. Most drivers quietly absorb this. NVIDIA’s, faced with six hundred heavy frames of backlog, eventually declined, and the capture frame’s readback blew its budget against a queue that was still digesting.
The loop now drains as it goes: a cheap poll every frame, a full drain every thirty-two. The backlog stays bounded no matter how heavy the scene is, and the thousand-light export finishes on the same card that used to abort it. Three runs, three identical images, which is the boring outcome we were after.
Returning nothing and calling it success
Underneath that crash sat a quieter design flaw. The blocking readback, the function whose whole job is “give me the rendered pixels”, reported failure by returning an empty buffer. A timeout, a lost device, a mapping failure: all of them came back as zero bytes and a log line, and every caller was trusted to remember the check. Callers, being callers, did not always remember, and an empty “image” would float downstream until something less polite noticed.
Failures are now errors, in the type system, where they cannot be ignored by accident. The export path refuses to write a file from a failed readback rather than leaving you a black PNG to discover in the morning. And the display cache now measures every snapshot before accepting it: a buffer that is not exactly width times height times four bytes is rejected at the door, logged with what arrived versus what was expected, while the previous good snapshot keeps rendering. A truncated readback can no longer reach the compositor and panic it from the inside.
One small bonus for log readers: the line that proudly announced each synced texture as “4 bytes” was reporting bytes per pixel, not the buffer size. It now reports the actual number, which makes the log paste worth pasting.
What it buys you
Long-warmup exports of heavy scenes are dependable on NVIDIA hardware, the failure modes that remain announce themselves in plain language instead of producing empty files, and the live display can shrug off a bad readback without taking the frame down with it. It continues the run started by the windowed display fix: the boring, structural honesty that live tools owe their operators.