diff --git a/.ci.yaml b/.ci.yaml index bfab35ac4097..06b2dd296167 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1335,6 +1335,17 @@ targets: task_name: channels_integration_test scheduler: luci + - name: Linux_android clipper_cache_perf__e2e_summary + bringup: true + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","linux"] + task_name: clipper_cache_perf__e2e_summary + scheduler: luci + - name: Linux_android color_filter_and_fade_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false diff --git a/TESTOWNERS b/TESTOWNERS index 9706dde1c515..d36f11ccbf94 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -22,6 +22,7 @@ /dev/devicelab/bin/tasks/backdrop_filter_perf__e2e_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/basic_material_app_android__compile.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/codegen_integration.dart @zanderso @flutter/tool +/dev/devicelab/bin/tasks/clipper_cache_perf__e2e_summary.dart @flar @flutter/engine /dev/devicelab/bin/tasks/color_filter_and_fade_perf__e2e_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/shader_mask_cache_perf__e2e_summary.dart @flar @flutter/engine /dev/devicelab/bin/tasks/color_filter_cache_perf__e2e_summary.dart @flar @flutter/engine diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart index 023d81136355..39df4ce506b6 100644 --- a/dev/benchmarks/macrobenchmarks/lib/common.dart +++ b/dev/benchmarks/macrobenchmarks/lib/common.dart @@ -14,6 +14,7 @@ const String kLargeImagesRouteName = '/large_images'; const String kTextRouteName = '/text'; const String kFullscreenTextRouteName = '/fullscreen_text'; const String kAnimatedPlaceholderRouteName = '/animated_placeholder'; +const String kClipperCacheRouteName = '/clipper_cache'; const String kColorFilterAndFadeRouteName = '/color_filter_and_fade'; const String kColorFilterCacheRouteName = '/color_filter_cache'; const String kFadingChildAnimationRouteName = '/fading_child_animation'; diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart index 7b4fea0c55c0..dd02537c40ed 100644 --- a/dev/benchmarks/macrobenchmarks/lib/main.dart +++ b/dev/benchmarks/macrobenchmarks/lib/main.dart @@ -11,6 +11,7 @@ import 'src/animated_image.dart'; import 'src/animated_placeholder.dart'; import 'src/animation_with_microtasks.dart'; import 'src/backdrop_filter.dart'; +import 'src/clipper_cache.dart'; import 'src/color_filter_and_fade.dart'; import 'src/color_filter_cache.dart'; import 'src/cubic_bezier.dart'; @@ -58,6 +59,7 @@ class MacrobenchmarksApp extends StatelessWidget { kTextRouteName: (BuildContext context) => const TextPage(), kFullscreenTextRouteName: (BuildContext context) => const TextFieldPage(), kAnimatedPlaceholderRouteName: (BuildContext context) => const AnimatedPlaceholderPage(), + kClipperCacheRouteName: (BuildContext context) => const ClipperCachePage(), kColorFilterAndFadeRouteName: (BuildContext context) => const ColorFilterAndFadePage(), kColorFilterCacheRouteName: (BuildContext context) => const ColorFilterCachePage(), kFadingChildAnimationRouteName: (BuildContext context) => const FilteredChildAnimationPage(FilterType.opacity), @@ -168,6 +170,13 @@ class HomePage extends StatelessWidget { Navigator.pushNamed(context, kAnimatedPlaceholderRouteName); }, ), + ElevatedButton( + key: const Key(kClipperCacheRouteName), + child: const Text('Clipper Cache'), + onPressed: () { + Navigator.pushNamed(context, kClipperCacheRouteName); + }, + ), ElevatedButton( key: const Key(kColorFilterAndFadeRouteName), child: const Text('Color Filter and Fade'), diff --git a/dev/benchmarks/macrobenchmarks/lib/src/clipper_cache.dart b/dev/benchmarks/macrobenchmarks/lib/src/clipper_cache.dart new file mode 100644 index 000000000000..85098ef34cb4 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/clipper_cache.dart @@ -0,0 +1,93 @@ +// 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:async'; +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'picture_cache.dart'; + +class ClipperCachePage extends StatefulWidget { + const ClipperCachePage({super.key}); + @override + State createState() => _ClipperCachePageState(); +} + +class _ClipperCachePageState extends State + with TickerProviderStateMixin { + final double _animateOffset = 100; + final ScrollController _controller = ScrollController(); + final bool _isComplex = true; + late double _topMargin; + + @override + void initState() { + super.initState(); + const double itemHeight = 140; + _topMargin = (window.physicalSize.height / window.devicePixelRatio - itemHeight * 3) / 2; + if (_topMargin < 0) { + _topMargin = 0; + } + _controller.addListener(() { + if (_controller.offset < 10) { + _controller.animateTo(_animateOffset, duration: const Duration(milliseconds: 1000), curve: Curves.ease); + } else if (_controller.offset > _animateOffset - 10) { + _controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease); + } + }); + Timer(const Duration(milliseconds: 500), () { + _controller.animateTo(_animateOffset, duration: const Duration(milliseconds: 1000), curve: Curves.ease); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.blue, + body: ListView( + controller: _controller, + children: [ + SizedBox(height: _topMargin), + ClipPath( + clipBehavior: Clip.antiAliasWithSaveLayer, + child: _makeChild(0, _isComplex) + ), + ClipRect( + clipBehavior: Clip.antiAliasWithSaveLayer, + child: _makeChild(1, _isComplex) + ), + ClipRRect( + clipBehavior: Clip.antiAliasWithSaveLayer, + child: _makeChild(2, _isComplex) + ), + const SizedBox(height: 1000), + ], + ), + ); + } + + Widget _makeChild(int itemIndex, bool complex) { + final BoxDecoration decoration = BoxDecoration( + color: Colors.white70, + boxShadow: const [ + BoxShadow( + blurRadius: 5.0, + ), + ], + borderRadius: BorderRadius.circular(5.0), + ); + return RepaintBoundary( + child: Container( + margin: const EdgeInsets.fromLTRB(10, 5, 10, 5), + decoration: complex ? decoration : null, + child: ListItem(index: itemIndex), + ), + ); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } +} diff --git a/dev/benchmarks/macrobenchmarks/test/clipper_cache_perf_e2e.dart b/dev/benchmarks/macrobenchmarks/test/clipper_cache_perf_e2e.dart new file mode 100644 index 000000000000..ad09a9be83fc --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test/clipper_cache_perf_e2e.dart @@ -0,0 +1,16 @@ +// 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 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTestE2E( + 'clipper_cache_perf', + kClipperCacheRouteName, + pageDelay: const Duration(seconds: 1), + duration: const Duration(seconds: 10), + ); +} diff --git a/dev/devicelab/bin/tasks/clipper_cache_perf__e2e_summary.dart b/dev/devicelab/bin/tasks/clipper_cache_perf__e2e_summary.dart new file mode 100644 index 000000000000..13c3b032e902 --- /dev/null +++ b/dev/devicelab/bin/tasks/clipper_cache_perf__e2e_summary.dart @@ -0,0 +1,14 @@ +// 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:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createClipperCachePerfE2ETest()); +} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index ef4280213e18..ec2cdefd30a4 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -353,6 +353,13 @@ TaskFunction createFullscreenTextfieldPerfE2ETest() { ).run; } +TaskFunction createClipperCachePerfE2ETest() { + return PerfTest.e2e( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test/clipper_cache_perf_e2e.dart', + ).run; +} + TaskFunction createColorFilterAndFadePerfTest() { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',