Fix skipped realtime analyzer frames
This commit is contained in:
@@ -10,4 +10,11 @@ assert(!/\bopt-w-\d+\b/.test(styleSelect), 'style selector must not have a fixed
|
|||||||
assert(/adjustStyleDropdownWidth\(\)/.test(main), 'dynamic style selector sizing is missing');
|
assert(/adjustStyleDropdownWidth\(\)/.test(main), 'dynamic style selector sizing is missing');
|
||||||
assert(/styleSel\.style\.width\s*=/.test(main), 'dynamic style selector width assignment is missing');
|
assert(/styleSel\.style\.width\s*=/.test(main), 'dynamic style selector width assignment is missing');
|
||||||
|
|
||||||
|
assert(/currentMetricsSeq\s*=\s*Number\.isFinite\(env\.audio\?\.phoenixMetricsSeq\)/.test(main),
|
||||||
|
'render loop must track the metrics sequence used by the RTA');
|
||||||
|
assert(/renderRequestGeneration\s*\+=\s*1/.test(main),
|
||||||
|
'render requests must carry a generation that survives asynchronous rendering');
|
||||||
|
assert(/renderRequestGeneration\s*===\s*renderGeneration\)\s*renderDirty\s*=\s*false/.test(main),
|
||||||
|
'an in-flight render must not clear a newer render request');
|
||||||
|
|
||||||
console.log('GUI contract regression tests passed');
|
console.log('GUI contract regression tests passed');
|
||||||
|
|||||||
+15
-3
@@ -2634,6 +2634,7 @@ let prevSaverActive = false;
|
|||||||
let audioRecoverInFlight = false;
|
let audioRecoverInFlight = false;
|
||||||
let lastAudioRecoverAt = 0;
|
let lastAudioRecoverAt = 0;
|
||||||
let renderDirty = true;
|
let renderDirty = true;
|
||||||
|
let renderRequestGeneration = 0;
|
||||||
let lastRenderedAudioSeq = 0;
|
let lastRenderedAudioSeq = 0;
|
||||||
let processingProfileDirty = true;
|
let processingProfileDirty = true;
|
||||||
let appliedProcessingProfileView = '';
|
let appliedProcessingProfileView = '';
|
||||||
@@ -2642,6 +2643,7 @@ const DATA_ONLY_RENDER_REASONS = new Set(['audio', 'spectro', 'visuals']);
|
|||||||
|
|
||||||
function requestRender(reason = 'ui') {
|
function requestRender(reason = 'ui') {
|
||||||
renderDirty = true;
|
renderDirty = true;
|
||||||
|
renderRequestGeneration += 1;
|
||||||
if (!DATA_ONLY_RENDER_REASONS.has(reason)) processingProfileDirty = true;
|
if (!DATA_ONLY_RENDER_REASONS.has(reason)) processingProfileDirty = true;
|
||||||
env.__lastRenderReason = reason;
|
env.__lastRenderReason = reason;
|
||||||
}
|
}
|
||||||
@@ -2686,7 +2688,14 @@ async function loop(now){
|
|||||||
}
|
}
|
||||||
const targetMs = audioOk ? (1000 / desiredFpsForStyle(renderStyle)) : (1000 / 20);
|
const targetMs = audioOk ? (1000 / desiredFpsForStyle(renderStyle)) : (1000 / 20);
|
||||||
const target = targetMs;
|
const target = targetMs;
|
||||||
const currentAudioSeq = Number.isFinite(env.audio?.xySeq) ? env.audio.xySeq : 0;
|
const currentMetricsSeq = Number.isFinite(env.audio?.phoenixMetricsSeq)
|
||||||
|
? env.audio.phoenixMetricsSeq
|
||||||
|
: 0;
|
||||||
|
const currentVisualsSeq = Number.isFinite(env.audio?.phoenixVisualsSeq)
|
||||||
|
? env.audio.phoenixVisualsSeq
|
||||||
|
: 0;
|
||||||
|
const currentXySeq = Number.isFinite(env.audio?.xySeq) ? env.audio.xySeq : 0;
|
||||||
|
const currentAudioSeq = Math.max(currentMetricsSeq, currentVisualsSeq, currentXySeq);
|
||||||
const audioDirty = currentAudioSeq > lastRenderedAudioSeq;
|
const audioDirty = currentAudioSeq > lastRenderedAudioSeq;
|
||||||
const shouldRenderFrame =
|
const shouldRenderFrame =
|
||||||
renderDirty ||
|
renderDirty ||
|
||||||
@@ -2714,14 +2723,17 @@ async function loop(now){
|
|||||||
}
|
}
|
||||||
prevSaverActive = saverActive;
|
prevSaverActive = saverActive;
|
||||||
if (!saverActive && shouldRenderFrame) {
|
if (!saverActive && shouldRenderFrame) {
|
||||||
|
const renderGeneration = renderRequestGeneration;
|
||||||
meterFacade.setFrameStamp?.(++frameCounter);
|
meterFacade.setFrameStamp?.(++frameCounter);
|
||||||
drawBG();
|
drawBG();
|
||||||
if (!currentView || currentViewId !== renderStyle) setView(renderStyle);
|
if (!currentView || currentViewId !== renderStyle) setView(renderStyle);
|
||||||
if (currentView.render) await currentView.render(env, viewState);
|
if (currentView.render) await currentView.render(env, viewState);
|
||||||
drawOptionsPanelBackdrop();
|
drawOptionsPanelBackdrop();
|
||||||
drawAudioLostOverlay();
|
drawAudioLostOverlay();
|
||||||
renderDirty = false;
|
// A packet or UI event can request another frame while the async view
|
||||||
lastRenderedAudioSeq = currentAudioSeq;
|
// render is in progress. Do not erase that newer request here.
|
||||||
|
if (renderRequestGeneration === renderGeneration) renderDirty = false;
|
||||||
|
lastRenderedAudioSeq = Math.max(lastRenderedAudioSeq, currentAudioSeq);
|
||||||
}
|
}
|
||||||
} catch(e){
|
} catch(e){
|
||||||
showErr('Render error: ' + (e?.message || String(e)));
|
showErr('Render error: ' + (e?.message || String(e)));
|
||||||
|
|||||||
Reference in New Issue
Block a user