Skip to content

Commit

Permalink
Skwasm Renderer - initial implementation (#39072)
Browse files Browse the repository at this point in the history
Skwasm Renderer - initial implementation
  • Loading branch information
eyebrowsoffire committed Mar 2, 2023
1 parent f85e4c6 commit a749820
Show file tree
Hide file tree
Showing 52 changed files with 2,985 additions and 233 deletions.
52 changes: 52 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1937,7 +1937,24 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codecs.dart
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/services/serialization.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/image.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paragraph.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metrics.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path_metrics.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_picture.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/surface.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart + ../../../flutter/LICENSE
Expand Down Expand Up @@ -1978,6 +1995,15 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/text.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/tile_mode.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/ui.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/window.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/canvas.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/export.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/helpers.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/paint.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/path.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/picture.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/wrappers.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/runtime/dart_isolate.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/runtime/dart_isolate.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/runtime/dart_isolate_group_data.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -4436,7 +4462,24 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codecs.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/serialization.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/image.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paragraph.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metrics.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path_metrics.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_picture.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/surface.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart
Expand Down Expand Up @@ -4477,6 +4520,15 @@ FILE: ../../../flutter/lib/web_ui/lib/text.dart
FILE: ../../../flutter/lib/web_ui/lib/tile_mode.dart
FILE: ../../../flutter/lib/web_ui/lib/ui.dart
FILE: ../../../flutter/lib/web_ui/lib/window.dart
FILE: ../../../flutter/lib/web_ui/skwasm/canvas.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/export.h
FILE: ../../../flutter/lib/web_ui/skwasm/helpers.h
FILE: ../../../flutter/lib/web_ui/skwasm/paint.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/path.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/picture.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/surface.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/wrappers.h
FILE: ../../../flutter/runtime/dart_isolate.cc
FILE: ../../../flutter/runtime/dart_isolate.h
FILE: ../../../flutter/runtime/dart_isolate_group_data.cc
Expand Down
3 changes: 0 additions & 3 deletions common/config.gni
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ declare_args() {

# Whether to use a prebuilt Dart SDK instead of building one.
flutter_prebuilt_dart_sdk = false

# Whether to build the flutter web sdk outline/DDC artifacts.
flutter_build_web_sdk = false
}

# feature_defines_list ---------------------------------------------------------
Expand Down
50 changes: 21 additions & 29 deletions lib/web_ui/dev/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ import 'environment.dart';
import 'pipeline.dart';
import 'utils.dart';

const Map<String, String> targetAliases = <String, String>{
'sdk': 'flutter/web_sdk',
'web_sdk': 'flutter/web_sdk',
'canvaskit': 'flutter/third_party/canvaskit:canvaskit_group',
'canvaskit_chromium': 'flutter/third_party/canvaskit:canvaskit_chromium_group',
'skwasm': 'flutter/lib/web_ui/skwasm',
};

class BuildCommand extends Command<bool> with ArgUtils<bool> {
BuildCommand() {
argParser.addFlag(
Expand All @@ -21,16 +29,6 @@ class BuildCommand extends Command<bool> with ArgUtils<bool> {
help: 'Run the build in watch mode so it rebuilds whenever a change is '
'made. Disabled by default.',
);
argParser.addFlag(
'build-canvaskit',
help: 'Build CanvasKit locally instead of getting it from CIPD. Enabled '
'by default.',
defaultsTo: true
);
argParser.addFlag(
'build-canvaskit-chromium',
help: 'Build the Chromium variant of CanvasKit. Disabled by default.',
);
argParser.addFlag(
'host',
help: 'Build the host build instead of the wasm build, which is '
Expand All @@ -46,22 +44,19 @@ class BuildCommand extends Command<bool> with ArgUtils<bool> {

bool get isWatchMode => boolArg('watch');

bool get buildCanvasKit => boolArg('build-canvaskit');

bool get buildCanvasKitChromium => boolArg('build-canvaskit-chromium');

bool get host => boolArg('host');

List<String> get targets => argResults?.rest ?? <String>[];

@override
FutureOr<bool> run() async {
final FilePath libPath = FilePath.fromWebUi('lib');
final List<PipelineStep> steps = <PipelineStep>[
GnPipelineStep(
buildCanvasKit: buildCanvasKit,
buildCanvasKitChromium: buildCanvasKitChromium,
host: host,
GnPipelineStep(host: host),
NinjaPipelineStep(
buildDirectory: host ? environment.hostDebugUnoptDir : environment.wasmReleaseOutDir,
targets: targets.map((String target) => targetAliases[target] ?? target),
),
NinjaPipelineStep(target: host ? environment.hostDebugUnoptDir : environment.wasmReleaseOutDir),
];
final Pipeline buildPipeline = Pipeline(steps: steps);
await buildPipeline.run();
Expand All @@ -86,13 +81,9 @@ class BuildCommand extends Command<bool> with ArgUtils<bool> {
/// state. GN is pretty quick though, so it's OK to not support interruption.
class GnPipelineStep extends ProcessStep {
GnPipelineStep({
required this.buildCanvasKit,
required this.buildCanvasKitChromium,
required this.host,
});

final bool buildCanvasKit;
final bool buildCanvasKitChromium;
final bool host;

@override
Expand All @@ -111,8 +102,6 @@ class GnPipelineStep extends ProcessStep {
return <String>[
'--web',
'--runtime-mode=release',
if (buildCanvasKit) '--build-canvaskit',
if (buildCanvasKitChromium) '--build-canvaskit-chromium',
];
}
}
Expand All @@ -131,16 +120,18 @@ class GnPipelineStep extends ProcessStep {
///
/// Can be safely interrupted.
class NinjaPipelineStep extends ProcessStep {
NinjaPipelineStep({required this.target});
NinjaPipelineStep({required this.buildDirectory, required this.targets});

@override
String get description => 'ninja';

@override
bool get isSafeToInterrupt => true;

/// The target directory to build.
final Directory target;
/// The directory to build.
final Directory buildDirectory;

final Iterable<String> targets;

@override
Future<ProcessManager> createProcess() {
Expand All @@ -149,7 +140,8 @@ class NinjaPipelineStep extends ProcessStep {
'autoninja',
<String>[
'-C',
target.path,
buildDirectory.path,
...targets,
],
);
}
Expand Down
47 changes: 43 additions & 4 deletions lib/web_ui/dev/steps/compile_tests_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import '../utils.dart';
/// * test/ - compiled test code
/// * test_images/ - test images copied from Skis sources.
class CompileTestsStep implements PipelineStep {
CompileTestsStep({this.testFiles, this.useLocalCanvasKit = false, this.isWasm = false});
CompileTestsStep({
this.testFiles,
this.useLocalCanvasKit = false,
this.isWasm = false
});

final List<FilePath>? testFiles;
final bool isWasm;
Expand All @@ -46,6 +50,7 @@ class CompileTestsStep implements PipelineStep {
await environment.webUiBuildDir.create();
if (isWasm) {
await copyDart2WasmTestScript();
await copySkwasm();
}
await copyCanvasKitFiles(useLocalCanvasKit: useLocalCanvasKit);
await buildHostPage();
Expand Down Expand Up @@ -133,11 +138,36 @@ Future<void> copyDart2WasmTestScript() async {
environment.webUiDevDir.path,
'test_dart2wasm.js',
));
final io.Directory targetDir = io.Directory(pathlib.join(
final io.File targetFile = io.File(pathlib.join(
environment.webUiBuildDir.path,
'test_dart2wasm.js',
));
await sourceFile.copy(targetDir.path);
await sourceFile.copy(targetFile.path);
}

Future<void> copySkwasm() async {
final io.Directory targetDir = io.Directory(pathlib.join(
environment.webUiBuildDir.path,
'skwasm',
));

await targetDir.create(recursive: true);

for (final String fileName in <String>[
'skwasm.wasm',
'skwasm.js',
'skwasm.worker.js',
]) {
final io.File sourceFile = io.File(pathlib.join(
environment.wasmReleaseOutDir.path,
fileName,
));
final io.File targetFile = io.File(pathlib.join(
targetDir.path,
fileName,
));
await sourceFile.copy(targetFile.path);
}
}

final io.Directory _localCanvasKitDir = io.Directory(pathlib.join(
Expand Down Expand Up @@ -207,7 +237,7 @@ Future<void> copyCanvasKitFiles({bool useLocalCanvasKit = false}) async {
Future<void> compileTests(List<FilePath> testFiles, bool isWasm) async {
final Stopwatch stopwatch = Stopwatch()..start();

final TestsByRenderer sortedTests = sortTestsByRenderer(testFiles);
final TestsByRenderer sortedTests = sortTestsByRenderer(testFiles, isWasm);

await Future.wait(<Future<void>>[
if (sortedTests.htmlTests.isNotEmpty)
Expand Down Expand Up @@ -327,11 +357,13 @@ Future<bool> compileUnitTestToJS(FilePath input, {required Renderer renderer}) a
Future<bool> compileUnitTestToWasm(FilePath input, {required Renderer renderer}) async {
final String targetFileName = pathlib.join(
environment.webUiBuildDir.path,
getBuildDirForRenderer(renderer),
'${input.relativeToWebUi}.browser_test.dart.wasm',
);

final io.Directory directoryToTarget = io.Directory(pathlib.join(
environment.webUiBuildDir.path,
getBuildDirForRenderer(renderer),
pathlib.dirname(input.relativeToWebUi)));

if (!directoryToTarget.existsSync()) {
Expand All @@ -350,6 +382,13 @@ Future<bool> compileUnitTestToWasm(FilePath input, {required Renderer renderer})
'-DFLUTTER_WEB_AUTO_DETECT=false',
'-DFLUTTER_WEB_USE_SKIA=${renderer == Renderer.canvasKit}',
'-DFLUTTER_WEB_USE_SKWASM=${renderer == Renderer.skwasm}',

if (renderer == Renderer.skwasm)
...<String>[
'--import-shared-memory',
'--shared-memory-max-pages=32768',
],

input.relativeToWebUi, // current path.
targetFileName, // target path.
];
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/dev/steps/run_tests_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class RunTestsStep implements PipelineStep {
final SkiaGoldClient? skiaClient = await _createSkiaClient();
final List<FilePath> testFiles = this.testFiles ?? findAllTests();

final TestsByRenderer sortedTests = sortTestsByRenderer(testFiles);
final TestsByRenderer sortedTests = sortTestsByRenderer(testFiles, isWasm);

bool testsPassed = true;

Expand Down
19 changes: 18 additions & 1 deletion lib/web_ui/dev/test_dart2wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,27 @@ window.onload = async function () {
let dart2wasm_runtime;
let moduleInstance;
try {
const isSkwasm = link.hasAttribute('skwasm');
const imports = isSkwasm ? new Promise((resolve) => {
const skwasmScript = document.createElement('script');
skwasmScript.src = '/skwasm/skwasm.js';

document.body.appendChild(skwasmScript);
skwasmScript.addEventListener('load', async () => {
const skwasmInstance = await skwasm();
resolve({
"skwasm": skwasmInstance.asm,
"ffi": {
"memory": skwasmInstance.wasmMemory,
}
});
});
}) : {};

let baseName = link.href + '.browser_test.dart';
dart2wasm_runtime = await import(baseName + '.mjs');
const dartModulePromise = WebAssembly.compileStreaming(fetch(baseName + '.wasm'));
moduleInstance = await dart2wasm_runtime.instantiate(dartModulePromise, {});
moduleInstance = await dart2wasm_runtime.instantiate(dartModulePromise, imports);
} catch (exception) {
const message = `Failed to fetch and instantiate wasm module: ${exception}`;
sendLoadException(message);
Expand Down
19 changes: 17 additions & 2 deletions lib/web_ui/dev/test_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ import 'browser.dart';
import 'environment.dart' as env;
import 'utils.dart';

const Map<String, String> coopCoepHeaders = <String, String>{
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
};

/// Custom test platform that serves web engine unit tests.
class BrowserPlatform extends PlatformPlugin {
BrowserPlatform._({
Expand Down Expand Up @@ -472,10 +477,16 @@ class BrowserPlatform extends PlatformPlugin {
return shelf.Response.internalServerError(body: error);
}

final bool needsCoopCoep =
extension == '.js' ||
extension == '.mjs' ||
extension == '.html';
return shelf.Response.ok(
fileInBuild.readAsBytesSync(),
headers: <String, Object>{
HttpHeaders.contentTypeHeader: contentType,
if (needsCoopCoep && isWasm && renderer == Renderer.skwasm)
...coopCoepHeaders,
},
);
}
Expand All @@ -489,7 +500,7 @@ class BrowserPlatform extends PlatformPlugin {

// Link to the Dart wrapper.
final String scriptBase = htmlEscape.convert(p.basename(test));
final String link = '<link rel="x-dart-test" href="$scriptBase">';
final String link = '<link rel="x-dart-test" href="$scriptBase"${renderer == Renderer.skwasm ? " skwasm" : ""}>';

final String testRunner = isWasm ? '/test_dart2wasm.js' : 'packages/test/dart.js';

Expand All @@ -508,7 +519,11 @@ class BrowserPlatform extends PlatformPlugin {
<script src="$testRunner"></script>
</head>
</html>
''', headers: <String, String>{'Content-Type': 'text/html'});
''', headers: <String, String>{
'Content-Type': 'text/html',
if (isWasm && renderer == Renderer.skwasm)
...coopCoepHeaders
});
}

return shelf.Response.notFound('Not found.');
Expand Down

0 comments on commit a749820

Please sign in to comment.