mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-15 21:27:14 +00:00
perf(highway_3d): pre-warm shaders and label textures at init
Trace showed frame spikes from Three.js first-use costs mid-song: shader program compilation (getParameters/getProgramCacheKey) and lazy texture uploads (texSubImage2D) whenever a chord name, section banner, or fret label first appeared. - ren.compile(scene, cam) after initScene (pools already warmed by feedBack#226, board built, background mounted) so programs compile during the load spinner. - Pre-rasterise + GPU-upload (ren.initTexture) the deterministic txtMat entries: fret numbers 0-24 in the noteFret/fretRow/ghostFret combos the per-frame paths request. - Chart-dependent labels (chord template names, section names) prewarm once on the first draw() after each init, when bundle arrays are guaranteed populated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
fd840011d2
commit
5239665e2b
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "highway_3d",
|
"id": "highway_3d",
|
||||||
"name": "3D Highway",
|
"name": "3D Highway",
|
||||||
"version": "3.30.2",
|
"version": "3.31.0",
|
||||||
"type": "visualization",
|
"type": "visualization",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"script": "screen.js",
|
"script": "screen.js",
|
||||||
|
|||||||
@@ -9886,6 +9886,55 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── Per-frame rendering ─────────────────────────────────────────── */
|
/* ── Per-frame rendering ─────────────────────────────────────────── */
|
||||||
|
// ── GPU pre-warm (perf: first-appearance hitches) ─────────────────
|
||||||
|
// Three.js compiles a material's shader program and uploads a
|
||||||
|
// texture the first frame the owning object renders — profiled as
|
||||||
|
// mid-song frame spikes (getParameters / texSubImage2D). Pay those
|
||||||
|
// costs during init (load spinner) instead:
|
||||||
|
// _prewarmStatic() — ren.compile() over the fully-built scene
|
||||||
|
// + deterministic label textures (fret
|
||||||
|
// numbers in every per-frame style/colour
|
||||||
|
// combo).
|
||||||
|
// _prewarmChart(bundle) — chart-dependent labels (chord template
|
||||||
|
// names, section names); needs the ready
|
||||||
|
// bundle, so it runs once from the first
|
||||||
|
// draw() after each init.
|
||||||
|
// txtMat() rasterises into the unbounded cache these draws hit
|
||||||
|
// anyway; ren.initTexture() forces the GPU upload now.
|
||||||
|
let _chartPrewarmed = false;
|
||||||
|
function _prewarmTex(mat) {
|
||||||
|
if (mat && mat.map && ren) ren.initTexture(mat.map);
|
||||||
|
}
|
||||||
|
function _prewarmStatic() {
|
||||||
|
try {
|
||||||
|
if (ren && scene && cam) ren.compile(scene, cam);
|
||||||
|
} catch (e) { console.warn('[3D-Hwy] prewarm compile:', e); }
|
||||||
|
try {
|
||||||
|
for (let f = 0; f <= NFRETS; f++) {
|
||||||
|
_prewarmTex(txtMat(f, FRET_LABEL_GOLD_HEX, false, 'noteFret'));
|
||||||
|
_prewarmTex(txtMat(f, FRET_LABEL_GOLD_HEX, false, 'fretRow'));
|
||||||
|
_prewarmTex(txtMat(f, FRET_LABEL_IDLE_HEX, false, 'fretRow'));
|
||||||
|
_prewarmTex(txtMat(f, '#ffffff', false, 'ghostFret'));
|
||||||
|
}
|
||||||
|
} catch (e) { console.warn('[3D-Hwy] prewarm labels:', e); }
|
||||||
|
}
|
||||||
|
function _prewarmChart(bundle) {
|
||||||
|
try {
|
||||||
|
const tpls = bundle && bundle.chordTemplates;
|
||||||
|
if (Array.isArray(tpls)) {
|
||||||
|
for (const tpl of tpls) {
|
||||||
|
if (tpl && tpl.name) _prewarmTex(txtMat(tpl.name, '#e8d080', true, 'chord'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const secs = bundle && bundle.sections;
|
||||||
|
if (Array.isArray(secs)) {
|
||||||
|
for (const s of secs) {
|
||||||
|
if (s && s.name) _prewarmTex(txtMat(s.name, '#00cccc', true, 'section'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) { console.warn('[3D-Hwy] prewarm chart labels:', e); }
|
||||||
|
}
|
||||||
|
|
||||||
function update(bundle) {
|
function update(bundle) {
|
||||||
pbBeg(0);
|
pbBeg(0);
|
||||||
// [verdict glow] Apply the level-driven verdict brightness captured
|
// [verdict glow] Apply the level-driven verdict brightness captured
|
||||||
@@ -14962,6 +15011,12 @@
|
|||||||
_invertedForBoard = _invertedCached;
|
_invertedForBoard = _invertedCached;
|
||||||
_leftyForBoard = _leftyCached;
|
_leftyForBoard = _leftyCached;
|
||||||
if (!initScene()) { _unsubscribeFocus(); _rejectReady(new Error('initScene failed')); return; }
|
if (!initScene()) { _unsubscribeFocus(); _rejectReady(new Error('initScene failed')); return; }
|
||||||
|
// Pre-compile shaders + upload deterministic label
|
||||||
|
// textures while the load spinner is still up; the
|
||||||
|
// chart-dependent half runs on first draw() (bundle
|
||||||
|
// arrays are only guaranteed populated post-ready).
|
||||||
|
_prewarmStatic();
|
||||||
|
_chartPrewarmed = false;
|
||||||
const sz = canvasSize(highwayCanvas);
|
const sz = canvasSize(highwayCanvas);
|
||||||
// Mark ready before RAF so any resize(w,h) calls that arrive
|
// Mark ready before RAF so any resize(w,h) calls that arrive
|
||||||
// in the meantime (e.g. from sizeCanvases()) are applied directly.
|
// in the meantime (e.g. from sizeCanvases()) are applied directly.
|
||||||
@@ -15000,6 +15055,10 @@
|
|||||||
|
|
||||||
draw(bundle) {
|
draw(bundle) {
|
||||||
if (!_isReady) return;
|
if (!_isReady) return;
|
||||||
|
if (!_chartPrewarmed) {
|
||||||
|
_chartPrewarmed = true;
|
||||||
|
_prewarmChart(bundle);
|
||||||
|
}
|
||||||
_invertedCached = !!bundle.inverted;
|
_invertedCached = !!bundle.inverted;
|
||||||
_leftyCached = !!bundle.lefty;
|
_leftyCached = !!bundle.lefty;
|
||||||
const newNStr = resolveStringCount(bundle);
|
const newNStr = resolveStringCount(bundle);
|
||||||
|
|||||||
Reference in New Issue
Block a user