Skip to content

Commit b2a4a05

Browse files
[skwasm] Dynamic Threading (#164748)
This switches skwasm over from the emscripten pthreads implementation to emscripten's "wasm workers" threading implementation. The pthreads implementation simply will not run at all in a non-crossOriginIsolated context, but the wasm workers implementation only fails if we actually attempt to spawn a thread. This means we can actually choose whether to use a single-threaded or multi-threaded strategy at runtime, which means we don't have to build two variants of skwasm for single- vs multi-threaded.
1 parent d6c4153 commit b2a4a05

File tree

16 files changed

+205
-309
lines changed

16 files changed

+205
-309
lines changed

engine/src/build/config/compiler/BUILD.gn

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,9 @@ config("compiler") {
277277
}
278278

279279
if (is_wasm) {
280-
if (wasm_use_pthreads) {
281-
cflags += [ "-pthread" ]
282-
ldflags += [ "-pthread" ]
280+
if (wasm_use_workers) {
281+
cflags += [ "-sWASM_WORKERS=1" ]
282+
ldflags += [ "-sWASM_WORKERS=1" ]
283283
} if (wasm_shared_memory) {
284284
cflags += [ "-sSHARED_MEMORY=1" ]
285285
ldflags += [ "-sSHARED_MEMORY=1" ]
@@ -396,12 +396,12 @@ config("compiler") {
396396
# to say that it does. Define them here instead.
397397
defines += [ "HAVE_SYS_UIO_H" ]
398398

399-
# When Android requires new flags consider also editing the flags in
400-
# the following locations.
399+
# When Android requires new flags consider also editing the flags in
400+
# the following locations.
401401
# Framework plugin_ffi template: packages/flutter_tools/templates/plugin_ffi/src.tmpl/CMakeLists.txt.tmpl
402402
# Example PR: https://github.com/flutter/flutter/pull/155508
403-
# Dart Lang JNI package: pkgs/jni/src/CMakeLists.txt
404-
# Example PR: https://github.com/dart-lang/native/pull/1615
403+
# Dart Lang JNI package: pkgs/jni/src/CMakeLists.txt
404+
# Example PR: https://github.com/dart-lang/native/pull/1615
405405
ldflags += [
406406
"-Wl,--no-undefined",
407407
"-Wl,--exclude-libs,ALL",

engine/src/build/toolchain/wasm.gni

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ declare_args() {
1111
# The location of an activated embedded emsdk.
1212
emsdk_dir = rebase_path("//flutter/prebuilts/emsdk")
1313

14-
wasm_use_pthreads = false
14+
wasm_use_workers = false
1515
wasm_shared_memory = false
1616
wasm_use_dwarf = false
1717
}

engine/src/flutter/ci/licenses_golden/licenses_flutter

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42726,8 +42726,6 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/filters.cpp + ../../../flutter/LICENS
4272642726
ORIGIN: ../../../flutter/lib/web_ui/skwasm/fonts.cpp + ../../../flutter/LICENSE
4272742727
ORIGIN: ../../../flutter/lib/web_ui/skwasm/helpers.h + ../../../flutter/LICENSE
4272842728
ORIGIN: ../../../flutter/lib/web_ui/skwasm/image.cpp + ../../../flutter/LICENSE
42729-
ORIGIN: ../../../flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js + ../../../flutter/LICENSE
42730-
ORIGIN: ../../../flutter/lib/web_ui/skwasm/library_skwasm_single_threaded.js + ../../../flutter/LICENSE
4273142729
ORIGIN: ../../../flutter/lib/web_ui/skwasm/library_skwasm_support.js + ../../../flutter/LICENSE
4273242730
ORIGIN: ../../../flutter/lib/web_ui/skwasm/paint.cpp + ../../../flutter/LICENSE
4273342731
ORIGIN: ../../../flutter/lib/web_ui/skwasm/path.cpp + ../../../flutter/LICENSE
@@ -42737,8 +42735,6 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/skwasm_support.h + ../../../flutter/L
4273742735
ORIGIN: ../../../flutter/lib/web_ui/skwasm/string.cpp + ../../../flutter/LICENSE
4273842736
ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.cpp + ../../../flutter/LICENSE
4273942737
ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.h + ../../../flutter/LICENSE
42740-
ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface_mt.cpp + ../../../flutter/LICENSE
42741-
ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface_st.cpp + ../../../flutter/LICENSE
4274242738
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/line_metrics.cpp + ../../../flutter/LICENSE
4274342739
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph.cpp + ../../../flutter/LICENSE
4274442740
ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp + ../../../flutter/LICENSE
@@ -45696,8 +45692,6 @@ FILE: ../../../flutter/lib/web_ui/skwasm/filters.cpp
4569645692
FILE: ../../../flutter/lib/web_ui/skwasm/fonts.cpp
4569745693
FILE: ../../../flutter/lib/web_ui/skwasm/helpers.h
4569845694
FILE: ../../../flutter/lib/web_ui/skwasm/image.cpp
45699-
FILE: ../../../flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js
45700-
FILE: ../../../flutter/lib/web_ui/skwasm/library_skwasm_single_threaded.js
4570145695
FILE: ../../../flutter/lib/web_ui/skwasm/library_skwasm_support.js
4570245696
FILE: ../../../flutter/lib/web_ui/skwasm/paint.cpp
4570345697
FILE: ../../../flutter/lib/web_ui/skwasm/path.cpp
@@ -45707,8 +45701,6 @@ FILE: ../../../flutter/lib/web_ui/skwasm/skwasm_support.h
4570745701
FILE: ../../../flutter/lib/web_ui/skwasm/string.cpp
4570845702
FILE: ../../../flutter/lib/web_ui/skwasm/surface.cpp
4570945703
FILE: ../../../flutter/lib/web_ui/skwasm/surface.h
45710-
FILE: ../../../flutter/lib/web_ui/skwasm/surface_mt.cpp
45711-
FILE: ../../../flutter/lib/web_ui/skwasm/surface_st.cpp
4571245704
FILE: ../../../flutter/lib/web_ui/skwasm/text/line_metrics.cpp
4571345705
FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph.cpp
4571445706
FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp

engine/src/flutter/lib/web_ui/dev/steps/copy_artifacts_step.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,13 @@ class CopyArtifactsStep implements PipelineStep {
7676
final String canvaskitSourceDirectory;
7777
final String canvaskitChromiumSourceDirectory;
7878
final String skwasmSourceDirectory;
79-
final String skwasmStSourceDirectory;
8079
switch (source) {
8180
case LocalArtifactSource(:final mode):
8281
final buildDirectory = getBuildDirectoryForRuntimeMode(mode).path;
8382
flutterJsSourceDirectory = pathlib.join(buildDirectory, 'flutter_web_sdk', 'flutter_js');
8483
canvaskitSourceDirectory = pathlib.join(buildDirectory, 'canvaskit');
8584
canvaskitChromiumSourceDirectory = pathlib.join(buildDirectory, 'canvaskit_chromium');
8685
skwasmSourceDirectory = pathlib.join(buildDirectory, 'skwasm');
87-
skwasmStSourceDirectory = pathlib.join(buildDirectory, 'skwasm_st');
8886

8987
case GcsArtifactSource(:final realm):
9088
final artifactsDirectory = (await _downloadArtifacts(realm)).path;
@@ -96,7 +94,6 @@ class CopyArtifactsStep implements PipelineStep {
9694
'chromium',
9795
);
9896
skwasmSourceDirectory = pathlib.join(artifactsDirectory, 'canvaskit');
99-
skwasmStSourceDirectory = pathlib.join(artifactsDirectory, 'canvaskit');
10097
}
10198

10299
await environment.webTestsArtifactsDir.create(recursive: true);
@@ -116,7 +113,6 @@ class CopyArtifactsStep implements PipelineStep {
116113
if (artifactDeps.skwasm) {
117114
copied.add('Skwasm');
118115
await copyWasmLibrary('skwasm', skwasmSourceDirectory, 'canvaskit');
119-
await copyWasmLibrary('skwasm_st', skwasmStSourceDirectory, 'canvaskit');
120116
}
121117
print('Copied artifacts: ${copied.join(', ')}');
122118
}

engine/src/flutter/lib/web_ui/flutter_js/src/skwasm_loader.js

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,64 @@ import { createWasmInstantiator } from "./instantiate_wasm.js";
66
import { resolveUrlWithSegments } from "./utils.js";
77

88
export const loadSkwasm = async (deps, config, browserEnvironment, baseUrl) => {
9-
const fileStem = (browserEnvironment.crossOriginIsolated && !config.forceSingleThreadedSkwasm) ? "skwasm" : "skwasm_st";
10-
const rawSkwasmUrl = resolveUrlWithSegments(baseUrl, `${fileStem}.js`)
9+
const rawSkwasmUrl = resolveUrlWithSegments(baseUrl, 'skwasm.js')
1110
let skwasmUrl = rawSkwasmUrl;
1211
if (deps.flutterTT.policy) {
1312
skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl);
1413
}
15-
const wasmInstantiator = createWasmInstantiator(resolveUrlWithSegments(baseUrl, `${fileStem}.wasm`));
14+
const wasmInstantiator = createWasmInstantiator(resolveUrlWithSegments(baseUrl, 'skwasm.wasm'));
1615
const skwasm = await import(skwasmUrl);
1716
return await skwasm.default({
17+
skwasmSingleThreaded: !browserEnvironment.crossOriginIsolated || config.forceSingleThreadedSkwasm,
1818
instantiateWasm: wasmInstantiator,
19-
// When hosted via a CDN or some other url that is not the same
20-
// origin as the main script of the page, we will fail to create
21-
// a web worker with the bootstrapping script. This workaround will
22-
// make sure that the worker JS can be loaded regardless of where
23-
// it is hosted.
24-
mainScriptUrlOrBlob: new Blob(
25-
[`import '${skwasmUrl}'`],
26-
{ 'type': 'application/javascript' },
27-
),
19+
locateFile: (filename, scriptDirectory) => {
20+
// The wasm workers API has a separate .ww.js file that bootstraps the
21+
// web worker. However, it turns out this worker bootstrapper doesn't
22+
// actually work with ES6 modules, which we have enabled. So we instead
23+
// pass our own bootstrapper that loads skwasm.js as an ES6 module, and
24+
// queues/flushes pending messages that were received during the
25+
// asynchronous load.
26+
if (filename.endsWith('.ww.js')) {
27+
const url = resolveUrlWithSegments(baseUrl, filename);
28+
return URL.createObjectURL(new Blob(
29+
[`
30+
"use strict";
31+
32+
let eventListener;
33+
eventListener = (message) => {
34+
const pendingMessages = [];
35+
const data = message.data;
36+
data["instantiateWasm"] = (info,receiveInstance) => {
37+
const instance = new WebAssembly.Instance(data["wasm"], info);
38+
return receiveInstance(instance, data["wasm"])
39+
};
40+
import(data.js).then(async (skwasm) => {
41+
await skwasm.default(data);
42+
43+
removeEventListener("message", eventListener);
44+
for (const message of pendingMessages) {
45+
dispatchEvent(message);
46+
}
47+
});
48+
console.log("removing initial listener");
49+
removeEventListener("message", eventListener);
50+
eventListener = (message) => {
51+
52+
pendingMessages.push(message);
53+
};
54+
55+
addEventListener("message", eventListener);
56+
};
57+
addEventListener("message", eventListener);
58+
`
59+
],
60+
{ 'type': 'application/javascript' }));
61+
}
62+
return url;
63+
},
64+
// Because of the above workaround, the worker is just a blob and
65+
// can't locate the main script using a relative path to itself,
66+
// so we pass the main script location in.
67+
mainScriptUrlOrBlob: rawSkwasmUrl,
2868
});
2969
}

engine/src/flutter/lib/web_ui/skwasm/BUILD.gn

Lines changed: 57 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,96 +4,69 @@
44

55
import("//build/toolchain/wasm.gni")
66

7-
template("skwasm_variant") {
8-
wasm_lib(target_name) {
9-
public_configs = [ "//flutter:config" ]
7+
wasm_lib("skwasm") {
8+
public_configs = [ "//flutter:config" ]
109

11-
sources = [
12-
"canvas.cpp",
13-
"contour_measure.cpp",
14-
"data.cpp",
15-
"export.h",
16-
"filters.cpp",
17-
"fonts.cpp",
18-
"helpers.h",
19-
"image.cpp",
20-
"paint.cpp",
21-
"path.cpp",
22-
"picture.cpp",
23-
"shaders.cpp",
24-
"skwasm_support.h",
25-
"string.cpp",
26-
"surface.cpp",
27-
"text/line_metrics.cpp",
28-
"text/paragraph.cpp",
29-
"text/paragraph_builder.cpp",
30-
"text/paragraph_style.cpp",
31-
"text/strut_style.cpp",
32-
"text/text_style.cpp",
33-
"vertices.cpp",
34-
"wrappers.h",
35-
]
36-
37-
cflags = [ "-mreference-types" ]
38-
39-
ldflags = [
40-
"-std=c++20",
41-
"-lGL",
42-
"-sUSE_WEBGL2=1",
43-
"-sMAX_WEBGL_VERSION=2",
44-
"-sOFFSCREENCANVAS_SUPPORT",
45-
"-sALLOW_MEMORY_GROWTH",
46-
"-sALLOW_TABLE_GROWTH",
47-
"-lexports.js",
48-
"-sEXPORTED_FUNCTIONS=[stackAlloc]",
49-
"-sEXPORTED_RUNTIME_METHODS=[addFunction,wasmExports,wasmMemory,stackAlloc]",
50-
"-sINCOMING_MODULE_JS_API=[instantiateWasm,noExitRuntime,mainScriptUrlOrBlob]",
51-
"-sUSE_ES6_IMPORT_META=0",
52-
"--js-library",
53-
rebase_path("library_skwasm_support.js"),
54-
]
10+
sources = [
11+
"canvas.cpp",
12+
"contour_measure.cpp",
13+
"data.cpp",
14+
"export.h",
15+
"filters.cpp",
16+
"fonts.cpp",
17+
"helpers.h",
18+
"image.cpp",
19+
"paint.cpp",
20+
"path.cpp",
21+
"picture.cpp",
22+
"shaders.cpp",
23+
"skwasm_support.h",
24+
"string.cpp",
25+
"surface.cpp",
26+
"text/line_metrics.cpp",
27+
"text/paragraph.cpp",
28+
"text/paragraph_builder.cpp",
29+
"text/paragraph_style.cpp",
30+
"text/strut_style.cpp",
31+
"text/text_style.cpp",
32+
"vertices.cpp",
33+
"wrappers.h",
34+
]
5535

56-
inputs = [ rebase_path("library_skwasm_support.js") ]
36+
cflags = [ "-mreference-types" ]
5737

58-
if (invoker.multi_threaded) {
59-
sources += [ "surface_mt.cpp" ]
60-
ldflags += [
61-
"-sPTHREAD_POOL_SIZE=1",
62-
"-Wno-pthreads-mem-growth",
63-
"--js-library",
64-
rebase_path("library_skwasm_multi_threaded.js"),
65-
]
66-
inputs += [ rebase_path("library_skwasm_multi_threaded.js") ]
67-
} else {
68-
sources += [ "surface_st.cpp" ]
69-
ldflags += [
70-
"--js-library",
71-
rebase_path("library_skwasm_single_threaded.js"),
72-
]
73-
inputs += [ rebase_path("library_skwasm_single_threaded.js") ]
74-
}
38+
ldflags = [
39+
"-std=c++20",
40+
"-lGL",
41+
"-sUSE_WEBGL2=1",
42+
"-sMAX_WEBGL_VERSION=2",
43+
"-sOFFSCREENCANVAS_SUPPORT",
44+
"-sALLOW_MEMORY_GROWTH",
45+
"-sALLOW_TABLE_GROWTH",
46+
"-lexports.js",
47+
"-sEXPORTED_FUNCTIONS=[stackAlloc]",
48+
"-sEXPORTED_RUNTIME_METHODS=[addFunction,wasmExports,wasmMemory,stackAlloc]",
49+
"-sINCOMING_MODULE_JS_API=[instantiateWasm,locateFile,noExitRuntime,mainScriptUrlOrBlob,wasmMemory,wasm,skwasmSingleThreaded]",
50+
"-sUSE_ES6_IMPORT_META=0",
51+
"--js-library",
52+
rebase_path("library_skwasm_support.js"),
53+
]
7554

76-
if (is_debug) {
77-
ldflags += [
78-
"-sASSERTIONS=1",
79-
"-sGL_ASSERTIONS=1",
80-
]
81-
} else {
82-
ldflags += [ "--closure=1" ]
83-
}
55+
inputs = [ rebase_path("library_skwasm_support.js") ]
8456

85-
deps = [
86-
"//flutter/skia",
87-
"//flutter/skia/modules/skparagraph",
88-
"//flutter/skia/modules/skunicode",
57+
if (is_debug) {
58+
ldflags += [
59+
"-sASSERTIONS=1",
60+
"-sGL_ASSERTIONS=1",
61+
"-sSTACK_OVERFLOW_CHECK=2",
8962
]
63+
} else {
64+
ldflags += [ "--closure=1" ]
9065
}
91-
}
92-
93-
skwasm_variant("skwasm") {
94-
multi_threaded = true
95-
}
9666

97-
skwasm_variant("skwasm_st") {
98-
multi_threaded = false
67+
deps = [
68+
"//flutter/skia",
69+
"//flutter/skia/modules/skparagraph",
70+
"//flutter/skia/modules/skunicode",
71+
]
9972
}

engine/src/flutter/lib/web_ui/skwasm/library_skwasm_multi_threaded.js

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)