[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.height = height;
};
_skwasm_captureImageBitmap = function(contextHandle, width, height, imagePromises) {
if (!imagePromises) imagePromises = Array();
_skwasm_captureImageBitmap = function(contextHandle, images) {
if (!images) images = Array();
const canvas = handleToCanvasMap.get(contextHandle);
imagePromises.push(createImageBitmap(canvas, 0, 0, width, height));
return imagePromises;
images.push(canvas.transferToImageBitmap());
return images;
};
_skwasm_resolveAndPostImages = async function(surfaceHandle, imagePromises, rasterStart, callbackId) {
const imageBitmaps = imagePromises ? await Promise.all(imagePromises) : [];
_skwasm_postImages = async function(surfaceHandle, imageBitmaps, rasterStart, callbackId) {
const rasterEnd = skwasm_getCurrentTimestamp();
skwasm_postMessage({
skwasmMessage: 'onRenderComplete',
@ -136,7 +135,7 @@ mergeInto(LibraryManager.library, {
const newTexture = glCtx.createTexture();
glCtx.bindTexture(glCtx.TEXTURE_2D, newTexture);
glCtx.pixelStorei(glCtx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
glCtx.texImage2D(glCtx.TEXTURE_2D, 0, glCtx.RGBA, width, height, 0, glCtx.RGBA, glCtx.UNSIGNED_BYTE, textureSource);
glCtx.pixelStorei(glCtx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
@ -193,8 +192,8 @@ mergeInto(LibraryManager.library, {
skwasm_resizeCanvas__deps: ['$skwasm_support_setup'],
skwasm_captureImageBitmap: function () {},
skwasm_captureImageBitmap__deps: ['$skwasm_support_setup'],
skwasm_resolveAndPostImages: function () {},
skwasm_resolveAndPostImages__deps: ['$skwasm_support_setup'],
skwasm_postImages: function () {},
skwasm_postImages__deps: ['$skwasm_support_setup'],
skwasm_createGlTextureFromTextureSource: function () {},
skwasm_createGlTextureFromTextureSource__deps: ['$skwasm_support_setup'],
skwasm_dispatchDisposeSurface: function() {},
@ -204,4 +203,3 @@ mergeInto(LibraryManager.library, {
skwasm_postRasterizeResult: function() {},
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 void skwasm_resizeCanvas(uint32_t contextHandle, int width, int height);
extern SkwasmObject skwasm_captureImageBitmap(uint32_t contextHandle,
int width,
int height,
SkwasmObject imagePromises);
extern void skwasm_resolveAndPostImages(Skwasm::Surface* surface,
SkwasmObject imagePromises,
double rasterStart,
uint32_t callbackId);
extern void skwasm_postImages(Skwasm::Surface* surface,
SkwasmObject imageBitmaps,
double rasterStart,
uint32_t callbackId);
extern unsigned int skwasm_createGlTextureFromTextureSource(
SkwasmObject textureSource,
int width,

View File

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