add benchmark for picture recording (#54908)
diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_picture_recording.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_picture_recording.dart
new file mode 100644
index 0000000..1e45f9a
--- /dev/null
+++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_picture_recording.dart
@@ -0,0 +1,75 @@
+// 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 'package:macrobenchmarks/src/web/recorder.dart';
+
+/// Measure the performance of paint bounds estimation by recording a picture
+/// without actually rendering it.
+///
+/// Bounds estimation is done in two phases:
+///
+/// * As we call drawing methods on `Canvas` we grow bounds with every paint op.
+/// * When we're done recording a picture we call `PictureRecorder.endRecording`
+/// at which point we compute the overall picture bounds and cache the result.
+///
+/// This benchmarks puts emphasis on paint operations that trigger expensive
+/// math such as `transformLTRB`. To do that we push non-identity transforms
+/// and rotations before calling drawing methods.
+class BenchPictureRecording extends RawRecorder {
+ BenchPictureRecording() : super(name: benchmarkName);
+
+ static const String benchmarkName = 'bench_picture_recording';
+
+ /// Cached paint used for drawing.
+ ///
+ /// We want to avoid polluting the results with paint initialization logic.
+ Paint paint;
+
+ /// A prelaid out and cached paragraph.
+ ///
+ /// This is cached to remove text layout time from the benchmark time.
+ Paragraph paragraph;
+
+ @override
+ Future<void> setUpAll() async {
+ paint = Paint();
+ paragraph = (ParagraphBuilder(ParagraphStyle())
+ ..addText('abcd edfh ijkl mnop qrst uvwx yz'))
+ .build()
+ ..layout(const ParagraphConstraints(width: 50));
+ }
+
+ @override
+ void body(Profile profile) {
+ final PictureRecorder recorder = PictureRecorder();
+ final Canvas canvas = Canvas(recorder);
+ profile.record('recordPaintCommands', () {
+ for (int i = 1; i <= 100; i++) {
+ canvas.translate((10 + i).toDouble(), (10 + i).toDouble());
+
+ canvas.save();
+ for (int j = 0; j < 10; j++) {
+ canvas.drawRect(const Rect.fromLTWH(10, 10, 10, 10), paint);
+ canvas.drawCircle(const Offset(50, 50), 50, paint);
+ canvas.rotate(1.0);
+ }
+ canvas.restore();
+
+ canvas.save();
+ for (int j = 0; j < 10; j++) {
+ canvas.translate(1, 1);
+ canvas.clipRect(Rect.fromLTWH(20, 20, 40 / i, 40));
+ canvas.drawRRect(RRect.fromRectAndRadius(const Rect.fromLTWH(10, 10, 10, 10), const Radius.circular(2)), paint);
+ canvas.drawParagraph(paragraph, Offset.zero);
+ }
+ canvas.restore();
+ }
+ });
+ profile.record('estimatePaintBounds', () {
+ recorder.endRecording();
+ });
+ }
+}
diff --git a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart
index e306199..06e4a99 100644
--- a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart
@@ -14,6 +14,7 @@
import 'src/web/bench_card_infinite_scroll.dart';
import 'src/web/bench_draw_rect.dart';
import 'src/web/bench_dynamic_clip_on_static_picture.dart';
+import 'src/web/bench_picture_recording.dart';
import 'src/web/bench_simple_lazy_text_scroll.dart';
import 'src/web/bench_text_out_of_picture_bounds.dart';
import 'src/web/recorder.dart';
@@ -33,6 +34,7 @@
BenchSimpleLazyTextScroll.benchmarkName: () => BenchSimpleLazyTextScroll(),
BenchBuildMaterialCheckbox.benchmarkName: () => BenchBuildMaterialCheckbox(),
BenchDynamicClipOnStaticPicture.benchmarkName: () => BenchDynamicClipOnStaticPicture(),
+ BenchPictureRecording.benchmarkName: () => BenchPictureRecording(),
if (isCanvasKit)
BenchBuildColorsGrid.canvasKitBenchmarkName: () => BenchBuildColorsGrid.canvasKit(),