Front-load post-processing compile into the loader
primeSceneForLoader() compiled scene materials and rendered the shadow/reflection passes once, but never ran the full composer pipeline — so the SSAO and output passes compiled their programs and allocated their render targets on the first live frame after the loader faded, tanking FPS for ~1-2s before it climbed to full. Now the loader runs composer.render() twice during prime, and precompiles the flip page materials (created lazily on first flip, so previously missed by renderer.compile) via a throwaway probe mesh. The heavy first-frame work is paid behind the loader overlay instead. Verified live: loader timings show composerWarmup taking ~1499ms during load (exactly the cost that used to hit the first frame); after fade-out there are no over-budget tank frames in the slow-frame log and idle settles at ~72fps. Static suite passes (165). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4317,12 +4317,39 @@ function primeSceneForLoader() {
|
|||||||
updateTableReflection();
|
updateTableReflection();
|
||||||
markLoaderTiming('tableReflection:end');
|
markLoaderTiming('tableReflection:end');
|
||||||
markLoaderTiming('shaderCompile:start');
|
markLoaderTiming('shaderCompile:start');
|
||||||
renderer.compile(scene, camera);
|
compileFlipMaterialsForLoader();
|
||||||
markLoaderTiming('shaderCompile:end');
|
markLoaderTiming('shaderCompile:end');
|
||||||
|
// Run the full post-processing pipeline now so the SSAO and output passes compile their
|
||||||
|
// programs and allocate their render targets during the loader, instead of stalling the
|
||||||
|
// first live frames after the loader fades out.
|
||||||
|
markLoaderTiming('composerWarmup:start');
|
||||||
|
if (composer) {
|
||||||
|
composer.render();
|
||||||
|
composer.render();
|
||||||
|
}
|
||||||
|
markLoaderTiming('composerWarmup:end');
|
||||||
staticSceneBuffersDirty = false;
|
staticSceneBuffersDirty = false;
|
||||||
markLoaderTiming('primeSceneForLoader:end');
|
markLoaderTiming('primeSceneForLoader:end');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The flipping page mesh is only created on the first page flip, so its materials are not in
|
||||||
|
// the scene graph that renderer.compile walks. Compile them now via a throwaway probe mesh so
|
||||||
|
// the first flip does not stutter while the GPU compiles the flip page program.
|
||||||
|
function compileFlipMaterialsForLoader() {
|
||||||
|
const probeGeometry = new THREE.PlaneGeometry(0.001, 0.001);
|
||||||
|
const probes = [materials.flipPageSurface, materials.flipPageBackSurface, materials.flipPageEdge]
|
||||||
|
.map((material) => {
|
||||||
|
const probe = new THREE.Mesh(probeGeometry, material);
|
||||||
|
probe.position.copy(book.position);
|
||||||
|
probe.visible = true;
|
||||||
|
book.add(probe);
|
||||||
|
return probe;
|
||||||
|
});
|
||||||
|
renderer.compile(scene, camera);
|
||||||
|
probes.forEach((probe) => book.remove(probe));
|
||||||
|
probeGeometry.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
function tintAmbientFromCanvas(canvas) {
|
function tintAmbientFromCanvas(canvas) {
|
||||||
if (!canvas || !candleBounceLight) return;
|
if (!canvas || !candleBounceLight) return;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|||||||
Reference in New Issue
Block a user