Expand description
VBlank-kicked presentation: a one-frame-deep queue between the CPU and the
GPU. Built with the present-queue feature.
A game publishes each finished frame’s DMA chain together with the GP1(05h) word that shows the frame before it, and returns at once. psx-rt’s VBlank handler kicks the chain on the first edge where the previous chain’s closing GP0(1Fh) has run (GPUSTAT bit 24) and DMA channel 2 is idle: it flips the display to the finished frame, acknowledges the flag with GP1(02h), and starts the new walk. A flip therefore lands only on a blank edge and only on a fully drawn frame, and the CPU builds the next frame while the GPU draws this one. The CPU waits only when it is a whole frame ahead, and before reusing memory a walk may still read.
Ported from quake-psx’s platform.rs (3ca915c, 16e27a9: E1M1 chain bench
+25.5%, monster route +46.1% over its blocking present) so every game
shares one queue.
§Protocol
- Call
startonce, aftercrate::interrupts::install_vblank_counter, with nothing queued and channel 2 idle. It raises the draw-done flag so the first published frame finds it set. - Every published chain must end on GP0(1Fh) (
psx_gpu::DRAW_DONE_NODE,OrderingTable::end_with_draw_done), and must carry its own draw area, offset and clear as leading packets: the handler writes only GP1.psx_io::gpu::start_recording_rawrecords those from the usual immediate calls. - Before
publish_raw, callwait_slot_empty. Before rebuilding memory that the frame before the last published one used, callwait_arena_free. - Direct command or display-control writes and GPU DMA starts are safe
at any time:
publish_rawarms psx-io’s direct-access guard, so the first such access after it runswait_idle. Code that only records keeps the overlap.
Keep interrupt source 1 (GPU) masked in I_MASK: GP0(1Fh) raises it and
the handler, which owns VBlank only, would acknowledge it as a stray. The handler returns past a GTE
command an edge interrupted (8055e87f6), so publishing from GTE-heavy code
is safe.
§With psx_gpu::frame
A frame kicked from the CPU (psx_gpu::frame::OtFrame::submit,
FrameStorage::draw_async, or any other GPU DMA start) first runs the
guard, so it starts only once every published frame has been kicked and
has finished drawing: the channel is never kicked twice, and no queued
walk reads memory the CPU path is about to reuse. The reverse also holds:
the handler never kicks while a CPU-kicked walk runs, since it needs
channel 2 idle. A queued flip waits on GPUSTAT bit 24, which only chains
ending in GP0(1Fh) raise, so a CPU-kicked chain should end the same way
when a published frame follows it.
Structs§
- Present
Stats - Counters for telemetry and A/B reports.
Constants§
- STALL_
VBLANKS - Edges a published frame may wait before the CPU treats the chain ahead of it as stalled (its walk wedged, or it lost its GP0(1Fh)).
Functions§
- is_
slot_ full - True while a published chain is waiting for the handler to kick it.
- publish_
raw ⚠ - Hand one chain, and the GP1(05h) word that shows the frame before it, to
the VBlank handler. Pass
display0 when nothing is on screen yet. - start
- Register the direct-access guard and raise the draw-done flag once, so the first published frame’s edge finds it set. Nothing may be queued and channel 2 must be idle.
- stats
- Kick, skip and recovery counts since boot.
- wait_
arena_ free - Wait until memory used by the frame before the most recently published
one is no longer walked. Once the published frame has been kicked (slot
empty), the handler saw the older frame’s GP0(1Fh), so its walk had
ended; while it is still queued, the only walk that can be running is the
older frame’s. Bounded like
wait_slot_empty. - wait_
idle - Wait until the GPU is completely idle: nothing queued, no walk running and
the last chain’s drawing done. The direct-access guard runs this before
the first direct GPU access after a publish. Bounded like
wait_slot_empty; a walk it gives up on is stopped by hand. - wait_
slot_ empty - Block until the handler has kicked the published frame. Spins only when the CPU is a whole frame ahead of presentation. Not inlined, so a profile can tell the spin from work.