diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_child_layers.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_child_layers.dart new file mode 100644 index 00000000000..56672a075ba --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_child_layers.dart @@ -0,0 +1,90 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'recorder.dart'; + +/// Repeatedly paints a grid of rectangles where each rectangle is drawn in its +/// own [Picture]. +/// +/// Measures the performance of updating many layers. For example, the HTML +/// rendering backend attempts to reuse the DOM nodes created for engine layers. +/// +/// See also `bench_draw_rect.dart`, which draws nearly identical UI but puts all +/// rectangles into the same picture. +class BenchUpdateManyChildLayers extends SceneBuilderRecorder { + BenchUpdateManyChildLayers() : super(name: benchmarkName); + + static const String benchmarkName = 'bench_update_many_child_layers'; + + /// Number of rows in the grid. + static const int kRows = 32; + + /// Number of columns in the grid. + static const int kColumns = 32; + + /// Counter used to offset the rendered rects to make them wobble. + /// + /// The wobbling is there so a human could visually verify that the benchmark + /// is correctly pumping frames. + double wobbleCounter = 0; + + List _pictures; + Size windowSize; + Size cellSize; + Size rectSize; + + @override + Future setUpAll() async { + _pictures = []; + windowSize = window.physicalSize; + cellSize = Size( + windowSize.width / kColumns, + windowSize.height / kRows, + ); + rectSize = cellSize * 0.8; + + final Paint paint = Paint()..color = const Color.fromARGB(255, 255, 0, 0); + for (int i = 0; i < kRows * kColumns; i++) { + final PictureRecorder pictureRecorder = PictureRecorder(); + final Canvas canvas = Canvas(pictureRecorder); + canvas.drawRect(Offset.zero & rectSize, paint); + _pictures.add(pictureRecorder.endRecording()); + } + } + + OffsetEngineLayer _rootLayer; + final Map _layers = {}; + + @override + void onDrawFrame(SceneBuilder sceneBuilder) { + _rootLayer = sceneBuilder.pushOffset(0, 0, oldLayer: _rootLayer); + for (int row = 0; row < kRows; row++) { + for (int col = 0; col < kColumns; col++) { + final int layerId = 1000000 * row + col; + final OffsetEngineLayer oldLayer = _layers[layerId]; + final double wobbleOffsetX = col * cellSize.width + (wobbleCounter - 5).abs(); + final double offsetY = row * cellSize.height; + // Retain every other layer, so we exercise the update path 50% of the + // time and the retain path the other 50%. + final bool shouldRetain = oldLayer != null && (row + col) % 2 == 0; + if (shouldRetain) { + sceneBuilder.addRetained(oldLayer); + } else { + _layers[layerId] = sceneBuilder.pushOffset( + wobbleOffsetX, + offsetY, + oldLayer: oldLayer, + ); + sceneBuilder.addPicture(Offset.zero, _pictures[row * kColumns + col]); + sceneBuilder.pop(); + } + } + } + sceneBuilder.pop(); + wobbleCounter += 1; + wobbleCounter = wobbleCounter % 10; + } +} diff --git a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart index 211a446ca70..c63507623d6 100644 --- a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart +++ b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart @@ -12,6 +12,7 @@ import 'package:macrobenchmarks/src/web/bench_text_out_of_picture_bounds.dart'; import 'src/web/bench_build_material_checkbox.dart'; import 'src/web/bench_card_infinite_scroll.dart'; +import 'src/web/bench_child_layers.dart'; import 'src/web/bench_clipped_out_pictures.dart'; import 'src/web/bench_draw_rect.dart'; import 'src/web/bench_dynamic_clip_on_static_picture.dart'; @@ -40,6 +41,7 @@ final Map benchmarks = { BenchBuildMaterialCheckbox.benchmarkName: () => BenchBuildMaterialCheckbox(), BenchDynamicClipOnStaticPicture.benchmarkName: () => BenchDynamicClipOnStaticPicture(), BenchPictureRecording.benchmarkName: () => BenchPictureRecording(), + BenchUpdateManyChildLayers.benchmarkName: () => BenchUpdateManyChildLayers(), if (isCanvasKit) BenchBuildColorsGrid.canvasKitBenchmarkName: () => BenchBuildColorsGrid.canvasKit(),