[CP-beta][skwasm] Use queueMicrotask instead of postMessage when single-threaded (#167154)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)

### Issue Link:
https://github.com/flutter/flutter/issues/166905

### Changelog Description:
* [flutter/166905](https://github.com/flutter/flutter/issues/166905) Fixes a performance regression in skwasm when running in single-threaded mode.

### Impact Description:
This fixes a significant regression in the skwasm renderer when running single-thraaded (i.e. in a non-`crossOriginIsolated` browsing context)

### Workaround:
Is there a workaround for this issue?

The only workaround is to run skwasm in a multi-threaded context or to disable skwasm.

### Risk:
What is the risk level of this cherry-pick?

  - [ x ] Low

This essentially returns the single-threaded renderer to the previous message passing strategy.

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

  - [ x ] Yes

### Validation Steps:
What are the steps to validate that this fix works?

Built the Wonderous app and take a Chrome profile.
This commit is contained in:
flutteractionsbot 2025-04-15 18:09:26 -07:00 committed by GitHub
parent eeb81b9a8a
commit 2cf78c5583
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,51 +8,72 @@
mergeInto(LibraryManager.library, { mergeInto(LibraryManager.library, {
$skwasm_support_setup__postset: 'skwasm_support_setup();', $skwasm_support_setup__postset: 'skwasm_support_setup();',
$skwasm_support_setup: function() { $skwasm_support_setup: function() {
// This value represents the difference between the time origin of the main if (Module["skwasmSingleThreaded"]) {
// thread and whichever web worker this code is running on. This is so that _skwasm_isSingleThreaded = function() {
// when we report frame timings, that they are in the same time domain return true;
// regardless of whether they are captured on the main thread or the web
// worker.
let timeOriginDelta = 0;
skwasm_registerMessageListener = function(threadId, listener) {
const eventListener = function({data}) {
const skwasmMessage = data.skwasmMessage;
if (!skwasmMessage) {
return;
}
if (skwasmMessage == 'syncTimeOrigin') {
timeOriginDelta = performance.timeOrigin - data.timeOrigin;
return;
}
listener(data);
}; };
if (!threadId) {
addEventListener("message", eventListener); let messageListener;
} else { // In single threaded mode, we simply invoke the message listener as a
_wasmWorkers[threadId].addEventListener("message", eventListener); // microtask, as it's much cheaper than doing a full postMessage
_wasmWorkers[threadId].postMessage({ skwasm_registerMessageListener = function(threadId, listener) {
skwasmMessage: 'syncTimeOrigin', messageListener = listener;
timeOrigin: performance.timeOrigin,
});
} }
}; skwasm_getCurrentTimestamp = function() {
skwasm_getCurrentTimestamp = function() { return performance.now();
return performance.now() + timeOriginDelta; };
}; skwasm_postMessage = function(message, transfers, threadId) {
skwasm_postMessage = function(message, transfers, threadId) { // If we're in single-threaded mode, we shouldn't use postMessage, as
if (threadId) { // it ends up being quite expensive. Instead, just queue a microtask.
_wasmWorkers[threadId].postMessage(message, transfers); queueMicrotask(() => messageListener(message));
} else { };
postMessage(message, transfers); } else {
} _skwasm_isSingleThreaded = function() {
}; return false;
};
// This value represents the difference between the time origin of the main
// thread and whichever web worker this code is running on. This is so that
// when we report frame timings, that they are in the same time domain
// regardless of whether they are captured on the main thread or the web
// worker.
let timeOriginDelta = 0;
skwasm_registerMessageListener = function(threadId, listener) {
const eventListener = function({data}) {
const skwasmMessage = data.skwasmMessage;
if (!skwasmMessage) {
return;
}
if (skwasmMessage == 'syncTimeOrigin') {
timeOriginDelta = performance.timeOrigin - data.timeOrigin;
return;
}
listener(data);
};
if (!threadId) {
addEventListener("message", eventListener);
} else {
_wasmWorkers[threadId].addEventListener("message", eventListener);
_wasmWorkers[threadId].postMessage({
skwasmMessage: 'syncTimeOrigin',
timeOrigin: performance.timeOrigin,
});
}
};
skwasm_getCurrentTimestamp = function() {
return performance.now() + timeOriginDelta;
};
skwasm_postMessage = function(message, transfers, threadId) {
if (threadId) {
_wasmWorkers[threadId].postMessage(message, { transfer: transfers } );
} else {
postMessage(message, { transfer: transfers });
}
};
}
const handleToCanvasMap = new Map(); const handleToCanvasMap = new Map();
const associatedObjectsMap = new Map(); const associatedObjectsMap = new Map();
_skwasm_isSingleThreaded = function() {
return Module["skwasmSingleThreaded"];
};
_skwasm_setAssociatedObjectOnThread = function(threadId, pointer, object) { _skwasm_setAssociatedObjectOnThread = function(threadId, pointer, object) {
skwasm_postMessage({ skwasm_postMessage({
skwasmMessage: 'setAssociatedObject', skwasmMessage: 'setAssociatedObject',