perf(record/canvas): 2D ImageBitmap fast-path (SR-4163)#108
Draft
lewgordon-amplitude wants to merge 4 commits into
Draft
perf(record/canvas): 2D ImageBitmap fast-path (SR-4163)#108lewgordon-amplitude wants to merge 4 commits into
lewgordon-amplitude wants to merge 4 commits into
Conversation
Resolve the years-old TODO at serialize-args.ts:99 by adding a canvas-2D fast-path that transfers an ImageBitmap to the image-bitmap-data-url worker for off-thread encoding instead of calling synchronous toDataURL. - serialize-args: detect OffscreenCanvas + transferToImageBitmap support; when both are available, serializeArg returns a Promise<CanvasArg> that resolves once the worker finishes encoding. Sync toDataURL is kept as the fallback for browsers lacking either API. - image-bitmap-data-url-worker: extend to handle one-shot 'encodeId'-keyed encode requests (new ImageBitmapEncodeWorkerParams type) alongside the existing FPS-sampling path, reusing a shared encodeBitmap helper. - 2d.ts observer: await Promise.all(serializeArgs(...)) so async canvas args resolve before the mutation callback fires. - canvas-manager.ts: forward dataURLOptions into the mutation observer; narrow the FPS-worker onmessage type to avoid union confusion. - types: add ImageBitmapEncodeWorkerParams / ImageBitmapEncodeWorkerResponse (additive — no enum reordering). - test: 8 jsdom unit tests covering both the fast-path and fallback paths, plus replay back-compat deserialization. Co-Authored-By: Claude Opus 4.7 <[email protected]>
|
…illar-3-canvas-fast-path
…s-fast-path' into lewgordon/sr-4163-pillar-3-canvas-fast-path
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves the years-old TODO at
packages/rrweb/src/record/observers/canvas/serialize-args.ts:99:Linear: https://linear.app/amplitude/issue/SR-4163
Confluence plan: https://amplitude.atlassian.net/wiki/spaces/IG/pages/3794403393
What's done
2D fast-path (
serialize-args.ts): WhenOffscreenCanvasandtransferToImageBitmapare both available (Chrome 66+, Firefox 119+, Safari 18.2+),serializeArg(HTMLCanvasElement)now returns aPromise<CanvasArg>instead of blocking the main thread withtoDataURL. The canvas frame is transferred (zero-copy) to the existingimage-bitmap-data-url-workerwhich encodes it off-thread withOffscreenCanvas.convertToBlob.Worker extended (
image-bitmap-data-url-worker.ts): Added a one-shotencodeId-keyed message variant (ImageBitmapEncodeWorkerParams/ImageBitmapEncodeWorkerResponse) alongside the existing FPS-sampling path. Both paths share a newencodeBitmaphelper to avoid code duplication.2D observer async-aware (
2d.ts): ThesetTimeoutcallback nowawaitsPromise.all(serializeArgs(...))so that canvas args resolve before the mutation callback fires.canvas-manager.ts: ForwardsdataURLOptionsintoinitCanvasMutationObserver; narrows the FPS-worker'sonmessagetype to avoid union confusion with the new encode response type.Types (
packages/types/src/index.ts): AddedImageBitmapEncodeWorkerParamsandImageBitmapEncodeWorkerResponse— purely additive, no enum reordering.Tests: 8 jsdom unit tests in
test/record/canvas-2d-fast-path.test.tscovering: fast-path returns Promise, worker message shape, Promise resolution, fallback paths (OffscreenCanvas absent,transferToImageBitmapabsent), and replay back-compat deserialization.What's deferred
maskTextFn/maskInputFnapplication is deferred until Pillar 0's parity harness is ready to gate it.toDataURLworker offload: WebGL already uses the FPS-sampling path with worker encoding; the mutation-observer path for WebGL was not changed in this PR.Back-compat
The serialized output of the fast-path is identical in shape to the existing fallback —
{ rr_type: 'HTMLImageElement', src: 'data:image/...' }. Existing recordings are fully compatible;deserialize-args.tsrequired no changes. Environments withoutOffscreenCanvas/transferToImageBitmapfall through to the synchronoustoDataURLpath unchanged.Browser-compat caveats
transferToImageBitmapOffscreenCanvasBoth must be present for the fast-path to activate. All other environments fall through to the existing synchronous path.
Test plan
packages/rrwebtype check:tsc -noEmitpassespackages/rrwebvite build passestest/record/canvas-2d-fast-path.test.ts(8 tests)serialize-args,2d-mutation,deserialize-args,webgl-mutation,replay/2d-mutation,seek-cache,checkpoint-index,rrdom,util(all pass)🤖 Generated with Claude Code