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:
@@ -33,14 +33,19 @@ namespace {
|
||||
// swallow a rapid A→B→A flip whole — that flip's restore then cancels the park
|
||||
// outright and the plugins never move at all — and short enough that the window
|
||||
// in which a user could add an FX to the track the switch just hid, and so miss
|
||||
// the pre-park snapshot, stays implausible. Seconds, not minutes: this delay is
|
||||
// the width of the hazard documented at tickDeferredFxParks.
|
||||
// the pre-park snapshot, stays implausible. Seconds, not minutes; this is ONE
|
||||
// term of the hazard's width — see tickDeferredFxParks for the other.
|
||||
constexpr double kParkCoalesceSeconds = 1.0;
|
||||
|
||||
FxParkQueue g_queue;
|
||||
ReaProject* g_owner = nullptr; // the project the pending intents were enqueued against
|
||||
bool g_draining = false;
|
||||
double g_parkReadyAt = 0.0; // time_precise() stamp; re-armed by every enqueued park
|
||||
// The gate is GLOBAL, not per-track: a park enqueued for track Z re-arms this
|
||||
// same stamp even though it does nothing to an already-partial park on track A.
|
||||
// Benign — that track's FX are already I_FXEN=0/B_MAINSEND=0 from the
|
||||
// synchronous half, so only its CPU reclaim (not correctness) is delayed — but
|
||||
// this is not a per-intent debounce.
|
||||
double g_parkReadyAt = 0.0; // parkReadyAt() stamp; re-armed by every enqueued park
|
||||
|
||||
// Makes "one drain at a time" explicit rather than implied by the call sites.
|
||||
// RAII because an apply can throw and a stuck flag would silence the queue for
|
||||
@@ -81,10 +86,11 @@ int firstOnlineFx(MediaTrack* tr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// One track by GUID. The park tick resolves ONE track and does so afresh every
|
||||
// tick — a whole-project map would be rebuilt per tick for a single lookup, and
|
||||
// caching the handle across ticks is exactly the dangle ValidatePtr2 is here to
|
||||
// prevent.
|
||||
// One track by GUID, resolved afresh every tick — caching the handle across
|
||||
// ticks is exactly the dangle ValidatePtr2 is here to prevent. Still O(tracks),
|
||||
// still one guidString() per track per tick; a per-tick unordered_map keyed by
|
||||
// GUID would cost the same enumeration to build for a single lookup, so the only
|
||||
// thing avoided by NOT building one is that allocation.
|
||||
MediaTrack* findTrack(ReaProject* proj, const std::string& guid) {
|
||||
const int count = CountTracks(proj);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
@@ -169,7 +175,7 @@ std::vector<FxOfflineOp> deferFxPark(ReaProject* proj, const std::string& guid)
|
||||
adoptOwner(proj);
|
||||
// Re-armed, not set once: while switches keep arriving the park keeps
|
||||
// waiting, which is the whole point of coalescing them.
|
||||
g_parkReadyAt = time_precise() + kParkCoalesceSeconds;
|
||||
g_parkReadyAt = parkReadyAt(time_precise(), kParkCoalesceSeconds);
|
||||
return g_queue.park(guid);
|
||||
}
|
||||
|
||||
@@ -239,7 +245,7 @@ void drainDeferredFxRestores() {
|
||||
|
||||
void tickDeferredFxParks() {
|
||||
if (!drainGateOpen()) return;
|
||||
if (time_precise() < g_parkReadyAt) return; // still coalescing
|
||||
if (!parkIsReady(time_precise(), g_parkReadyAt)) return; // still coalescing
|
||||
|
||||
const std::string guid = g_queue.nextParkGuid();
|
||||
if (guid.empty()) return; // restores only — not this half's work
|
||||
|
||||
Reference in New Issue
Block a user