view: assert the FX-park coalescing delay's debounce; correct four overclaiming doc/comment claims
Extracts parkReadyAt/parkIsReady as a tested pure fold per PLAN.md's phase criterion; the rest is wording fixes — hitch bound, hazard width, forced-drain scope, progressive CPU reclaim.
This commit is contained in:
+26
-11
@@ -57,17 +57,32 @@ decide membership or mode rules.
|
||||
`[verify — DAW]`. **The drain is SPLIT BY INTENT KIND, because only one kind is
|
||||
unsafe to persist over.** A pending RESTORE is: flags restored, snapshot already
|
||||
dropped, FX still offline — a save inside that window records offline FX beside a
|
||||
model that can no longer replan them, unrecoverable on reopen. So any path that
|
||||
serializes the view model drains every restore synchronously first
|
||||
(`persistViewState`, `render_in_place`), and an action-driven switch still pays
|
||||
the RELOAD hitch before it returns — its repaint and undo block have both closed
|
||||
by then, which is what the deferral was for. Any new caller that reapplies a mode
|
||||
and then persists inherits this obligation. A pending PARK is safe to save over:
|
||||
flags parked, snapshot stored, FX still online, so a reopen replans the park and
|
||||
the drain offlines it — it converges. Parks therefore go lazy, ONE FX per idle
|
||||
tick behind a one-second coalescing delay, so the unload half never blocks the
|
||||
UI at all. The delay is also the width of the live-enumeration hazard at
|
||||
`tickDeferredFxParks` — do not lengthen it casually.
|
||||
model that can no longer replan them, unrecoverable on reopen. `persistViewState`
|
||||
and `render_in_place` are the only two paths that force the restore drain before
|
||||
they serialize; roughly ten other `saveToActiveProject` callers (`ingest.cpp`,
|
||||
`bank_ops.cpp`, `bake_land.cpp`, `capture_batch.cpp`, `capture_orchestrator.cpp`,
|
||||
`realtime_lifecycle.cpp`, `panel_input.cpp`) persist without forcing it first — a
|
||||
pre-existing, roughly one-tick-wide gap (the idle tick drains restores too),
|
||||
not known to be exploitable in practice. A new caller that reapplies a mode and
|
||||
then persists inherits the forced-drain obligation; one that merely persists does
|
||||
not. `drainDeferredFxRestores` is also a silent no-op while a drain is already in
|
||||
flight (`g_draining`), so a restore forced from inside another drain's
|
||||
message-pump window can itself be skipped — same order of window, same
|
||||
pre-existing status. An action-driven switch still pays the RELOAD hitch before
|
||||
it returns — its repaint and undo block have both closed by then, which is what
|
||||
the deferral was for. A pending PARK is safe to save over: flags parked, snapshot
|
||||
stored, FX still online, so a reopen replans the park and the drain offlines it —
|
||||
it converges. Parks therefore go lazy, ONE FX per idle tick behind a one-second
|
||||
coalescing delay, which bounds each tick's hitch to one FX's unload rather than
|
||||
eliminating it — see `view_fx_park.h` for why per-track chunking would not help.
|
||||
CPU reclaim is therefore PROGRESSIVE, completing over FX-count ticks rather than
|
||||
in one step: a user watching the CPU meter after a switch sees a ramp, not a
|
||||
drop — in tension with `design-view.md`'s full-CPU-park rationale ("a heavy FX
|
||||
bench you don't want taxing the CPU while you arrange"). The delay is only ONE term
|
||||
of the live-enumeration hazard's width: `firstOnlineFx` re-enumerates the chain
|
||||
every tick, not just the first, so the actual exposure is delay + (FX count ×
|
||||
tick interval), and for a large chain the second term dominates — see
|
||||
`tickDeferredFxParks`. Do not lengthen the delay casually.
|
||||
`[verify — DAW]` whether the switch's `UpdateArrange` paints before the first
|
||||
drain tick: nothing pumps the message loop between them, so "the switch paints
|
||||
first" is an assumption, not an SDK guarantee.
|
||||
|
||||
Reference in New Issue
Block a user