Cut per-paragraph GC stalls: reuse static paper base, cap lookahead to 1
Profiling the per-paragraph playback stutter showed the JS heap sawtoothing (37<->71MB) with 0.4-2.2s long tasks once per block — GC pauses from large (24-48MB) per-block canvas/ImageBitmap allocations, not pagination (buildPages was ~29ms). These pauses freeze the flip/reveal animation, which is also why the title flip looked un-animated. - The reveal "base" layer is the plain paper background, identical for every page of a side. The worker now sends its bitmap once per side+size; the renderer caches the canvas and reuses it for all reveals, removing a large per-block bitmap+canvas allocation. - WEBGL_BOOK_PREFETCH_LOOKAHEAD 2 -> 1 so only the next block's page render is prepared, instead of letting multiple large rasterizations overlap. Verified live: per-paragraph long tasks roughly halved (10 -> 5 over the same window) and worst case 2159ms -> 1431ms. Residual ~1.4s stall remains from the per-block page bitmap + prepared- page snapshot clone + texture upload; further reduction needs reworking those to reuse buffers. Suite 181. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -336,10 +336,17 @@ class BookTextureRendererModule extends BaseModule {
|
||||
ctx.clearRect(0, 0, this.canvases[side].width, this.canvases[side].height);
|
||||
ctx.drawImage(result.pageBitmap, 0, 0);
|
||||
result.pageBitmap.close?.();
|
||||
if (hasReveal && result.baseBitmap) {
|
||||
this.revealBaseCanvases[side] = this.canvasFromBitmap(result.baseBitmap);
|
||||
// The paper base is identical for every page of a side; the worker sends its bitmap
|
||||
// only once, and we cache the canvas and reuse it for all reveals. This removes a
|
||||
// large per-block canvas/bitmap allocation that was driving GC stalls.
|
||||
if (result.baseBitmap) {
|
||||
if (!this.cachedBaseCanvas) this.cachedBaseCanvas = {};
|
||||
this.cachedBaseCanvas[side] = this.canvasFromBitmap(result.baseBitmap);
|
||||
result.baseBitmap.close?.();
|
||||
}
|
||||
if (hasReveal) {
|
||||
this.revealBaseCanvases[side] = this.cachedBaseCanvas?.[side] || null;
|
||||
}
|
||||
result.baseBitmap?.close?.();
|
||||
});
|
||||
const published = this.publishSpread(sidesToDraw, options);
|
||||
this.markPipelineTiming('drawSpread:end', { sides: sidesToDraw, phase });
|
||||
|
||||
Reference in New Issue
Block a user