diff --git a/engine/src/build/config/compiler/BUILD.gn b/engine/src/build/config/compiler/BUILD.gn index 15d61c09c0..de15cb053e 100644 --- a/engine/src/build/config/compiler/BUILD.gn +++ b/engine/src/build/config/compiler/BUILD.gn @@ -277,9 +277,9 @@ config("compiler") { } if (is_wasm) { - if (wasm_use_pthreads) { - cflags += [ "-pthread" ] - ldflags += [ "-pthread" ] + if (wasm_use_workers) { + cflags += [ "-sWASM_WORKERS=1" ] + ldflags += [ "-sWASM_WORKERS=1" ] } if (wasm_shared_memory) { cflags += [ "-sSHARED_MEMORY=1" ] ldflags += [ "-sSHARED_MEMORY=1" ] @@ -396,12 +396,12 @@ config("compiler") { # to say that it does. Define them here instead. defines += [ "HAVE_SYS_UIO_H" ] - # When Android requires new flags consider also editing the flags in - # the following locations. + # When Android requires new flags consider also editing the flags in + # the following locations. # Framework plugin_ffi template: packages/flutter_tools/templates/plugin_ffi/src.tmpl/CMakeLists.txt.tmpl # Example PR: https://github.com/flutter/flutter/pull/155508 - # Dart Lang JNI package: pkgs/jni/src/CMakeLists.txt - # Example PR: https://github.com/dart-lang/native/pull/1615 + # Dart Lang JNI package: pkgs/jni/src/CMakeLists.txt + # Example PR: https://github.com/dart-lang/native/pull/1615 ldflags += [ "-Wl,--no-undefined", "-Wl,--exclude-libs,ALL", diff --git a/engine/src/build/toolchain/wasm.gni b/engine/src/build/toolchain/wasm.gni index 0da69d2874..e2515b7f3b 100644 --- a/engine/src/build/toolchain/wasm.gni +++ b/engine/src/build/toolchain/wasm.gni @@ -11,7 +11,7 @@ declare_args() { # The location of an activated embedded emsdk. emsdk_dir = rebase_path("//flutter/prebuilts/emsdk") - wasm_use_pthreads = false + wasm_use_workers = false wasm_shared_memory = false wasm_use_dwarf = false } diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 1a4e7c5ad2..6ecd230631 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -52263,8 +52263,6 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/filters.cpp + ../../../flutter/LICENS ORIGIN: ../../../flutter/lib/web_ui/skwasm/fonts.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/helpers.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/image.cpp + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/skwasm/library_skwasm_single_threaded.js + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/library_skwasm_support.js + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/paint.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/path.cpp + ../../../flutter/LICENSE @@ -52274,8 +52272,6 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/skwasm_support.h + ../../../flutter/L ORIGIN: ../../../flutter/lib/web_ui/skwasm/string.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface_mt.cpp + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface_st.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/line_metrics.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp + ../../../flutter/LICENSE @@ -55258,8 +55254,6 @@ FILE: ../../../flutter/lib/web_ui/skwasm/filters.cpp FILE: ../../../flutter/lib/web_ui/skwasm/fonts.cpp FILE: ../../../flutter/lib/web_ui/skwasm/helpers.h FILE: ../../../flutter/lib/web_ui/skwasm/image.cpp -FILE: ../../../flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js -FILE: ../../../flutter/lib/web_ui/skwasm/library_skwasm_single_threaded.js FILE: ../../../flutter/lib/web_ui/skwasm/library_skwasm_support.js FILE: ../../../flutter/lib/web_ui/skwasm/paint.cpp FILE: ../../../flutter/lib/web_ui/skwasm/path.cpp @@ -55269,8 +55263,6 @@ FILE: ../../../flutter/lib/web_ui/skwasm/skwasm_support.h FILE: ../../../flutter/lib/web_ui/skwasm/string.cpp FILE: ../../../flutter/lib/web_ui/skwasm/surface.cpp FILE: ../../../flutter/lib/web_ui/skwasm/surface.h -FILE: ../../../flutter/lib/web_ui/skwasm/surface_mt.cpp -FILE: ../../../flutter/lib/web_ui/skwasm/surface_st.cpp FILE: ../../../flutter/lib/web_ui/skwasm/text/line_metrics.cpp FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph.cpp FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp diff --git a/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart b/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart index f825680c48..9178a0236a 100644 --- a/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart +++ b/engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart @@ -76,7 +76,6 @@ class CopyArtifactsStep implements PipelineStep { final String canvaskitSourceDirectory; final String canvaskitChromiumSourceDirectory; final String skwasmSourceDirectory; - final String skwasmStSourceDirectory; switch (source) { case LocalArtifactSource(:final mode): final buildDirectory = getBuildDirectoryForRuntimeMode(mode).path; @@ -84,7 +83,6 @@ class CopyArtifactsStep implements PipelineStep { canvaskitSourceDirectory = pathlib.join(buildDirectory, 'canvaskit'); canvaskitChromiumSourceDirectory = pathlib.join(buildDirectory, 'canvaskit_chromium'); skwasmSourceDirectory = pathlib.join(buildDirectory, 'skwasm'); - skwasmStSourceDirectory = pathlib.join(buildDirectory, 'skwasm_st'); case GcsArtifactSource(:final realm): final artifactsDirectory = (await _downloadArtifacts(realm)).path; @@ -96,7 +94,6 @@ class CopyArtifactsStep implements PipelineStep { 'chromium', ); skwasmSourceDirectory = pathlib.join(artifactsDirectory, 'canvaskit'); - skwasmStSourceDirectory = pathlib.join(artifactsDirectory, 'canvaskit'); } await environment.webTestsArtifactsDir.create(recursive: true); @@ -116,7 +113,6 @@ class CopyArtifactsStep implements PipelineStep { if (artifactDeps.skwasm) { copied.add('Skwasm'); await copyWasmLibrary('skwasm', skwasmSourceDirectory, 'canvaskit'); - await copyWasmLibrary('skwasm_st', skwasmStSourceDirectory, 'canvaskit'); } print('Copied artifacts: ${copied.join(', ')}'); } diff --git a/engine/src/flutter/lib/web_ui/flutter_js/src/skwasm_loader.js b/engine/src/flutter/lib/web_ui/flutter_js/src/skwasm_loader.js index 8a72f1cd77..39928f82ab 100644 --- a/engine/src/flutter/lib/web_ui/flutter_js/src/skwasm_loader.js +++ b/engine/src/flutter/lib/web_ui/flutter_js/src/skwasm_loader.js @@ -6,24 +6,63 @@ import { createWasmInstantiator } from "./instantiate_wasm.js"; import { resolveUrlWithSegments } from "./utils.js"; export const loadSkwasm = async (deps, config, browserEnvironment, baseUrl) => { - const fileStem = (browserEnvironment.crossOriginIsolated && !config.forceSingleThreadedSkwasm) ? "skwasm" : "skwasm_st"; - const rawSkwasmUrl = resolveUrlWithSegments(baseUrl, `${fileStem}.js`) + const rawSkwasmUrl = resolveUrlWithSegments(baseUrl, 'skwasm.js') let skwasmUrl = rawSkwasmUrl; if (deps.flutterTT.policy) { skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl); } - const wasmInstantiator = createWasmInstantiator(resolveUrlWithSegments(baseUrl, `${fileStem}.wasm`)); + const wasmInstantiator = createWasmInstantiator(resolveUrlWithSegments(baseUrl, 'skwasm.wasm')); const skwasm = await import(skwasmUrl); return await skwasm.default({ + skwasmSingleThreaded: !browserEnvironment.crossOriginIsolated || config.forceSingleThreadedSkwasm, instantiateWasm: wasmInstantiator, - // When hosted via a CDN or some other url that is not the same - // origin as the main script of the page, we will fail to create - // a web worker with the bootstrapping script. This workaround will - // make sure that the worker JS can be loaded regardless of where - // it is hosted. - mainScriptUrlOrBlob: new Blob( - [`import '${skwasmUrl}'`], - { 'type': 'application/javascript' }, - ), + locateFile: (filename, scriptDirectory) => { + // The wasm workers API has a separate .ww.js file that bootstraps the + // web worker. However, it turns out this worker bootstrapper doesn't + // actually work with ES6 modules, which we have enabled. So we instead + // pass our own bootstrapper that loads skwasm.js as an ES6 module, and + // queues/flushes pending messages that were received during the + // asynchronous load. + if (filename.endsWith('.ww.js')) { + const url = resolveUrlWithSegments(baseUrl, filename); + return URL.createObjectURL(new Blob( + [` +"use strict"; + +let eventListener; +eventListener = (message) => { + const pendingMessages = []; + const data = message.data; + data["instantiateWasm"] = (info,receiveInstance) => { + const instance = new WebAssembly.Instance(data["wasm"], info); + return receiveInstance(instance, data["wasm"]) + }; + import(data.js).then(async (skwasm) => { + await skwasm.default(data); + + removeEventListener("message", eventListener); + for (const message of pendingMessages) { + dispatchEvent(message); + } + }); + removeEventListener("message", eventListener); + eventListener = (message) => { + + pendingMessages.push(message); + }; + + addEventListener("message", eventListener); +}; +addEventListener("message", eventListener); +` + ], + { 'type': 'application/javascript' })); + } + return url; + }, + // Because of the above workaround, the worker is just a blob and + // can't locate the main script using a relative path to itself, + // so we pass the main script location in. + mainScriptUrlOrBlob: rawSkwasmUrl, }); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn b/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn index 2d9063d5f5..1e4221cf71 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn +++ b/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn @@ -4,96 +4,69 @@ import("//build/toolchain/wasm.gni") -template("skwasm_variant") { - wasm_lib(target_name) { - public_configs = [ "//flutter:config" ] +wasm_lib("skwasm") { + public_configs = [ "//flutter:config" ] - sources = [ - "canvas.cpp", - "contour_measure.cpp", - "data.cpp", - "export.h", - "filters.cpp", - "fonts.cpp", - "helpers.h", - "image.cpp", - "paint.cpp", - "path.cpp", - "picture.cpp", - "shaders.cpp", - "skwasm_support.h", - "string.cpp", - "surface.cpp", - "text/line_metrics.cpp", - "text/paragraph.cpp", - "text/paragraph_builder.cpp", - "text/paragraph_style.cpp", - "text/strut_style.cpp", - "text/text_style.cpp", - "vertices.cpp", - "wrappers.h", - ] - - cflags = [ "-mreference-types" ] - - ldflags = [ - "-std=c++20", - "-lGL", - "-sUSE_WEBGL2=1", - "-sMAX_WEBGL_VERSION=2", - "-sOFFSCREENCANVAS_SUPPORT", - "-sALLOW_MEMORY_GROWTH", - "-sALLOW_TABLE_GROWTH", - "-lexports.js", - "-sEXPORTED_FUNCTIONS=[stackAlloc]", - "-sEXPORTED_RUNTIME_METHODS=[addFunction,wasmExports,wasmMemory,stackAlloc]", - "-sINCOMING_MODULE_JS_API=[instantiateWasm,noExitRuntime,mainScriptUrlOrBlob]", - "-sUSE_ES6_IMPORT_META=0", - "--js-library", - rebase_path("library_skwasm_support.js"), - ] - - inputs = [ rebase_path("library_skwasm_support.js") ] - - if (invoker.multi_threaded) { - sources += [ "surface_mt.cpp" ] - ldflags += [ - "-sPTHREAD_POOL_SIZE=1", - "-Wno-pthreads-mem-growth", - "--js-library", - rebase_path("library_skwasm_multi_threaded.js"), - ] - inputs += [ rebase_path("library_skwasm_multi_threaded.js") ] - } else { - sources += [ "surface_st.cpp" ] - ldflags += [ - "--js-library", - rebase_path("library_skwasm_single_threaded.js"), - ] - inputs += [ rebase_path("library_skwasm_single_threaded.js") ] - } - - if (is_debug) { - ldflags += [ - "-sASSERTIONS=1", - "-sGL_ASSERTIONS=1", - ] - } else { - ldflags += [ "--closure=1" ] - } - - deps = [ - "//flutter/skia", - "//flutter/skia/modules/skparagraph", - "//flutter/skia/modules/skunicode", + sources = [ + "canvas.cpp", + "contour_measure.cpp", + "data.cpp", + "export.h", + "filters.cpp", + "fonts.cpp", + "helpers.h", + "image.cpp", + "paint.cpp", + "path.cpp", + "picture.cpp", + "shaders.cpp", + "skwasm_support.h", + "string.cpp", + "surface.cpp", + "text/line_metrics.cpp", + "text/paragraph.cpp", + "text/paragraph_builder.cpp", + "text/paragraph_style.cpp", + "text/strut_style.cpp", + "text/text_style.cpp", + "vertices.cpp", + "wrappers.h", + ] + + cflags = [ "-mreference-types" ] + + ldflags = [ + "-std=c++20", + "-lGL", + "-sUSE_WEBGL2=1", + "-sMAX_WEBGL_VERSION=2", + "-sOFFSCREENCANVAS_SUPPORT", + "-sALLOW_MEMORY_GROWTH", + "-sALLOW_TABLE_GROWTH", + "-lexports.js", + "-sEXPORTED_FUNCTIONS=[stackAlloc]", + "-sEXPORTED_RUNTIME_METHODS=[addFunction,wasmExports,wasmMemory,stackAlloc]", + "-sINCOMING_MODULE_JS_API=[instantiateWasm,locateFile,noExitRuntime,mainScriptUrlOrBlob,wasmMemory,wasm,skwasmSingleThreaded]", + "-sUSE_ES6_IMPORT_META=0", + "--js-library", + rebase_path("library_skwasm_support.js"), + ] + + inputs = [ rebase_path("library_skwasm_support.js") ] + + if (is_debug) { + ldflags += [ + "-sASSERTIONS=1", + "-sGL_ASSERTIONS=1", + "-sSTACK_OVERFLOW_CHECK=2", ] + } else { + ldflags += [ "--closure=1" ] } -} -skwasm_variant("skwasm") { - multi_threaded = true -} - -skwasm_variant("skwasm_st") { - multi_threaded = false + deps = [ + "//flutter/skia", + "//flutter/skia/modules/skparagraph", + "//flutter/skia/modules/skunicode", + ] } diff --git a/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js b/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js deleted file mode 100644 index 237ccf38be..0000000000 --- a/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file adds JavaScript APIs that are accessible to the C++ layer. -// See: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#implement-a-c-api-in-javascript - -mergeInto(LibraryManager.library, { - $skwasm_threading_setup__postset: 'skwasm_threading_setup();', - $skwasm_threading_setup: function() { - // 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 { - PThread.pthreads[threadId].addEventListener("message", eventListener); - PThread.pthreads[threadId].postMessage({ - skwasmMessage: 'syncTimeOrigin', - timeOrigin: performance.timeOrigin, - }); - } - }; - skwasm_getCurrentTimestamp = function() { - return performance.now() + timeOriginDelta; - }; - skwasm_postMessage = function(message, transfers, threadId) { - if (threadId) { - PThread.pthreads[threadId].postMessage(message, transfers); - } else { - postMessage(message, transfers); - } - }; - }, - $skwasm_threading_setup__deps: ['$skwasm_registerMessageListener', '$skwasm_getCurrentTimestamp', '$skwasm_postMessage'], - $skwasm_registerMessageListener: function() {}, - $skwasm_registerMessageListener__deps: ['$skwasm_threading_setup'], - $skwasm_getCurrentTimestamp: function () {}, - $skwasm_getCurrentTimestamp__deps: ['$skwasm_threading_setup'], - $skwasm_postMessage: function () {}, - $skwasm_postMessage__deps: ['$skwasm_threading_setup'], -}); diff --git a/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_single_threaded.js b/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_single_threaded.js deleted file mode 100644 index 6b6221ad88..0000000000 --- a/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_single_threaded.js +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file adds JavaScript APIs that are accessible to the C++ layer. -// See: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#implement-a-c-api-in-javascript - -mergeInto(LibraryManager.library, { - $skwasm_threading_setup__postset: 'skwasm_threading_setup();', - $skwasm_threading_setup: function() { - let messageListener; - skwasm_registerMessageListener = function(threadId, listener) { - messageListener = listener; - }; - skwasm_getCurrentTimestamp = function() { - return performance.now(); - }; - skwasm_postMessage = function(message, transfers, threadId) { - queueMicrotask(() => { - messageListener(message); - }) - }; - }, - $skwasm_threading_setup__deps: ['$skwasm_registerMessageListener', '$skwasm_getCurrentTimestamp', '$skwasm_postMessage'], - $skwasm_registerMessageListener: function() {}, - $skwasm_registerMessageListener__deps: ['$skwasm_threading_setup'], - $skwasm_getCurrentTimestamp: function () {}, - $skwasm_getCurrentTimestamp__deps: ['$skwasm_threading_setup'], - $skwasm_postMessage: function () {}, - $skwasm_postMessage__deps: ['$skwasm_threading_setup'], -}); diff --git a/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_support.js b/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_support.js index db107d668d..702724e71d 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_support.js +++ b/engine/src/flutter/lib/web_ui/skwasm/library_skwasm_support.js @@ -8,9 +8,51 @@ mergeInto(LibraryManager.library, { $skwasm_support_setup__postset: 'skwasm_support_setup();', $skwasm_support_setup: function() { + // 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, transfers); + } else { + postMessage(message, transfers); + } + }; + const handleToCanvasMap = new Map(); const associatedObjectsMap = new Map(); + _skwasm_isSingleThreaded = function() { + return Module["skwasmSingleThreaded"]; + }; _skwasm_setAssociatedObjectOnThread = function(threadId, pointer, object) { skwasm_postMessage({ skwasmMessage: 'setAssociatedObject', @@ -175,15 +217,22 @@ mergeInto(LibraryManager.library, { }); } }, - $skwasm_support_setup__deps: [ '$skwasm_threading_setup'], + $skwasm_registerMessageListener: function() {}, + $skwasm_registerMessageListener__deps: ['$skwasm_support_setup'], + $skwasm_getCurrentTimestamp: function () {}, + $skwasm_getCurrentTimestamp__deps: ['$skwasm_support_setup'], + $skwasm_postMessage: function () {}, + $skwasm_postMessage__deps: ['$skwasm_support_setup'], + skwasm_isSingleThreaded: function() {}, + skwasm_isSingleThreaded__deps: ['$skwasm_support_setup'], skwasm_setAssociatedObjectOnThread: function () {}, - skwasm_setAssociatedObjectOnThread__deps: ['$skwasm_support_setup'], + skwasm_setAssociatedObjectOnThread__deps: ['$skwasm_support_setup', '$skwasm_postMessage'], skwasm_getAssociatedObject: function () {}, skwasm_getAssociatedObject__deps: ['$skwasm_support_setup'], skwasm_disposeAssociatedObjectOnThread: function () {}, skwasm_disposeAssociatedObjectOnThread__deps: ['$skwasm_support_setup'], skwasm_connectThread: function() {}, - skwasm_connectThread__deps: ['$skwasm_support_setup'], + skwasm_connectThread__deps: ['$skwasm_support_setup', '$skwasm_registerMessageListener', '$skwasm_getCurrentTimestamp'], skwasm_dispatchRenderPictures: function() {}, skwasm_dispatchRenderPictures__deps: ['$skwasm_support_setup'], skwasm_createOffscreenCanvas: function () {}, diff --git a/engine/src/flutter/lib/web_ui/skwasm/skwasm_support.h b/engine/src/flutter/lib/web_ui/skwasm/skwasm_support.h index 57dff635b5..54d6e5548d 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/skwasm_support.h +++ b/engine/src/flutter/lib/web_ui/skwasm/skwasm_support.h @@ -13,6 +13,7 @@ using SkwasmObject = __externref_t; extern "C" { +extern bool skwasm_isSingleThreaded(); extern void skwasm_setAssociatedObjectOnThread(unsigned long threadId, void* pointer, SkwasmObject object); diff --git a/engine/src/flutter/lib/web_ui/skwasm/surface.cpp b/engine/src/flutter/lib/web_ui/skwasm/surface.cpp index da0f41c9ce..cb91b10728 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/surface.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/surface.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "surface.h" +#include #include #include "skwasm_support.h" @@ -14,6 +15,23 @@ using namespace Skwasm; +Surface::Surface() { + if (skwasm_isSingleThreaded()) { + skwasm_connectThread(0); + } else { + assert(emscripten_is_main_browser_thread()); + + _thread = emscripten_malloc_wasm_worker(65536); + emscripten_wasm_worker_post_function_v(_thread, []() { + // Listen to the main thread from the worker + skwasm_connectThread(0); + }); + + // Listen to messages from the worker + skwasm_connectThread(_thread); + } +} + // Worker thread only void Surface::dispose() { delete this; @@ -58,16 +76,8 @@ void Surface::setCallbackHandler(CallbackHandler* callbackHandler) { _callbackHandler = callbackHandler; } -// Worker thread only -void Surface::_runWorker() { - _init(); - emscripten_exit_with_live_runtime(); -} - // Worker thread only void Surface::_init() { - // Listen to messages from the main thread - skwasm_connectThread(0); _glContext = skwasm_createOffscreenCanvas(256, 256); if (!_glContext) { printf("Failed to create context!\n"); @@ -95,6 +105,8 @@ void Surface::_init() { emscripten_glGetIntegerv(GL_SAMPLES, &_sampleCount); emscripten_glGetIntegerv(GL_STENCIL_BITS, &_stencil); + + _isInitialized = true; } // Worker thread only @@ -122,6 +134,10 @@ void Surface::renderPicturesOnWorker(sk_sp* pictures, int pictureCount, uint32_t callbackId, double rasterStart) { + if (!_isInitialized) { + _init(); + } + // This is populated by the `captureImageBitmap` call the first time it is // passed in. SkwasmObject imageBitmapArray = __builtin_wasm_ref_null_extern(); @@ -147,6 +163,10 @@ void Surface::renderPicturesOnWorker(sk_sp* pictures, void Surface::rasterizeImageOnWorker(SkImage* image, ImageByteFormat format, uint32_t callbackId) { + if (!_isInitialized) { + _init(); + } + // We handle PNG encoding with browser APIs so that we can omit libpng from // skia to save binary size. assert(format != ImageByteFormat::png); @@ -281,3 +301,7 @@ SKWASM_EXPORT void surface_onRasterizeComplete(Surface* surface, uint32_t callbackId) { surface->onRasterizeComplete(callbackId, data); } + +SKWASM_EXPORT bool skwasm_isMultiThreaded() { + return !skwasm_isSingleThreaded(); +} diff --git a/engine/src/flutter/lib/web_ui/skwasm/surface.h b/engine/src/flutter/lib/web_ui/skwasm/surface.h index 3ef5dbfadc..f793fbb2fc 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/surface.h +++ b/engine/src/flutter/lib/web_ui/skwasm/surface.h @@ -75,12 +75,10 @@ class Surface { uint32_t callbackId); private: - void _runWorker(); void _init(); void _resizeCanvasToFit(int width, int height); void _recreateSurface(); - std::string _canvasID; CallbackHandler* _callbackHandler = nullptr; uint32_t _currentCallbackId = 0; @@ -95,6 +93,8 @@ class Surface { GrGLint _stencil; pthread_t _thread; + + bool _isInitialized = false; }; } // namespace Skwasm diff --git a/engine/src/flutter/lib/web_ui/skwasm/surface_mt.cpp b/engine/src/flutter/lib/web_ui/skwasm/surface_mt.cpp deleted file mode 100644 index cd02dc6d9b..0000000000 --- a/engine/src/flutter/lib/web_ui/skwasm/surface_mt.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "surface.h" - -#include "skwasm_support.h" - -using namespace Skwasm; - -Surface::Surface() { - assert(emscripten_is_main_browser_thread()); - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - pthread_create( - &_thread, &attr, - [](void* context) -> void* { - static_cast(context)->_runWorker(); - return nullptr; - }, - this); - // Listen to messages from the worker - skwasm_connectThread(_thread); -} - -SKWASM_EXPORT bool skwasm_isMultiThreaded() { - return true; -} diff --git a/engine/src/flutter/lib/web_ui/skwasm/surface_st.cpp b/engine/src/flutter/lib/web_ui/skwasm/surface_st.cpp deleted file mode 100644 index 86c7b6b22e..0000000000 --- a/engine/src/flutter/lib/web_ui/skwasm/surface_st.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "surface.h" - -using namespace Skwasm; - -Surface::Surface() : _thread(0) { - _init(); -} - -SKWASM_EXPORT bool skwasm_isMultiThreaded() { - return false; -} diff --git a/engine/src/flutter/third_party/canvaskit/BUILD.gn b/engine/src/flutter/third_party/canvaskit/BUILD.gn index 417cba3517..7fb119bc9e 100644 --- a/engine/src/flutter/third_party/canvaskit/BUILD.gn +++ b/engine/src/flutter/third_party/canvaskit/BUILD.gn @@ -88,31 +88,7 @@ wasm_toolchain("skwasm") { skia_use_libpng_encode = false # skwasm is multithreaded - wasm_use_pthreads = true - wasm_prioritize_size = true - } -} - -wasm_toolchain("skwasm_st") { - extra_toolchain_args = { - # In Chromium browsers, we can use the browser's APIs to get the necessary - # ICU data. - skia_use_icu = false - skia_use_client_icu = true - skia_icu_bidi_third_party_dir = "//flutter/third_party/canvaskit/icu_bidi" - - skia_use_libjpeg_turbo_decode = false - skia_use_libpng_decode = false - skia_use_libwebp_decode = false - - # We use OffscreenCanvas to produce PNG data instead of skia - skia_use_no_png_encode = true - skia_use_libpng_encode = false - - # skwasm_st doesn't use pthreads, but does pass the shared memory flag in order - # to be compatible with the way app modules import the memory object. - wasm_use_pthreads = false - wasm_shared_memory = true + wasm_use_workers = true wasm_prioritize_size = true } } @@ -133,20 +109,3 @@ copy("skwasm_group") { } outputs = [ "$root_out_dir/flutter_web_sdk/canvaskit/{{source_file_part}}" ] } - -copy("skwasm_st_group") { - visibility = [ "//flutter/web_sdk:*" ] - public_deps = [ "//flutter/lib/web_ui/skwasm:skwasm_st(:skwasm_st)" ] - - sources = [ - "$root_out_dir/skwasm_st/skwasm_st.js", - "$root_out_dir/skwasm_st/skwasm_st.js.symbols", - "$root_out_dir/skwasm_st/skwasm_st.wasm", - ] - if (is_debug) { - if (!wasm_use_dwarf) { - sources += [ "$root_out_dir/skwasm_st/skwasm_st.wasm.map" ] - } - } - outputs = [ "$root_out_dir/flutter_web_sdk/canvaskit/{{source_file_part}}" ] -} diff --git a/engine/src/flutter/web_sdk/BUILD.gn b/engine/src/flutter/web_sdk/BUILD.gn index 80f9067282..67a77da000 100644 --- a/engine/src/flutter/web_sdk/BUILD.gn +++ b/engine/src/flutter/web_sdk/BUILD.gn @@ -414,7 +414,6 @@ if (!is_fuchsia) { "//flutter/third_party/canvaskit:canvaskit_chromium_group", "//flutter/third_party/canvaskit:canvaskit_group", "//flutter/third_party/canvaskit:skwasm_group", - "//flutter/third_party/canvaskit:skwasm_st_group", ] } deps += [ "//flutter/lib/web_ui/flutter_js" ] @@ -439,9 +438,6 @@ if (!is_fuchsia) { "$root_out_dir/flutter_web_sdk/canvaskit/skwasm.js", "$root_out_dir/flutter_web_sdk/canvaskit/skwasm.js.symbols", "$root_out_dir/flutter_web_sdk/canvaskit/skwasm.wasm", - "$root_out_dir/flutter_web_sdk/canvaskit/skwasm_st.js", - "$root_out_dir/flutter_web_sdk/canvaskit/skwasm_st.js.symbols", - "$root_out_dir/flutter_web_sdk/canvaskit/skwasm_st.wasm", ] }