[skwasm] Use transferToImageBitmap instead of createImageBitmap (#163251)

Harry had investigated that on the CanvasKit side, that this was a bit a
faster than the `createImageBitmap` approach when dealing with multiple
DOM canvases. Also, it appears that Safari is significantly faster at
`transferToImageBitmap` compared to `createImageBitmap`, so this might
make porting skwasm to Safari a bit more feasible. Either way, we should
validate the performance and make sure this doesn't actually make
anything slower.
This commit is contained in:
Jackson Gardner 2025-02-13 16:32:07 -08:00 committed by GitHub
parent 9ffdd3a0ec
commit 7d22606cda
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 18 additions and 24 deletions

View File

@ -113,14 +113,13 @@ mergeInto(LibraryManager.library, {
canvas.width = width; canvas.width = width;
canvas.height = height; canvas.height = height;
}; };
_skwasm_captureImageBitmap = function(contextHandle, width, height, imagePromises) { _skwasm_captureImageBitmap = function(contextHandle, images) {
if (!imagePromises) imagePromises = Array(); if (!images) images = Array();
const canvas = handleToCanvasMap.get(contextHandle); const canvas = handleToCanvasMap.get(contextHandle);
imagePromises.push(createImageBitmap(canvas, 0, 0, width, height)); images.push(canvas.transferToImageBitmap());
return imagePromises; return images;
}; };
_skwasm_resolveAndPostImages = async function(surfaceHandle, imagePromises, rasterStart, callbackId) { _skwasm_postImages = async function(surfaceHandle, imageBitmaps, rasterStart, callbackId) {
const imageBitmaps = imagePromises ? await Promise.all(imagePromises) : [];
const rasterEnd = skwasm_getCurrentTimestamp(); const rasterEnd = skwasm_getCurrentTimestamp();
skwasm_postMessage({ skwasm_postMessage({
skwasmMessage: 'onRenderComplete', skwasmMessage: 'onRenderComplete',
@ -193,8 +192,8 @@ mergeInto(LibraryManager.library, {
skwasm_resizeCanvas__deps: ['$skwasm_support_setup'], skwasm_resizeCanvas__deps: ['$skwasm_support_setup'],
skwasm_captureImageBitmap: function () {}, skwasm_captureImageBitmap: function () {},
skwasm_captureImageBitmap__deps: ['$skwasm_support_setup'], skwasm_captureImageBitmap__deps: ['$skwasm_support_setup'],
skwasm_resolveAndPostImages: function () {}, skwasm_postImages: function () {},
skwasm_resolveAndPostImages__deps: ['$skwasm_support_setup'], skwasm_postImages__deps: ['$skwasm_support_setup'],
skwasm_createGlTextureFromTextureSource: function () {}, skwasm_createGlTextureFromTextureSource: function () {},
skwasm_createGlTextureFromTextureSource__deps: ['$skwasm_support_setup'], skwasm_createGlTextureFromTextureSource__deps: ['$skwasm_support_setup'],
skwasm_dispatchDisposeSurface: function() {}, skwasm_dispatchDisposeSurface: function() {},
@ -204,4 +203,3 @@ mergeInto(LibraryManager.library, {
skwasm_postRasterizeResult: function() {}, skwasm_postRasterizeResult: function() {},
skwasm_postRasterizeResult__deps: ['$skwasm_support_setup'], skwasm_postRasterizeResult__deps: ['$skwasm_support_setup'],
}); });

View File

@ -28,13 +28,11 @@ extern void skwasm_dispatchRenderPictures(unsigned long threadId,
extern uint32_t skwasm_createOffscreenCanvas(int width, int height); extern uint32_t skwasm_createOffscreenCanvas(int width, int height);
extern void skwasm_resizeCanvas(uint32_t contextHandle, int width, int height); extern void skwasm_resizeCanvas(uint32_t contextHandle, int width, int height);
extern SkwasmObject skwasm_captureImageBitmap(uint32_t contextHandle, extern SkwasmObject skwasm_captureImageBitmap(uint32_t contextHandle,
int width,
int height,
SkwasmObject imagePromises); SkwasmObject imagePromises);
extern void skwasm_resolveAndPostImages(Skwasm::Surface* surface, extern void skwasm_postImages(Skwasm::Surface* surface,
SkwasmObject imagePromises, SkwasmObject imageBitmaps,
double rasterStart, double rasterStart,
uint32_t callbackId); uint32_t callbackId);
extern unsigned int skwasm_createGlTextureFromTextureSource( extern unsigned int skwasm_createGlTextureFromTextureSource(
SkwasmObject textureSource, SkwasmObject textureSource,
int width, int width,

View File

@ -99,9 +99,9 @@ void Surface::_init() {
// Worker thread only // Worker thread only
void Surface::_resizeCanvasToFit(int width, int height) { void Surface::_resizeCanvasToFit(int width, int height) {
if (!_surface || width > _canvasWidth || height > _canvasHeight) { if (!_surface || width != _canvasWidth || height != _canvasHeight) {
_canvasWidth = std::max(width, _canvasWidth); _canvasWidth = width;
_canvasHeight = std::max(height, _canvasHeight); _canvasHeight = height;
_recreateSurface(); _recreateSurface();
} }
} }
@ -124,7 +124,7 @@ void Surface::renderPicturesOnWorker(sk_sp<SkPicture>* pictures,
double rasterStart) { double rasterStart) {
// This is populated by the `captureImageBitmap` call the first time it is // This is populated by the `captureImageBitmap` call the first time it is
// passed in. // passed in.
SkwasmObject imagePromiseArray = __builtin_wasm_ref_null_extern(); SkwasmObject imageBitmapArray = __builtin_wasm_ref_null_extern();
for (int i = 0; i < pictureCount; i++) { for (int i = 0; i < pictureCount; i++) {
sk_sp<SkPicture> picture = pictures[i]; sk_sp<SkPicture> picture = pictures[i];
SkRect pictureRect = picture->cullRect(); SkRect pictureRect = picture->cullRect();
@ -138,11 +138,9 @@ void Surface::renderPicturesOnWorker(sk_sp<SkPicture>* pictures,
canvas->drawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc); canvas->drawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
canvas->drawPicture(picture, &matrix, nullptr); canvas->drawPicture(picture, &matrix, nullptr);
_grContext->flush(_surface.get()); _grContext->flush(_surface.get());
imagePromiseArray = imageBitmapArray = skwasm_captureImageBitmap(_glContext, imageBitmapArray);
skwasm_captureImageBitmap(_glContext, roundedOutRect.width(),
roundedOutRect.height(), imagePromiseArray);
} }
skwasm_resolveAndPostImages(this, imagePromiseArray, rasterStart, callbackId); skwasm_postImages(this, imageBitmapArray, rasterStart, callbackId);
} }
// Worker thread only // Worker thread only