mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-24 22:02:09 +00:00
perf(highway): stop the adaptive renderScale from visibly hunting up/down
Alpha testers reported the 3D-highway "quality going up and down to try to compensate" as passages got busier (#618 charrette). That's core's load-adaptive render scale (_adaptRenderScale, #654) ping-ponging across the 7-12ms deadband: it downscales when a busy frame blows the budget, then the now-cheaper frame dips under the low watermark so it upscales, which blows the budget again — a visible resolution pop on a loop. Fix: keep downscaling prompt (protect the frame rate), but make UPSCALING lazy and predictive: - smaller up-step (x1.06 vs x1.1) on a longer, separate cooldown (_AUTO_UPSCALE_COOLDOWN_MS = 2500ms vs the 600ms general adjust cooldown), reset on any downscale so we never bounce straight back up; - a predictive guard: only upscale when the projected cost AFTER the step (~cost * step^2, since draw cost tracks pixel count) still clears the high budget. The scale settles just inside the deadband instead of oscillating. No public API change; the user-facing "Min res" floor (_autoScaleMin) is untouched. Pairs with the in-plugin AA-under-bloom fix in feedBack#618. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5111ef9440
commit
0596f7970c
@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- **3D highway: section + tone HUD cards now default OFF.** The v0.3.0 player chrome carries a persistent "Up Next" pill, making the in-canvas section card redundant by default (it doubled the readout, feedBack feedback); the tone HUD follows the same less-is-more default. Both remain available in Settings → 3D Highway (visibility/position/size unchanged); users who previously toggled either explicitly keep their stored preference — only the untouched default flips. `plugins/highway_3d` v3.24.1.
|
||||
- **Perf**: replace runtime Tailwind Play CDN with a prebuilt static stylesheet (`static/tailwind.min.css`). The Play CDN's runtime JIT scanned the DOM ~1.8x/sec on the main thread (~37 ms blocking spans), dropping ~26% of frames in long playback sessions with the 3D highway as default. Theme extensions (dark/accent/gold colors, Inter font) move to `tailwind.config.js`; regen via `bash scripts/build-tailwind.sh`. No runtime build step — the generated CSS is committed. Fixes feedBack-desktop#110.
|
||||
- **Perf**: reduce per-frame allocations in the 2D highway chord + lyric render paths. `_ensureChordRenderCache` now also caches `sortedNotes` / `nonZeroNotes` / `nonZeroFrets` / `allMuted` / `hasMultipleNotes` (computed once per chord, invalidated on `src` / `_inverted` / `chordTemplates` change — the third key catches a stale `isOpen`-derived classification when the WS `chord_templates` message lands after the final `chords` chunk), so `drawChords` no longer re-sorts / re-filters / spreads min-max per visible chord per frame. The in-chord unison bend classification is folded inline (no `chordPositions.filter` × 2 per frame). `drawLyrics` memoizes `ctx.measureText` results in a two-level `Map<fontSize, Map<text, width>>` so cache hits don't allocate a composite string key. Lit-sustain shimmer in `drawSustains` swaps the 4 per-note-per-frame `Math.random()` calls for a 64-entry precomputed jitter LUT (xorshift32-seeded — the LUT contents are reload-stable and test-reproducible; rendered shimmer is deterministic per `createHighway()` instance, since the seed includes that instance's `_frameIdx`) indexed by `(frameIdx + n.s + ⌊n.t·60⌋)`, visually indistinguishable and allocation-free.
|
||||
- **Perf**: the load-adaptive render scale (`_adaptRenderScale`, #654) no longer visibly hunts up/down on passages that hover near the frame budget (testers saw "quality going up and down" with the 3D highway). Downscaling stays prompt to protect the frame rate, but **upscaling is now lazy**: a smaller step (×1.06 vs ×1.1) on a longer cooldown (`_AUTO_UPSCALE_COOLDOWN_MS` 2500 ms vs the 600 ms adjust cooldown), reset on any downscale, and gated by a predictive guard — it only upscales when the projected cost *after* the step (≈ cost × step², since draw cost tracks the pixel count) still clears the high budget. The scale therefore settles just inside the 7–12 ms deadband instead of oscillating across it. No new public API; the `_autoScaleMin` "Min res" floor is unchanged.
|
||||
|
||||
### Removed
|
||||
- **`c` library hotkey ("Convert to .sloppak") removed from core.** Core hardcoded a plugin-specific shortcut: a documentation-only `registerShortcut({ key: 'c', scope: 'library' })` no-op plus a `c → button.sloppak-convert-btn` entry in the library keydown handler that fired the Sloppak Converter plugin's button. Per the plugins-own-their-behavior principle, core no longer ships this hotkey — the convert button still works by click, and the Sloppak Converter plugin can register its own `c` shortcut via `window.registerShortcut()` if keyboard access is wanted. The `f` (favorite) and `e` (edit) library hotkeys, which drive core buttons, are unchanged. Help-modal/registry tests in `tests/browser/keyboard-shortcuts.spec.ts` updated to drop the `c` assertions.
|
||||
|
||||
@ -248,6 +248,7 @@ function createHighway() {
|
||||
let _frameMsEMA = 0; // smoothed frame interval (for the HUD)
|
||||
let _lastFramePerf = 0;
|
||||
let _lastAutoAdjustAt = 0;
|
||||
let _lastUpscaleAt = 0; // separate, longer clock for UPscaling (lazy)
|
||||
let _perfHud = null;
|
||||
let _hudOn = false; // cached highwayPerfHud flag (re-read ~2x/sec, not per-frame)
|
||||
let _hudFlagAt = 0;
|
||||
@ -266,6 +267,11 @@ function createHighway() {
|
||||
return Number.isFinite(v) ? Math.max(_AUTO_SCALE_MIN, Math.min(1, v)) : _AUTO_SCALE_MIN;
|
||||
})();
|
||||
const _AUTO_ADJUST_COOLDOWN_MS = 600;
|
||||
// Upscaling is deliberately LAZY (longer cooldown than the downscale path) so
|
||||
// the resolution doesn't visibly hunt up/down on passages that hover near the
|
||||
// budget — testers saw "quality going up and down" as parts got busier (#618
|
||||
// charrette). Downscale stays prompt to protect the frame rate.
|
||||
const _AUTO_UPSCALE_COOLDOWN_MS = 2500;
|
||||
let _inverted = localStorage.getItem('invertHighway') === 'true';
|
||||
let _lefty = localStorage.getItem('lefty') === '1';
|
||||
let _lastChordOnFretLine = null; // chord object currently shown on fret line
|
||||
@ -1291,9 +1297,22 @@ function createHighway() {
|
||||
const eff = _effectiveRenderScale();
|
||||
let next = _autoScale;
|
||||
if (_drawMsEMA > _DRAW_BUDGET_HI_MS && eff > _autoScaleMin) {
|
||||
// Over budget — downscale promptly to protect the frame rate, and reset
|
||||
// the upscale clock so we don't immediately bounce back up.
|
||||
next = _autoScale * 0.85;
|
||||
} else if (_drawMsEMA < _DRAW_BUDGET_LO_MS && eff < 1) {
|
||||
next = _autoScale * 1.1;
|
||||
_lastUpscaleAt = nowP;
|
||||
} else if (_drawMsEMA < _DRAW_BUDGET_LO_MS && eff < 1
|
||||
&& nowP - _lastUpscaleAt >= _AUTO_UPSCALE_COOLDOWN_MS) {
|
||||
// Headroom — upscale LAZILY: a smaller step on a longer cooldown, and
|
||||
// only when the projected cost AFTER the step (cost scales ~with the
|
||||
// pixel count, i.e. step²) still clears the high budget. That predictive
|
||||
// guard is what stops the up→over-budget→down ping-pong testers saw: the
|
||||
// scale settles just inside the deadband instead of oscillating across it.
|
||||
const step = 1.06;
|
||||
if (_drawMsEMA * step * step < _DRAW_BUDGET_HI_MS) {
|
||||
next = _autoScale * step;
|
||||
_lastUpscaleAt = nowP;
|
||||
}
|
||||
}
|
||||
// Clamp so _renderScale * _autoScale stays within [_autoScaleMin, 1].
|
||||
// Cap `lo` at 1: when the floor exceeds the manual ceiling (e.g. quality
|
||||
|
||||
Loading…
Reference in New Issue
Block a user