Skip to content

Commit 61e87fb

Browse files
committed
perf(engine): pool the canvas-write u8 scratch buffer
Float renders write the working f32 buffer onto the canvas through a `new Uint8ClampedArray(4 * w * h)` allocation each tick. For a 4 MP image that's a 16 MB ephemeral allocation per slider drag - more GC churn than I'd like for the interactive path. Keep the scratch on the Imgstry instance and reuse it; only re-allocate when the dimensions change.
1 parent 9f5aaa9 commit 61e87fb

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

source/platform/browser/imgstry/imgstry.browser.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ export class Imgstry extends ImgstryLayeredEditor implements IDisposable {
8787
cameraToSrgb: readonly number[] | null
8888
} | null = null;
8989
private _rawExposure = 0;
90+
/**
91+
* Reusable u8 scratch for the float-to-canvas write so interactive
92+
* float renders don't allocate a fresh 4*w*h byte buffer each tick.
93+
*/
94+
private _canvasScratch: Uint8ClampedArray<ArrayBuffer> | null = null;
9095

9196
/**
9297
* Creates an instance of Imgstry.
@@ -369,9 +374,11 @@ export class Imgstry extends ImgstryLayeredEditor implements IDisposable {
369374
if (this.canvas.width !== width || this.canvas.height !== height) {
370375
setSize(this.canvas, width, height);
371376
}
372-
const target = new Uint8ClampedArray(buffer.length);
373-
floatToU8(buffer, target);
374-
const frame = new ImageData(target, width, height);
377+
if (!this._canvasScratch || this._canvasScratch.length !== buffer.length) {
378+
this._canvasScratch = new Uint8ClampedArray(new ArrayBuffer(buffer.length));
379+
}
380+
floatToU8(buffer, this._canvasScratch);
381+
const frame = new ImageData(this._canvasScratch, width, height);
375382
this.context.putImageData(frame, 0, 0);
376383
}
377384

0 commit comments

Comments
 (0)