Repository navigation
Conversation
Since the idle FX slots run in passthrough (#1007), a 2 s classic wipe became a hard cut on the virtualized-GL macOS CI runner (wipe_between_letterboxed_sources_animates: animated=false, end white=0.00 red=0.76). Entering passthrough renegotiated the slot, which released its GL output pool. Leaving passthrough on the wipe's first buffer then renegotiated again, and decide_allocation sent a serialized ALLOCATION query down into the mixer from the branch's streaming thread. When that query is slow, the branch stalls: the mixer keeps compositing the last unmasked frame on a pad whose alpha the take has already turned on, and the masked frames that follow arrive too late to be shown. The wipe reads as a cut. Enter passthrough without renegotiating, so the pool negotiated at start stays allocated, and leave it without renegotiating when the pool is still there; a take no longer queries allocation. Only a slot whose pool was dropped (caps changed while in passthrough) renegotiates on the way out. Idle slots still render nothing (6 x 1080p30: 0 FX renders/s). Guard: wipe_animates_when_take_slot_allocation_is_slow runs the same letterbox wipes with every ALLOCATION query from a TAKE slot delayed by 2.5 s after start-up. Without the fix it fails with the CI signature (animated=false, end white=0.00 red=0.76); with it, it passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cargo test stops at the first failing test binary, so one flaky test on the macOS runner hid every binary after it. Verifying #1013 took three runs that each stopped on a different unrelated test (keyed_alpha, port_pool, thumbnail_tap_cuda) before the vision mixer FX tests were ever reached. With --no-fail-fast every binary runs and all failures show in one run; the step still fails if any test fails. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
srperens
left a comment
There was a problem hiding this comment.
Verdict: Request changes. This is posted as a COMMENT review because GitHub refuses REQUEST_CHANGES from the account this stage runs under, but the verdict is Request changes. The PR's own ci:macos run contradicts its central claim: at 62f75a2 the macOS runner still fails both wipe tests with the exact signature the PR sets out to fix. #994 offers a different cause for that same signature.
Requested changes
- Rebase onto #994, or wait for it to land, and re-run with
ci:macos. The wipe observer here still pulls from an appsink that drops frames:backend/tests/vision_mixer_fx_test.rs:337—("drop", PV::Bool(true)),. #994 makes this observer lossless, for the sameanimated=false end white=0.00 red=0.76failure on Linux. Until the observer stops dropping frames, a red wipe test on a slow runner cannot tell a stalled take from a missed frame. - Narrow the body once that run is in. If the wipe passes on macOS with #994 alone, then this change is a latency improvement (no ALLOCATION query on the take path), not the fix for the runner, and the Problem section should say so.
Claims
| Claim | Verdict | Evidence |
|---|---|---|
| Fixes the classic wipe on the macOS runner | CONTRADICTED |
Build (macOS), job 112456924613: wipe_between_letterboxed_sources_animates ... FAILED and wipe_animates_when_take_slot_allocation_is_slow ... FAILED, both with classic wipe: animated=false end white=0.00 red=0.76 |
| An injected slow ALLOCATION query turns the wipe into a cut, and the fix removes that | CONFIRMED |
On Linux only: Check (Linux) reported 3 passed in 5.05 s. Leaving passthrough now reconfigures only when no pool exists (citation below). I could not determine whether the guard fails on Linux with the change reverted |
| Leaving passthrough finds the start-up pool still in place | UNVERIFIED |
Slots request passthrough at build time, backend/src/blocks/builtin/vision_mixer/elements.rs:170 — crate::gst::shaders::request_passthrough(&elem, true);. SPECULATIVE (not verified): if basetransform renegotiates in passthrough on its first buffer anyway, the pool is gone before the first take, and this path still queries |
backend/src/gst/shaders/passthrough.rs:109 — if !passthrough && transform.buffer_pool().is_none() {
Diagnosis: the injected-delay reproduction shows that a slow allocation query can produce this symptom. It does not show that this is what the runner hits, and the runner says it is not, or not only. A frame-dropping observer produces the same symptom on a slow host, and that is #994's account. Coverage of the stated bug is therefore unproven.
Radius: LOCAL. One function. Every GPU vision mixer FX slot keeps its GL output pool while idle, which costs memory and no GPU work, as the body says.
Overlaps: #994 changes the same test's observer for the same failure signature, and it may make this PR unnecessary as a CI fix. It should land first. My review there stands at Approve. Also on this test file: #935 and #936 (shared test setup), which are textual only.
Tests & CI: at 62f75a2, Check (Linux) is green and Build (macOS) is red. The other macOS failures in that job (tally_follows_a_cut_on_the_same_frame_with_late_inputs, static_underlays_are_not_repushed_cpu) are in files this diff does not touch. The branch predates #1018, which changed the tally guard. Windows was skipped.
Confidence: MED
|
Runner traces from a diagnostic branch show that this PR's premise is not what fails CI. On 🤖 Generated with Claude Code |
|
Closing: the cause this PR fixes (a slow ALLOCATION query on the take path) did not occur on the runner. The take slot kept its pool there and no query stalled. The real cause of the wipe flake is late frames, fixed in #1027. The guard here reproduces only a probe-injected delay, so it does not guard an observed failure. Reopen if we see allocation stalls on real hardware. 🤖 Generated with Claude Code |
Problem
Since #1007 (idle FX slots in passthrough), a classic wipe on the GitHub macOS runner reads as a hard cut:
wipe_between_letterboxed_sources_animatesfails 2 of 2 withclassic wipe: animated=false end white=0.00 red=0.76. Before the perf merges (main at f8a83b8 and 48cd16e) it passed on the same runner; locally it passes.Mechanism: entering passthrough called
reconfigure_src(), so the slot renegotiated and, in passthrough,do_bufferpoolreleased its GL output pool. Leaving passthrough on the wipe's first buffer renegotiated again and sent a serialized ALLOCATION query from thefx_takebranch's streaming thread into the mixer. When that query is slow (virtualized GL on the runner), the branch stalls while the mixer keeps compositing the last unmasked frame on a pad whose alpha the classic take has already raised (+60 ms); the masked frames that follow arrive too late, so the wipe shows as a cut. Before #1007 the pool already existed and a take never queried allocation. The runner's GStreamer is the same 1.28.6 as local; the difference is speed.Change
backend/src/gst/shaders/passthrough.rs:buffer_pool()is gone (caps changed while the slot was in passthrough).Evidence
fx_take_0/1(installed after start-up): exactly the CI output,classic wipe: animated=false end white=0.00 red=0.76. Slowing buffers instead did not reproduce it. Delaying only thefx_take_*allocation reproduces it and changing onlypassthrough.rsremoves it, which rules out the other perf merges.wipe_animates_when_take_slot_allocation_is_slow(same body as the letterbox wipe test, with the delay probe): fails with the CI signature when the old reconfigure behaviour is put back, passes with the fix.ci:macos.Tests
Ran (macOS, GStreamer 1.28.6, GL):
vision_mixer_fx_test(3),vision_mixer_fx_passthrough_test(1 + the ignored measurement once),vision_mixer_cpu_test(7),pipeline_lifecycle_test(4),vision_mixer_source_resize_test(8),passthroughlib unit tests (4), clippy-D warnings, fmt.For the reviewer
🤖 Generated with Claude Code