[canvaskit] Add configuration option to force multi-Surface rendering (#163087)

Adds a configuration option `canvasKitForceMultiSurfaceRasterizer` and
associated environment variable
`FLUTTER_WEB_CANVASKIT_FORCE_MULTI_SURFACE_RASTERIZER` to force the
CanvasKit renderer to use `MultiSurfaceRasterizer`.

This allows us to easily create reproduction apps for
https://github.com/flutter/flutter/issues/162618 to show to the Chrome
team.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
Harry Terkelsen 2025-02-12 11:39:23 -08:00 committed by GitHub
parent 1023664651
commit 512d1d58ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 48 additions and 1 deletions

View File

@ -48,17 +48,27 @@ class CanvasKitRenderer implements Renderer {
Rasterizer _rasterizer = _createRasterizer();
static Rasterizer _createRasterizer() {
if (isSafari || isFirefox) {
if (configuration.canvasKitForceMultiSurfaceRasterizer || isSafari || isFirefox) {
return MultiSurfaceRasterizer();
}
return OffscreenCanvasRasterizer();
}
/// Resets the [Rasterizer] to the default value. Used in tests.
void debugResetRasterizer() {
_rasterizer = _createRasterizer();
}
/// Override the rasterizer with the given [_rasterizer]. Used in tests.
void debugOverrideRasterizer(Rasterizer testRasterizer) {
_rasterizer = testRasterizer;
}
/// Returns the current [Rasterizer]. Used in tests.
Rasterizer debugGetRasterizer() {
return _rasterizer;
}
set resourceCacheMaxBytes(int bytes) => _rasterizer.setResourceCacheMaxBytes(bytes);
/// A surface used specifically for `Picture.toImage` when software rendering

View File

@ -275,6 +275,13 @@ class FlutterConfiguration {
'FLUTTER_WEB_CANVASKIT_FORCE_CPU_ONLY',
);
bool get canvasKitForceMultiSurfaceRasterizer =>
_configuration?.canvasKitForceMultiSurfaceRasterizer ??
_defaultCanvasKitForceMultiSurfaceRasterizer;
static const bool _defaultCanvasKitForceMultiSurfaceRasterizer = bool.fromEnvironment(
'FLUTTER_WEB_CANVASKIT_FORCE_MULTI_SURFACE_RASTERIZER',
);
/// The maximum number of canvases to use when rendering in CanvasKit.
///
/// Limits the amount of overlays that can be created.
@ -370,6 +377,10 @@ extension JsFlutterConfigurationExtension on JsFlutterConfiguration {
external JSBoolean? get _canvasKitForceCpuOnly;
bool? get canvasKitForceCpuOnly => _canvasKitForceCpuOnly?.toDart;
@JS('canvasKitForceMultiSurfaceRasterizer')
external JSBoolean? get _canvasKitForceMultiSurfaceRasterizer;
bool? get canvasKitForceMultiSurfaceRasterizer => _canvasKitForceMultiSurfaceRasterizer?.toDart;
@JS('canvasKitMaximumSurfaces')
external JSNumber? get _canvasKitMaximumSurfaces;
double? get canvasKitMaximumSurfaces => _canvasKitMaximumSurfaces?.toDartDouble;

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:js_interop';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
@ -68,6 +70,10 @@ void testMain() {
group('Renderer', () {
setUpCanvasKitTest();
tearDown(() {
CanvasKitRenderer.instance.debugResetRasterizer();
});
test('always renders most recent picture and skips intermediate pictures', () async {
final TestRasterizer testRasterizer = TestRasterizer();
CanvasKitRenderer.instance.debugOverrideRasterizer(testRasterizer);
@ -175,5 +181,25 @@ void testMain() {
expect(treesRenderedInView3.first, treesToRenderInView3.first);
expect(treesRenderedInView3.last, treesToRenderInView3.last);
});
test(
'defaults to OffscreenCanvasRasterizer on Chrome and MultiSurfaceRasterizer on Firefox and Safari',
() {
if (isChromium) {
expect(CanvasKitRenderer.instance.debugGetRasterizer(), isA<OffscreenCanvasRasterizer>());
} else {
expect(CanvasKitRenderer.instance.debugGetRasterizer(), isA<MultiSurfaceRasterizer>());
}
},
);
test('can be configured to always use MultiSurfaceRasterizer', () {
debugOverrideJsConfiguration(
<String, Object?>{'canvasKitForceMultiSurfaceRasterizer': true}.jsify()
as JsFlutterConfiguration?,
);
CanvasKitRenderer.instance.debugResetRasterizer();
expect(CanvasKitRenderer.instance.debugGetRasterizer(), isA<MultiSurfaceRasterizer>());
});
});
}