From c34bac7b63265b64a85e7cdd900e1b0cdffa55d1 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Wed, 27 Mar 2024 16:50:41 -0700 Subject: [PATCH 1/3] Add configuration for maximum canvases in CanvasKit --- .../src/engine/canvaskit/embedded_views.dart | 7 +- lib/web_ui/lib/src/engine/configuration.dart | 16 +++++ .../test/canvaskit/embedded_views_test.dart | 70 ++++++++++++++++++- .../initialization/stores_config_test.dart | 2 +- .../test/engine/configuration_test.dart | 2 +- 5 files changed, 91 insertions(+), 6 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 846107d4ad038..1767e990865a9 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -5,7 +5,8 @@ import 'dart:math' as math; import 'package:ui/ui.dart' as ui; -import '../../engine.dart' show PlatformViewManager, longestIncreasingSubsequence; +import '../../engine.dart' + show PlatformViewManager, configuration, longestIncreasingSubsequence; import '../display.dart'; import '../dom.dart'; import '../html/path_to_svg_clip.dart'; @@ -49,7 +50,7 @@ class HtmlViewEmbedder { /// The maximum number of render canvases to create. Too many canvases can /// cause a performance burden. - static const int maximumCanvases = 8; + static int get maximumCanvases => configuration.canvasKitMaximumSurfaces; /// The views that need to be recomposited into the scene on the next frame. final Set _viewsToRecomposite = {}; @@ -478,7 +479,7 @@ class HtmlViewEmbedder { final List modifiedEntities = List.from(rendering.entities); bool sawLastCanvas = false; - for (int i = rendering.entities.length - 1; i > 0; i--) { + for (int i = rendering.entities.length - 1; i >= 0; i--) { final RenderingEntity entity = modifiedEntities[i]; if (entity is RenderingRenderCanvas) { if (!sawLastCanvas) { diff --git a/lib/web_ui/lib/src/engine/configuration.dart b/lib/web_ui/lib/src/engine/configuration.dart index 5591598795f64..d444f7942bfb1 100644 --- a/lib/web_ui/lib/src/engine/configuration.dart +++ b/lib/web_ui/lib/src/engine/configuration.dart @@ -271,6 +271,17 @@ class FlutterConfiguration { 'FLUTTER_WEB_CANVASKIT_FORCE_CPU_ONLY', ); + /// The maximum number of canvases to use when rendering in CanvasKit. + /// + /// Limits the amount of overlays that can be created. + int get canvasKitMaximumSurfaces { + int maxSurfaces = _configuration?.canvasKitMaximumSurfaces?.toInt() ?? 8; + if (maxSurfaces < 1) { + return 1; + } + return maxSurfaces; + } + /// Set this flag to `true` to cause the engine to visualize the semantics tree /// on the screen for debugging. /// @@ -361,6 +372,11 @@ extension JsFlutterConfigurationExtension on JsFlutterConfiguration { external JSBoolean? get _canvasKitForceCpuOnly; bool? get canvasKitForceCpuOnly => _canvasKitForceCpuOnly?.toDart; + @JS('canvasKitMaximumSurfaces') + external JSNumber? get _canvasKitMaximumSurfaces; + double? get canvasKitMaximumSurfaces => + _canvasKitMaximumSurfaces?.toDartDouble; + @JS('debugShowSemanticsNodes') external JSBoolean? get _debugShowSemanticsNodes; bool? get debugShowSemanticsNodes => _debugShowSemanticsNodes?.toDart; diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index 1b0d76249d393..5d1ba41265f55 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:js_interop'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; @@ -1119,7 +1120,7 @@ void testMain() { ]); }); - test('optimized overlays correctly with transforms and clips', () async { + test('optimizes overlays correctly with transforms and clips', () async { ui_web.platformViewRegistry.registerViewFactory( 'test-view', (int viewId) => createDomHTMLDivElement()..className = 'platform-view', @@ -1152,6 +1153,73 @@ void testMain() { _platformView, ]); }); + + test('can customize amount of overlays', () async { + final CkPicture testPicture = + paintPicture(const ui.Rect.fromLTRB(0, 0, 10, 10), (CkCanvas canvas) { + canvas.drawCircle(const ui.Offset(5, 5), 5, CkPaint()); + }); + + // Initialize all platform views to be used in the test. + final List platformViewIds = []; + for (int i = 0; i < 16; i++) { + ui_web.platformViewRegistry.registerViewFactory( + 'test-platform-view', + (int viewId) => createDomHTMLDivElement()..id = 'view-$i', + ); + await createPlatformView(i, 'test-platform-view'); + platformViewIds.add(i); + } + + Future renderTestScene({required int viewCount}) async { + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + for (int i = 0; i < viewCount; i++) { + sb.addPicture(ui.Offset.zero, testPicture); + sb.addPlatformView(i, width: 10, height: 10); + } + await renderScene(sb.build()); + } + + // Set maximum overlays to 4. + debugOverrideJsConfiguration({ + 'canvasKitMaximumSurfaces': 4, + }.jsify() as JsFlutterConfiguration?); + + await renderTestScene(viewCount: 8); + _expectSceneMatches(<_EmbeddedViewMarker>[ + _overlay, + _platformView, + _overlay, + _platformView, + _overlay, + _platformView, + _platformView, + _platformView, + _platformView, + _platformView, + _overlay, + _platformView, + ]); + + // Set maximum overlays to -1. Should default to 1. + debugOverrideJsConfiguration({ + 'canvasKitMaximumSurfaces': -1, + }.jsify() as JsFlutterConfiguration?); + + await renderTestScene(viewCount: 8); + _expectSceneMatches(<_EmbeddedViewMarker>[ + _platformView, + _platformView, + _platformView, + _platformView, + _platformView, + _platformView, + _platformView, + _overlay, + _platformView, + ]); + }); }); } diff --git a/lib/web_ui/test/canvaskit/initialization/stores_config_test.dart b/lib/web_ui/test/canvaskit/initialization/stores_config_test.dart index e708471d4ef65..1955f8009be34 100644 --- a/lib/web_ui/test/canvaskit/initialization/stores_config_test.dart +++ b/lib/web_ui/test/canvaskit/initialization/stores_config_test.dart @@ -20,7 +20,7 @@ void testMain() { // A property under test, that we'll try to read later. js_util.setProperty(config, 'nonce', 'some_nonce'); // A non-existing property to verify our js-interop doesn't crash. - js_util.setProperty(config, 'canvasKitMaximumSurfaces', 32.0); + js_util.setProperty(config, 'nonexistentProperty', 32.0); // Remove window.flutterConfiguration (if it's there) js_util.setProperty(domWindow, 'flutterConfiguration', null); diff --git a/lib/web_ui/test/engine/configuration_test.dart b/lib/web_ui/test/engine/configuration_test.dart index 60eca6cab9424..24f748f42f3ef 100644 --- a/lib/web_ui/test/engine/configuration_test.dart +++ b/lib/web_ui/test/engine/configuration_test.dart @@ -67,7 +67,7 @@ void testMain() { expect(() { config.setUserConfiguration( js_util.jsify({ - 'canvasKitMaximumSurfaces': 32.0, + 'nonexistentProperty': 32.0, }) as JsFlutterConfiguration); }, returnsNormally); }); From 93d58397075b62d879ab09d8b2117ce0866999ac Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Wed, 27 Mar 2024 16:58:29 -0700 Subject: [PATCH 2/3] FIx import --- lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 1767e990865a9..0bbfe359395a1 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -5,8 +5,7 @@ import 'dart:math' as math; import 'package:ui/ui.dart' as ui; -import '../../engine.dart' - show PlatformViewManager, configuration, longestIncreasingSubsequence; +import '../../engine.dart' show PlatformViewManager, configuration, longestIncreasingSubsequence; import '../display.dart'; import '../dom.dart'; import '../html/path_to_svg_clip.dart'; From 47daa7e6eb4b96acf18aecffbfdccddd2c00975c Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 28 Mar 2024 15:44:44 -0700 Subject: [PATCH 3/3] Fix analysis error --- lib/web_ui/lib/src/engine/configuration.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/configuration.dart b/lib/web_ui/lib/src/engine/configuration.dart index d444f7942bfb1..57b3dca4a39b4 100644 --- a/lib/web_ui/lib/src/engine/configuration.dart +++ b/lib/web_ui/lib/src/engine/configuration.dart @@ -275,7 +275,8 @@ class FlutterConfiguration { /// /// Limits the amount of overlays that can be created. int get canvasKitMaximumSurfaces { - int maxSurfaces = _configuration?.canvasKitMaximumSurfaces?.toInt() ?? 8; + final int maxSurfaces = + _configuration?.canvasKitMaximumSurfaces?.toInt() ?? 8; if (maxSurfaces < 1) { return 1; }