Skip to content

feat: record fast3d capture sequences from renderer reset - #37

Merged
dcvz merged 2 commits into
mainfrom
helix-capture-sequence
Sep 11, 2026
Merged

dcvz merged 2 commits into
mainfrom
helix-capture-sequence

Conversation

@dcvz

@dcvz dcvz commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Supersedes #33, which no longer applies: main has since taken fast3d's fallible memory API, and the capture hook now has to record a sequence rather than a directory of single frames. This is #33's behaviour ported onto main deliberately rather than rebased.

The per-frame mode is unchanged in spirit — FAST3D_CAPTURE_DIR plus FAST3D_CAPTURE_FRAMES writes selected renderer serials as frame-%06d.f3dcap. Two fixes while porting: selection is now one-based so it matches the filenames it produces (#33's selection 120 wrote frame-000121.f3dcap), and an empty element in the serial list no longer aborts capture entirely. That last one is easy to hit, because BSD seq -s, emits a trailing comma and the old behaviour was to log once and then run the game as if capture had never been asked for.

New is FAST3D_CAPTURE_SEQUENCE, with FAST3D_CAPTURE_WARMUP_FRAMES and FAST3D_CAPTURE_PRESENTATIONS. It wraps the renderer in fast3d::capture::CaptureSequence from the first graphics task, so the recording starts at a renderer reset and retains every serial through the endpoint with no gaps, which is what fast3d's container requires — it rejects a cropped or intermittent recording rather than renumbering it. Recording stops and writes at the largest requested presentation. Renderer resizes are deferred while a sequence is active and applied afterwards.

Output is published atomically: bytes are synced to <output>.<pid>-<id>.partial and hard-linked into place, so an existing recording is never overwritten and a .partial on its own is never mistaken for a finished one. SIGINT, SIGTERM and SIGHUP save the completed prefix; kill -9 cannot. If the signal handler can't be installed the run logs a warning and carries on, since the endpoint save is how a completed run finishes anyway — worth noting because launching the game as a background job leaves SIGINT ignored, and ctrlc refuses to register over any non-default disposition.

With no capture variable set, nothing changes: no reset, no depth-policy change, no wrapper, no signal handler.

fast3d is pinned to 509cf9b, which is retrofoundry/fast3d-rs#64 on main.

Used to record three sm64 attract-mode sequences of 1400-1600 frames each and replay them under fast3d's depth-discard controls. The recordings are deterministic across separate game launches and across fast3d builds: the same presentation serials hash identically every time.

@dcvz
dcvz marked this pull request as ready for review September 8, 2026 20:50
@dcvz
dcvz merged commit c56de61 into main Sep 11, 2026
4 checks passed
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.

1 participant