Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 6d54e22

Browse files
[canvaskit] Add configuration for maximum canvases (#51735)
Allows developers to customize the maximum amount of overlay canvases. Fixes flutter/flutter#144589 ## 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] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [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/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent 35b6c7b commit 6d54e22

File tree

5 files changed

+91
-6
lines changed

5 files changed

+91
-6
lines changed

lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'dart:math' as math;
55

66
import 'package:ui/ui.dart' as ui;
77

8-
import '../../engine.dart' show PlatformViewManager, longestIncreasingSubsequence;
8+
import '../../engine.dart' show PlatformViewManager, configuration, longestIncreasingSubsequence;
99
import '../display.dart';
1010
import '../dom.dart';
1111
import '../html/path_to_svg_clip.dart';
@@ -49,7 +49,7 @@ class HtmlViewEmbedder {
4949

5050
/// The maximum number of render canvases to create. Too many canvases can
5151
/// cause a performance burden.
52-
static const int maximumCanvases = 8;
52+
static int get maximumCanvases => configuration.canvasKitMaximumSurfaces;
5353

5454
/// The views that need to be recomposited into the scene on the next frame.
5555
final Set<int> _viewsToRecomposite = <int>{};
@@ -478,7 +478,7 @@ class HtmlViewEmbedder {
478478
final List<RenderingEntity> modifiedEntities =
479479
List<RenderingEntity>.from(rendering.entities);
480480
bool sawLastCanvas = false;
481-
for (int i = rendering.entities.length - 1; i > 0; i--) {
481+
for (int i = rendering.entities.length - 1; i >= 0; i--) {
482482
final RenderingEntity entity = modifiedEntities[i];
483483
if (entity is RenderingRenderCanvas) {
484484
if (!sawLastCanvas) {

lib/web_ui/lib/src/engine/configuration.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,18 @@ class FlutterConfiguration {
271271
'FLUTTER_WEB_CANVASKIT_FORCE_CPU_ONLY',
272272
);
273273

274+
/// The maximum number of canvases to use when rendering in CanvasKit.
275+
///
276+
/// Limits the amount of overlays that can be created.
277+
int get canvasKitMaximumSurfaces {
278+
final int maxSurfaces =
279+
_configuration?.canvasKitMaximumSurfaces?.toInt() ?? 8;
280+
if (maxSurfaces < 1) {
281+
return 1;
282+
}
283+
return maxSurfaces;
284+
}
285+
274286
/// Set this flag to `true` to cause the engine to visualize the semantics tree
275287
/// on the screen for debugging.
276288
///
@@ -361,6 +373,11 @@ extension JsFlutterConfigurationExtension on JsFlutterConfiguration {
361373
external JSBoolean? get _canvasKitForceCpuOnly;
362374
bool? get canvasKitForceCpuOnly => _canvasKitForceCpuOnly?.toDart;
363375

376+
@JS('canvasKitMaximumSurfaces')
377+
external JSNumber? get _canvasKitMaximumSurfaces;
378+
double? get canvasKitMaximumSurfaces =>
379+
_canvasKitMaximumSurfaces?.toDartDouble;
380+
364381
@JS('debugShowSemanticsNodes')
365382
external JSBoolean? get _debugShowSemanticsNodes;
366383
bool? get debugShowSemanticsNodes => _debugShowSemanticsNodes?.toDart;

lib/web_ui/test/canvaskit/embedded_views_test.dart

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6+
import 'dart:js_interop';
67

78
import 'package:test/bootstrap/browser.dart';
89
import 'package:test/test.dart';
@@ -1119,7 +1120,7 @@ void testMain() {
11191120
]);
11201121
});
11211122

1122-
test('optimized overlays correctly with transforms and clips', () async {
1123+
test('optimizes overlays correctly with transforms and clips', () async {
11231124
ui_web.platformViewRegistry.registerViewFactory(
11241125
'test-view',
11251126
(int viewId) => createDomHTMLDivElement()..className = 'platform-view',
@@ -1152,6 +1153,73 @@ void testMain() {
11521153
_platformView,
11531154
]);
11541155
});
1156+
1157+
test('can customize amount of overlays', () async {
1158+
final CkPicture testPicture =
1159+
paintPicture(const ui.Rect.fromLTRB(0, 0, 10, 10), (CkCanvas canvas) {
1160+
canvas.drawCircle(const ui.Offset(5, 5), 5, CkPaint());
1161+
});
1162+
1163+
// Initialize all platform views to be used in the test.
1164+
final List<int> platformViewIds = <int>[];
1165+
for (int i = 0; i < 16; i++) {
1166+
ui_web.platformViewRegistry.registerViewFactory(
1167+
'test-platform-view',
1168+
(int viewId) => createDomHTMLDivElement()..id = 'view-$i',
1169+
);
1170+
await createPlatformView(i, 'test-platform-view');
1171+
platformViewIds.add(i);
1172+
}
1173+
1174+
Future<void> renderTestScene({required int viewCount}) async {
1175+
final LayerSceneBuilder sb = LayerSceneBuilder();
1176+
sb.pushOffset(0, 0);
1177+
for (int i = 0; i < viewCount; i++) {
1178+
sb.addPicture(ui.Offset.zero, testPicture);
1179+
sb.addPlatformView(i, width: 10, height: 10);
1180+
}
1181+
await renderScene(sb.build());
1182+
}
1183+
1184+
// Set maximum overlays to 4.
1185+
debugOverrideJsConfiguration(<String, Object?>{
1186+
'canvasKitMaximumSurfaces': 4,
1187+
}.jsify() as JsFlutterConfiguration?);
1188+
1189+
await renderTestScene(viewCount: 8);
1190+
_expectSceneMatches(<_EmbeddedViewMarker>[
1191+
_overlay,
1192+
_platformView,
1193+
_overlay,
1194+
_platformView,
1195+
_overlay,
1196+
_platformView,
1197+
_platformView,
1198+
_platformView,
1199+
_platformView,
1200+
_platformView,
1201+
_overlay,
1202+
_platformView,
1203+
]);
1204+
1205+
// Set maximum overlays to -1. Should default to 1.
1206+
debugOverrideJsConfiguration(<String, Object?>{
1207+
'canvasKitMaximumSurfaces': -1,
1208+
}.jsify() as JsFlutterConfiguration?);
1209+
1210+
await renderTestScene(viewCount: 8);
1211+
_expectSceneMatches(<_EmbeddedViewMarker>[
1212+
_platformView,
1213+
_platformView,
1214+
_platformView,
1215+
_platformView,
1216+
_platformView,
1217+
_platformView,
1218+
_platformView,
1219+
_overlay,
1220+
_platformView,
1221+
]);
1222+
});
11551223
});
11561224
}
11571225

lib/web_ui/test/canvaskit/initialization/stores_config_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ void testMain() {
2020
// A property under test, that we'll try to read later.
2121
js_util.setProperty(config, 'nonce', 'some_nonce');
2222
// A non-existing property to verify our js-interop doesn't crash.
23-
js_util.setProperty(config, 'canvasKitMaximumSurfaces', 32.0);
23+
js_util.setProperty(config, 'nonexistentProperty', 32.0);
2424

2525
// Remove window.flutterConfiguration (if it's there)
2626
js_util.setProperty(domWindow, 'flutterConfiguration', null);

lib/web_ui/test/engine/configuration_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void testMain() {
6767
expect(() {
6868
config.setUserConfiguration(
6969
js_util.jsify(<String, Object?>{
70-
'canvasKitMaximumSurfaces': 32.0,
70+
'nonexistentProperty': 32.0,
7171
}) as JsFlutterConfiguration);
7272
}, returnsNormally);
7373
});

0 commit comments

Comments
 (0)