diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart index 741920d712c..e88a70800a8 100644 --- a/dev/benchmarks/macrobenchmarks/lib/common.dart +++ b/dev/benchmarks/macrobenchmarks/lib/common.dart @@ -1,6 +1 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - const String kCullOpacityRouteName = '/cull_opacity'; -const String kCubicBezierRouteName = '/cubic_bezier'; diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart index c9fb5f9b3f4..c7a2778aa25 100644 --- a/dev/benchmarks/macrobenchmarks/lib/main.dart +++ b/dev/benchmarks/macrobenchmarks/lib/main.dart @@ -1,11 +1,6 @@ -// Copyright 2015 The Chromium 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:flutter/material.dart'; import 'common.dart'; -import 'src/cubic_bezier.dart'; import 'src/cull_opacity.dart'; const String kMacrobenchmarks ='Macrobenchmarks'; @@ -21,7 +16,6 @@ class MacrobenchmarksApp extends StatelessWidget { routes: { '/': (BuildContext context) => HomePage(), kCullOpacityRouteName: (BuildContext context) => CullOpacityPage(), - kCubicBezierRouteName: (BuildContext context) => CubicBezierPage(), }, ); } @@ -40,13 +34,6 @@ class HomePage extends StatelessWidget { onPressed: (){ Navigator.pushNamed(context, kCullOpacityRouteName); }, - ), - RaisedButton( - key: const Key(kCubicBezierRouteName), - child: const Text('Cubic Bezier'), - onPressed: (){ - Navigator.pushNamed(context, kCubicBezierRouteName); - }, ) ], ), diff --git a/dev/benchmarks/macrobenchmarks/lib/src/cubic_bezier.dart b/dev/benchmarks/macrobenchmarks/lib/src/cubic_bezier.dart deleted file mode 100644 index 85023be2c5d..00000000000 --- a/dev/benchmarks/macrobenchmarks/lib/src/cubic_bezier.dart +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright 2015 The Chromium 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:math'; - -import 'package:flutter/widgets.dart'; -import 'package:flutter/animation.dart'; -import 'package:flutter/material.dart'; - -// Based on https://github.com/eseidelGoogle/bezier_perf/blob/master/lib/main.dart -class CubicBezierPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Bezier(Colors.amber, 1.0), - ], - ), - ); - } -} - -class Bezier extends StatelessWidget { - const Bezier(this.color, this.scale, {this.blur = 0.0, this.delay = 0.0}); - - final Color color; - final double scale; - final double blur; - final double delay; - - List _getLogoPath() { - final List paths = []; - - final Path path = Path(); - path.moveTo(100.0, 97.0); - path.cubicTo(100.0, 97.0, 142.0, 59.0, 169.91, 41.22); - path.cubicTo(197.82, 23.44, 249.24, 5.52, 204.67, 85.84); - - paths.add(PathDetail(path)); - - // Path 2 - final Path bezier2Path = Path(); - bezier2Path.moveTo(0.0, 70.55); - bezier2Path.cubicTo(0.0, 70.55, 42.0, 31.55, 69.91, 14.77); - bezier2Path.cubicTo(97.82, -2.01, 149.24, -20.93, 104.37, 59.39); - - paths.add(PathDetail(bezier2Path, - translate: [29.45, 151.0], rotation: -1.5708)); - - // Path 3 - final Path bezier3Path = Path(); - bezier3Path.moveTo(0.0, 69.48); - bezier3Path.cubicTo(0.0, 69.48, 44.82, 27.92, 69.91, 13.7); - bezier3Path.cubicTo(95.0, -0.52, 149.24, -22.0, 104.37, 58.32); - - paths.add(PathDetail(bezier3Path, - translate: [53.0, 200.48], rotation: -3.14159)); - - // Path 4 - final Path bezier4Path = Path(); - bezier4Path.moveTo(0.0, 69.48); - bezier4Path.cubicTo(0.0, 69.48, 43.82, 27.92, 69.91, 13.7); - bezier4Path.cubicTo(96.0, -0.52, 149.24, -22.0, 104.37, 58.32); - - paths.add(PathDetail(bezier4Path, - translate: [122.48, 77.0], rotation: -4.71239)); - - return paths; - } - - @override - Widget build(BuildContext context) { - return Stack(children: [ - CustomPaint( - foregroundPainter: - BezierPainter(Colors.grey, 0.0, _getLogoPath(), false), - size: const Size(100.0, 100.0), - ), - AnimatedBezier(color, scale, blur: blur, delay: delay), - ]); - } -} - -class PathDetail { - PathDetail(this.path, {this.translate, this.rotation}); - - Path path; - List translate = []; - double rotation; -} - -class AnimatedBezier extends StatefulWidget { - const AnimatedBezier(this.color, this.scale, {this.blur = 0.0, this.delay}); - - final Color color; - final double scale; - final double blur; - final double delay; - - @override - State createState() => AnimatedBezierState(); -} - -class Point { - Point(this.x, this.y); - - double x; - double y; -} - -class AnimatedBezierState extends State - with SingleTickerProviderStateMixin { - double scale; - AnimationController controller; - CurvedAnimation curve; - bool isPlaying = false; - List> pointList = >[] - ..add([]) - ..add([]) - ..add([]) - ..add([]); - bool isReversed = false; - - List _playForward() { - final List paths = []; - final double t = curve.value; - final double b = controller.upperBound; - double pX; - double pY; - - final Path path = Path(); - - if (t < b / 2) { - pX = _getCubicPoint(t * 2, 100.0, 100.0, 142.0, 169.91); - pY = _getCubicPoint(t * 2, 97.0, 97.0, 59.0, 41.22); - pointList[0].add(Point(pX, pY)); - } else { - pX = _getCubicPoint(t * 2 - b, 169.91, 197.80, 249.24, 204.67); - pY = _getCubicPoint(t * 2 - b, 41.22, 23.44, 5.52, 85.84); - pointList[0].add(Point(pX, pY)); - } - - path.moveTo(100.0, 97.0); - - for (Point p in pointList[0]) { - path.lineTo(p.x, p.y); - } - - paths.add(PathDetail(path)); - - // Path 2 - final Path bezier2Path = Path(); - - if (t <= b / 2) { - final double pX = _getCubicPoint(t * 2, 0.0, 0.0, 42.0, 69.91); - final double pY = _getCubicPoint(t * 2, 70.55, 70.55, 31.55, 14.77); - pointList[1].add(Point(pX, pY)); - } else { - final double pX = _getCubicPoint(t * 2 - b, 69.91, 97.82, 149.24, 104.37); - final double pY = _getCubicPoint(t * 2 - b, 14.77, -2.01, -20.93, 59.39); - pointList[1].add(Point(pX, pY)); - } - - bezier2Path.moveTo(0.0, 70.55); - - for (Point p in pointList[1]) { - bezier2Path.lineTo(p.x, p.y); - } - - paths.add(PathDetail(bezier2Path, - translate: [29.45, 151.0], rotation: -1.5708)); - - // Path 3 - final Path bezier3Path = Path(); - if (t <= b / 2) { - pX = _getCubicPoint(t * 2, 0.0, 0.0, 44.82, 69.91); - pY = _getCubicPoint(t * 2, 69.48, 69.48, 27.92, 13.7); - pointList[2].add(Point(pX, pY)); - } else { - pX = _getCubicPoint(t * 2 - b, 69.91, 95.0, 149.24, 104.37); - pY = _getCubicPoint(t * 2 - b, 13.7, -0.52, -22.0, 58.32); - pointList[2].add(Point(pX, pY)); - } - - bezier3Path.moveTo(0.0, 69.48); - - for (Point p in pointList[2]) { - bezier3Path.lineTo(p.x, p.y); - } - - paths.add(PathDetail(bezier3Path, - translate: [53.0, 200.48], rotation: -3.14159)); - - // Path 4 - final Path bezier4Path = Path(); - - if (t < b / 2) { - final double pX = _getCubicPoint(t * 2, 0.0, 0.0, 43.82, 69.91); - final double pY = _getCubicPoint(t * 2, 69.48, 69.48, 27.92, 13.7); - pointList[3].add(Point(pX, pY)); - } else { - final double pX = _getCubicPoint(t * 2 - b, 69.91, 96.0, 149.24, 104.37); - final double pY = _getCubicPoint(t * 2 - b, 13.7, -0.52, -22.0, 58.32); - pointList[3].add(Point(pX, pY)); - } - - bezier4Path.moveTo(0.0, 69.48); - - for (Point p in pointList[3]) { - bezier4Path.lineTo(p.x, p.y); - } - - paths.add(PathDetail(bezier4Path, - translate: [122.48, 77.0], rotation: -4.71239)); - - return paths; - } - - List _playReversed() { - for (List list in pointList) { - if (list.isNotEmpty) { - list.removeLast(); - } - } - - final List points = pointList[0]; - final Path path = Path(); - - path.moveTo(100.0, 97.0); - - for (Point point in points) { - path.lineTo(point.x, point.y); - } - - final Path bezier2Path = Path(); - - bezier2Path.moveTo(0.0, 70.55); - - for (Point p in pointList[1]) { - bezier2Path.lineTo(p.x, p.y); - } - - final Path bezier3Path = Path(); - bezier3Path.moveTo(0.0, 69.48); - - for (Point p in pointList[2]) { - bezier3Path.lineTo(p.x, p.y); - } - - final Path bezier4Path = Path(); - - bezier4Path.moveTo(0.0, 69.48); - - for (Point p in pointList[3]) { - bezier4Path.lineTo(p.x, p.y); - } - - return [ - PathDetail(path), - PathDetail(bezier2Path, translate: [29.45, 151.0], rotation: -1.5708), - PathDetail(bezier3Path, - translate: [53.0, 200.48], rotation: -3.14159), - PathDetail(bezier4Path, translate: [122.48, 77.0], rotation: -4.71239) - ]; - } - - List _getLogoPath() { - if (!isReversed) { - return _playForward(); - } - - return _playReversed(); - } - - //From http://wiki.roblox.com/index.php?title=File:Beziereq4.png - double _getCubicPoint(double t, double p0, double p1, double p2, double p3) { - return pow(1 - t, 3) * p0 + - 3 * pow(1 - t, 2) * t * p1 + - 3 * (1 - t) * pow(t, 2) * p2 + - pow(t, 3) * p3; - } - - void playAnimation() { - isPlaying = true; - isReversed = false; - for (List list in pointList) { - list.clear(); - } - controller.reset(); - controller.forward(); - } - - void stopAnimation() { - isPlaying = false; - controller.stop(); - for (List list in pointList) { - list.clear(); - } - } - - void reverseAnimation() { - isReversed = true; - controller.reverse(); - } - - @override - void initState() { - super.initState(); - controller = AnimationController( - vsync: this, duration: const Duration(milliseconds: 1000)); - curve = CurvedAnimation(parent: controller, curve: Curves.linear) - ..addListener(() { - setState(() {}); - }) - ..addStatusListener((AnimationStatus state) { - if (state == AnimationStatus.completed) { - reverseAnimation(); - } else if (state == AnimationStatus.dismissed) { - playAnimation(); - } - }); - - playAnimation(); - } - - @override - Widget build(BuildContext context) { - return CustomPaint( - foregroundPainter: BezierPainter(widget.color, - curve.value * widget.blur, _getLogoPath(), isPlaying), - size: const Size(100.0, 100.0)); - } -} - -class BezierPainter extends CustomPainter { - BezierPainter(this.color, this.blur, this.path, this.isPlaying); - - Color color; - final double blur; - List path; - bool isPlaying; - - @override - void paint(Canvas canvas, Size size) { - final Paint paint = Paint(); - paint.strokeWidth = 18.0; - paint.style = PaintingStyle.stroke; - paint.strokeCap = StrokeCap.round; - paint.color = color; - canvas.scale(0.5, 0.5); - - for (int i = 0; i < path.length; i++) { - if (path[i].translate != null) { - canvas.translate(path[i].translate[0], path[i].translate[1]); - } - - if (path[i].rotation != null) { - canvas.rotate(path[i].rotation); - } - - if (blur > 0) { - final MaskFilter blur = MaskFilter.blur(BlurStyle.normal, this.blur); - paint.maskFilter = blur; - canvas.drawPath(path[i].path, paint); - } - - paint.maskFilter = null; - canvas.drawPath(path[i].path, paint); - } - } - - @override - bool shouldRepaint(BezierPainter oldDelegate) => true; - - @override - bool shouldRebuildSemantics(BezierPainter oldDelegate) => false; -} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf.dart b/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf.dart deleted file mode 100644 index fc0c0a70863..00000000000 --- a/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf.dart +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 The Chromium 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:flutter_driver/driver_extension.dart'; -import 'package:flutter/painting.dart' show DefaultShaderWarmUp, PaintingBinding; -import 'package:macrobenchmarks/main.dart' as app; - -class CubicBezierShaderWarmUp extends DefaultShaderWarmUp { - @override - void warmUpOnCanvas(Canvas canvas) { - super.warmUpOnCanvas(canvas); - - // Warm up the cubic shaders used by CubicBezierPage. - // - // This tests that our custom shader warm up is working properly. - // Without this custom shader warm up, the worst frame time is about 115ms. - // With this, the worst frame time is about 70ms. (Data collected on a Moto - // G4 based on Flutter version 704814c67a874077710524d30412337884bf0254. - final Path path = Path(); - path.moveTo(20.0, 20.0); - // This cubic path is based on - // https://skia.org/user/api/SkPath_Reference#SkPath_cubicTo - path.cubicTo(300.0, 80.0, -140.0, 90.0, 220.0, 10.0); - final Paint paint = Paint(); - paint.isAntiAlias = true; - paint.strokeWidth = 18.0; - paint.style = PaintingStyle.stroke; - paint.strokeCap = StrokeCap.round; - canvas.drawPath(path, paint); - } -} - -void main() { - PaintingBinding.shaderWarmUp = CubicBezierShaderWarmUp(); - enableFlutterDriverExtension(); - app.main(); -} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf_test.dart deleted file mode 100644 index 12fc4126bcb..00000000000 --- a/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf_test.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Chromium 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() { - macroPerfTest('cubic_bezier_perf', kCubicBezierRouteName); -} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/cull_opacity_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/cull_opacity_perf_test.dart index c5b15bce58b..6493a1abad6 100644 --- a/dev/benchmarks/macrobenchmarks/test_driver/cull_opacity_perf_test.dart +++ b/dev/benchmarks/macrobenchmarks/test_driver/cull_opacity_perf_test.dart @@ -2,15 +2,42 @@ // 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_driver/flutter_driver.dart'; +import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; + import 'package:macrobenchmarks/common.dart'; -import 'util.dart'; - void main() { - macroPerfTest( - 'cull_opacity_perf', - kCullOpacityRouteName, - pageDelay: const Duration(seconds: 1), - duration: const Duration(seconds: 10) - ); + const String kName = 'cull_opacity_perf'; + + test(kName, () async { + final FlutterDriver driver = await FlutterDriver.connect(); + + // The slight initial delay avoids starting the timing during a + // period of increased load on the device. Without this delay, the + // benchmark has greater noise. + // See: https://github.com/flutter/flutter/issues/19434 + await Future.delayed(const Duration(milliseconds: 250)); + + await driver.forceGC(); + + final SerializableFinder button = find.byValueKey(kCullOpacityRouteName); + expect(button, isNotNull); + await driver.tap(button); + + // Wait for the page to load + await Future.delayed(const Duration(seconds: 1)); + + final Timeline timeline = await driver.traceAction(() async { + await Future.delayed(const Duration(seconds: 10)); + }); + + final TimelineSummary summary = TimelineSummary.summarize(timeline); + summary.writeSummaryToFile(kName, pretty: true); + summary.writeTimelineToFile(kName, pretty: true); + + driver.close(); + }); } diff --git a/dev/benchmarks/macrobenchmarks/test_driver/util.dart b/dev/benchmarks/macrobenchmarks/test_driver/util.dart deleted file mode 100644 index 26745735d74..00000000000 --- a/dev/benchmarks/macrobenchmarks/test_driver/util.dart +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2015 The Chromium 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_driver/flutter_driver.dart'; -import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; - -void macroPerfTest( - String testName, - String routeName, - {Duration pageDelay, Duration duration = const Duration(seconds: 3)}) { - test(testName, () async { - final FlutterDriver driver = await FlutterDriver.connect(); - - // The slight initial delay avoids starting the timing during a - // period of increased load on the device. Without this delay, the - // benchmark has greater noise. - // See: https://github.com/flutter/flutter/issues/19434 - await Future.delayed(const Duration(milliseconds: 250)); - - await driver.forceGC(); - - final SerializableFinder button = find.byValueKey(routeName); - expect(button, isNotNull); - await driver.tap(button); - - if (pageDelay != null) { - // Wait for the page to load - await Future.delayed(pageDelay); - } - - final Timeline timeline = await driver.traceAction(() async { - await Future.delayed(duration); - }); - - final TimelineSummary summary = TimelineSummary.summarize(timeline); - summary.writeSummaryToFile(testName, pretty: true); - summary.writeTimelineToFile(testName, pretty: true); - - driver.close(); - }); -} diff --git a/dev/devicelab/bin/tasks/cubic_bezier_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/cubic_bezier_perf__timeline_summary.dart deleted file mode 100644 index 3f7baf27fd0..00000000000 --- a/dev/devicelab/bin/tasks/cubic_bezier_perf__timeline_summary.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Chromium 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/tasks/perf_tests.dart'; -import 'package:flutter_devicelab/framework/adb.dart'; -import 'package:flutter_devicelab/framework/framework.dart'; - -Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createCubicBezierPerfTest()); -} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 515d122636d..27e877fbb6b 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -46,14 +46,6 @@ TaskFunction createCullOpacityPerfTest() { ).run; } -TaskFunction createCubicBezierPerfTest() { - return PerfTest( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test_driver/cubic_bezier_perf.dart', - 'cubic_bezier_perf', - ).run; -} - TaskFunction createFlutterGalleryStartupTest() { return StartupTest( '${flutterDirectory.path}/examples/flutter_gallery', diff --git a/dev/devicelab/manifest.yaml b/dev/devicelab/manifest.yaml index ec313442487..0d89a031735 100644 --- a/dev/devicelab/manifest.yaml +++ b/dev/devicelab/manifest.yaml @@ -134,13 +134,6 @@ tasks: stage: devicelab required_agent_capabilities: ["mac/android"] - cubic_bezier_perf__timeline_summary: - description: > - Measures the runtime performance of cubic bezier animations on Android. - stage: devicelab - required_agent_capabilities: ["mac/android"] - flaky: true - flavors_test: description: > Checks that flavored builds work on Android. diff --git a/examples/layers/raw/shader_warm_up.dart b/examples/layers/raw/shader_warm_up.dart deleted file mode 100644 index c2cc6809d2f..00000000000 --- a/examples/layers/raw/shader_warm_up.dart +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This example shows the draw operations to warm up the GPU shaders by default. - -import 'dart:ui' as ui; - -import 'package:flutter/material.dart'; -import 'package:flutter/painting.dart' show DefaultShaderWarmUp; - -void beginFrame(Duration timeStamp) { - // PAINT - final ui.PictureRecorder recorder = ui.PictureRecorder(); - final ui.Rect paintBounds = ui.Rect.fromLTRB(0, 0, 1000, 1000); - final ui.Canvas canvas = ui.Canvas(recorder, paintBounds); - final ui.Paint backgroundPaint = ui.Paint()..color = Colors.white; - canvas.drawRect(paintBounds, backgroundPaint); - const DefaultShaderWarmUp().warmUpOnCanvas(canvas); - final ui.Picture picture = recorder.endRecording(); - - // COMPOSITE - final ui.SceneBuilder sceneBuilder = ui.SceneBuilder() - ..pushClipRect(paintBounds) - ..addPicture(ui.Offset.zero, picture) - ..pop(); - ui.window.render(sceneBuilder.build()); -} - -void main() { - ui.window.onBeginFrame = beginFrame; - ui.window.scheduleFrame(); -} diff --git a/examples/layers/test/smoketests/raw/shader_warm_up_test.dart b/examples/layers/test/smoketests/raw/shader_warm_up_test.dart deleted file mode 100644 index 0124ac1375d..00000000000 --- a/examples/layers/test/smoketests/raw/shader_warm_up_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017 The Chromium 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:test_api/test_api.dart' hide TypeMatcher, isInstanceOf; - -import '../../../raw/shader_warm_up.dart' as demo; - -void main() { - test('layers smoketest for raw/shader_warm_up.dart', () { - demo.main(); - }); -} diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart index fe432cb9093..6cce1f837ab 100644 --- a/packages/flutter/lib/painting.dart +++ b/packages/flutter/lib/painting.dart @@ -50,7 +50,6 @@ export 'src/painting/matrix_utils.dart'; export 'src/painting/notched_shapes.dart'; export 'src/painting/paint_utilities.dart'; export 'src/painting/rounded_rectangle_border.dart'; -export 'src/painting/shader_warm_up.dart'; export 'src/painting/shape_decoration.dart'; export 'src/painting/stadium_border.dart'; export 'src/painting/strut_style.dart'; diff --git a/packages/flutter/lib/src/painting/binding.dart b/packages/flutter/lib/src/painting/binding.dart index 1d4e72e3711..01596ad85f7 100644 --- a/packages/flutter/lib/src/painting/binding.dart +++ b/packages/flutter/lib/src/painting/binding.dart @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart' show ServicesBinding; import 'image_cache.dart'; -import 'shader_warm_up.dart'; const double _kDefaultDecodedCacheRatioCap = 0.0; @@ -23,34 +22,12 @@ mixin PaintingBinding on BindingBase, ServicesBinding { super.initInstances(); _instance = this; _imageCache = createImageCache(); - if (shaderWarmUp != null) { - shaderWarmUp.execute(); - } } /// The current [PaintingBinding], if one has been created. static PaintingBinding get instance => _instance; static PaintingBinding _instance; - /// [ShaderWarmUp] to be executed during [initInstances]. - /// - /// If the application has scenes that require the compilation of complex - /// shaders that are not covered by [DefaultShaderWarmUp], it may cause jank - /// in the middle of an animation or interaction. In that case, set - /// [shaderWarmUp] to a custom [ShaderWarmUp] before calling [initInstances] - /// (usually before [runApp] for normal flutter apps, and before - /// [enableFlutterDriverExtension] for flutter drive tests). Paint the scene - /// in the custom [ShaderWarmUp] so Flutter can pre-compile and cache the - /// shaders during startup. The warm up is only costly (100ms-200ms, - /// depending on the shaders to compile) during the first run after the - /// installation or a data wipe. The warm up does not block the main thread - /// so there should be no "Application Not Responding" warning. - /// - /// Currently the warm-up happens synchronously on the GPU thread which means - /// the rendering of the first frame on the GPU thread will be postponed until - /// the warm-up is finished. - static ShaderWarmUp shaderWarmUp = const DefaultShaderWarmUp(); - /// The singleton that implements the Flutter framework's image cache. /// /// The cache is used internally by [ImageProvider] and should generally not diff --git a/packages/flutter/lib/src/painting/shader_warm_up.dart b/packages/flutter/lib/src/painting/shader_warm_up.dart deleted file mode 100644 index b71ac4743a7..00000000000 --- a/packages/flutter/lib/src/painting/shader_warm_up.dart +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2015 The Chromium 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:developer'; -import 'dart:ui' as ui; - -import 'package:flutter/foundation.dart'; - -/// Interface for drawing an image to warm up Skia shader compilations. -/// -/// When Skia first sees a certain type of draw operations on GPU, it needs to -/// compile the corresponding shader. The compilation can be slow (20ms-200ms). -/// Having that time as a startup latency is often better than having a jank in -/// the middle of an animation. -/// -/// Therefore, we use this during the [PaintingBinding.initInstances] call to -/// move common shader compilations from animation time to startup time. By -/// default, a [DefaultShaderWarmUp] is used. Create a custom [ShaderWarmUp] -/// subclass to replace [PaintingBinding.shaderWarmUp] before -/// [PaintingBinding.initInstances] is called. Usually, that can be done before -/// calling [runApp]. -/// -/// This warm up needs to be run on each individual device because the shader -/// compilation depends on the specific GPU hardware and driver a device has. It -/// can't be pre-computed during the Flutter engine compilation as the engine is -/// device agnostic. -/// -/// If no warm up is desired (e.g., when the startup latency is crucial), set -/// [PaintingBinding.shaderWarmUp] either to a custom ShaderWarmUp with an empty -/// [warmUpOnCanvas] or null. -abstract class ShaderWarmUp { - /// Allow const constructors for subclasses. - const ShaderWarmUp(); - - /// The size of the warm up image. - /// - /// The exact size shouldn't matter much as long as it's not too far away from - /// the target device's screen. 1024x1024 is a good choice as it is within an - /// order of magnitude of most devices. - /// - /// A custom shader warm up can override this based on targeted devices. - ui.Size get size => const ui.Size(1024.0, 1024.0); - - /// Trigger draw operations on a given canvas to warm up GPU shader - /// compilation cache. - /// - /// To decide which draw operations to be added to your custom warm up - /// process, try capture an skp using `flutter screenshot --observatory- - /// port= --type=skia` and analyze it with https://debugger.skia.org. - /// Alternatively, one may run the app with `flutter run --trace-skia` and - /// then examine the GPU thread in the observatory timeline to see which - /// Skia draw operations are commonly used, and which shader compilations - /// are causing janks. - @protected - void warmUpOnCanvas(ui.Canvas canvas); - - /// Construct an offscreen image of [size], and execute [warmUpOnCanvas] on a - /// canvas associated with that image. - void execute() { - final ui.PictureRecorder recorder = ui.PictureRecorder(); - final ui.Canvas canvas = ui.Canvas(recorder); - - warmUpOnCanvas(canvas); - - final ui.Picture picture = recorder.endRecording(); - final TimelineTask shaderWarmUpTask = TimelineTask(); - shaderWarmUpTask.start('Warm-up shader'); - picture.toImage(size.width.ceil(), size.height.ceil()).then((ui.Image image) { - shaderWarmUpTask.finish(); - }); - } -} - -/// Default way of warming up Skia shader compilations. -/// -/// The draw operations being warmed up here are decided according to Flutter -/// engineers' observation and experience based on the apps and the performance -/// issues seen so far. -class DefaultShaderWarmUp extends ShaderWarmUp { - /// Allow [DefaultShaderWarmUp] to be used as the default value of parameters. - const DefaultShaderWarmUp(); - - /// Trigger common draw operations on a canvas to warm up GPU shader - /// compilation cache. - @override - void warmUpOnCanvas(ui.Canvas canvas) { - final ui.RRect rrect = ui.RRect.fromLTRBXY(20.0, 20.0, 60.0, 60.0, 10.0, 10.0); - final ui.Path rrectPath = ui.Path()..addRRect(rrect); - - final ui.Path circlePath = ui.Path()..addOval( - ui.Rect.fromCircle(center: const ui.Offset(40.0, 40.0), radius: 20.0) - ); - - // The following path is based on - // https://skia.org/user/api/SkCanvas_Reference#SkCanvas_drawPath - final ui.Path path = ui.Path(); - path.moveTo(20.0, 60.0); - path.quadraticBezierTo(60.0, 20.0, 60.0, 60.0); - path.close(); - path.moveTo(60.0, 20.0); - path.quadraticBezierTo(60.0, 60.0, 20.0, 60.0); - - final List paths = [rrectPath, circlePath, path]; - - final List paints = [ - ui.Paint() - ..isAntiAlias = true - ..style = ui.PaintingStyle.fill, - ui.Paint() - ..isAntiAlias = true - ..style = ui.PaintingStyle.stroke - ..strokeWidth = 10, - ui.Paint() - ..isAntiAlias = true - ..style = ui.PaintingStyle.stroke - ..strokeWidth = 0.1 // hairline - ]; - - // Warm up path stroke and fill shaders. - for (int i = 0; i < paths.length; i += 1) { - canvas.save(); - for (ui.Paint paint in paints) { - canvas.drawPath(paths[i], paint); - canvas.translate(80.0, 0.0); - } - canvas.restore(); - canvas.translate(0.0, 80.0); - } - - // Warm up shadow shaders. - const ui.Color black = ui.Color(0xFF000000); - canvas.save(); - canvas.drawShadow(rrectPath, black, 10.0, true); - canvas.translate(80.0, 0.0); - canvas.drawShadow(rrectPath, black, 10.0, false); - canvas.restore(); - - // Warm up text shaders. - canvas.translate(0.0, 80.0); - final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder( - ui.ParagraphStyle(textDirection: ui.TextDirection.ltr), - )..pushStyle(ui.TextStyle(color: black))..addText('_'); - final ui.Paragraph paragraph = paragraphBuilder.build() - ..layout(const ui.ParagraphConstraints(width: 60.0)); - canvas.drawParagraph(paragraph, const ui.Offset(20.0, 20.0)); - } -}