e9d8f2bc04
The Linux raw-Vulkan HEVC backend blocked on two GPU fences per frame, so CPU readback and the next capture could not overlap the GPU encode. Refactor into a small ring of per-in-flight-frame resources (own command buffers, CSC descriptor set + Y/UV/NV12 scratch, bitstream buffer, feedback query and sync objects) so submit() records into a free slot and returns without waiting, and poll() reads back the oldest slot once its fence signals. The pump's non-blocking poll then overlaps a frame's CSC+encode with the next capture — the throughput win — with no capturer/pump change (VAAPI untouched). - New `Frame` struct + `make_frame`; encoder holds `frames`/`ring`/`in_flight`. - `record_submit` (non-blocking) + `read_slot` (fence-gated readback) replace the synchronous `encode_frame`; `enqueue` applies backpressure by draining the oldest slot when the ring is full. - DPB self-barrier between consecutive encodes: orders frame N's reconstruct write before N+1's reference read now that they can be in flight together. - flush() drains all in-flight slots in order; reset() waits idle + discards. - Ring depth defaults to 3, overridable via PUNKTFUNK_VULKAN_INFLIGHT (2..=6). - Smoke test drains via poll-loop + flush (async breaks one-AU-per-submit). Headless-validated on real RADV 780M: cargo check (feature on/off) + clippy -D warnings + rustfmt clean; smoke test at ring depth 2/3/6 all ffmpeg-decode clean (I P P P P P) and drop-heal (I P P P P) with 0 errors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>