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:
@@ -9,6 +9,10 @@
|
||||
let fontsReady = null;
|
||||
const imageCache = new Map(); // src -> ImageBitmap | null
|
||||
const surfaces = {}; // side -> { canvas, ctx }
|
||||
// The reveal "base" layer is the plain paper background (drawPageBase) — identical for every
|
||||
// page of a side at a given size. Send its bitmap only once per side+size; the main thread
|
||||
// caches and reuses it, avoiding a large per-block ImageBitmap allocation (GC churn).
|
||||
const sentBaseKeys = new Set();
|
||||
|
||||
function resolveImageSource(metadata = {}) {
|
||||
const explicit = String(metadata.url || metadata.src || '').trim();
|
||||
@@ -319,7 +323,11 @@ async function renderSide(job, side) {
|
||||
|
||||
drawPageBase(ctx, side, width, height);
|
||||
let baseBitmap = null;
|
||||
if (job.hasReveal) baseBitmap = await createImageBitmap(surface.canvas);
|
||||
const baseKey = `${side}:${width}x${height}`;
|
||||
if (job.hasReveal && !sentBaseKeys.has(baseKey)) {
|
||||
baseBitmap = await createImageBitmap(surface.canvas);
|
||||
sentBaseKeys.add(baseKey);
|
||||
}
|
||||
if (meta?.kind === 'title') drawTitlePage(ctx, metrics, side, job.titleData);
|
||||
drawPageLines(ctx, metrics, side, job.spreads?.[side] || []);
|
||||
drawPageNumber(ctx, metrics, side, meta);
|
||||
|
||||
Reference in New Issue
Block a user