diff --git a/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf.dart b/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf.dart index 69afb9e60b..3dae64149b 100644 --- a/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf.dart +++ b/dev/benchmarks/macrobenchmarks/test_driver/cubic_bezier_perf.dart @@ -10,8 +10,8 @@ import 'package:macrobenchmarks/main.dart' as app; class CubicBezierShaderWarmUp extends DefaultShaderWarmUp { @override - void warmUpOnCanvas(Canvas canvas) { - super.warmUpOnCanvas(canvas); + Future warmUpOnCanvas(Canvas canvas) async { + await super.warmUpOnCanvas(canvas); // Warm up the cubic shaders used by CubicBezierPage. // diff --git a/examples/layers/raw/shader_warm_up.dart b/examples/layers/raw/shader_warm_up.dart index 63f82b3577..9a6a973786 100644 --- a/examples/layers/raw/shader_warm_up.dart +++ b/examples/layers/raw/shader_warm_up.dart @@ -9,14 +9,14 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/painting.dart' show DefaultShaderWarmUp; -void beginFrame(Duration timeStamp) { +Future beginFrame(Duration timeStamp) async { // 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); + await const DefaultShaderWarmUp().warmUpOnCanvas(canvas); final ui.Picture picture = recorder.endRecording(); // COMPOSITE @@ -27,7 +27,7 @@ void beginFrame(Duration timeStamp) { ui.window.render(sceneBuilder.build()); } -void main() { +Future main() async { ui.window.onBeginFrame = beginFrame; ui.window.scheduleFrame(); } diff --git a/packages/flutter/lib/src/painting/shader_warm_up.dart b/packages/flutter/lib/src/painting/shader_warm_up.dart index b2ea90f751..03051e6426 100644 --- a/packages/flutter/lib/src/painting/shader_warm_up.dart +++ b/packages/flutter/lib/src/painting/shader_warm_up.dart @@ -2,7 +2,9 @@ // 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:developer'; +import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; @@ -65,6 +67,8 @@ abstract class ShaderWarmUp { /// Trigger draw operations on a given canvas to warm up GPU shader /// compilation cache. /// + /// Parameter [image] is to be used for drawImage related operations. + /// /// 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. @@ -73,20 +77,20 @@ abstract class ShaderWarmUp { /// Skia draw operations are commonly used, and which shader compilations /// are causing janks. @protected - void warmUpOnCanvas(ui.Canvas canvas); + Future warmUpOnCanvas(ui.Canvas canvas); /// Construct an offscreen image of [size], and execute [warmUpOnCanvas] on a /// canvas associated with that image. - void execute() { + Future execute() async { final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder); - warmUpOnCanvas(canvas); + await 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) { + picture.toImage(size.width.ceil(), size.height.ceil()).then((ui.Image _) { shaderWarmUpTask.finish(); }); } @@ -104,7 +108,7 @@ class DefaultShaderWarmUp extends ShaderWarmUp { /// Trigger common draw operations on a canvas to warm up GPU shader /// compilation cache. @override - void warmUpOnCanvas(ui.Canvas canvas) { + Future 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); @@ -179,5 +183,31 @@ class DefaultShaderWarmUp extends ShaderWarmUp { final ui.Paragraph paragraph = paragraphBuilder.build() ..layout(const ui.ParagraphConstraints(width: 60.0)); canvas.drawParagraph(paragraph, const ui.Offset(20.0, 20.0)); + + + // Construct an image for drawImage related operations + const int imageWidth = 40; + const int imageHeight = 40; + final Uint8List pixels = Uint8List.fromList(List.generate( + imageWidth * imageHeight * 4, + (int i) => i % 4 < 2 ? 0x00 : 0xFF, // opaque blue + )); + + final Completer completer = Completer(); + ui.decodeImageFromPixels(pixels, imageWidth, imageHeight, ui.PixelFormat.rgba8888, (ui.Image image) { + // Warm up image shaders + canvas.translate(0.0, 80.0); + canvas.save(); + final ui.Rect srcRect = ui.Rect.fromLTWH(0.0, 0.0, image.width.toDouble(), image.height.toDouble()); + canvas.drawImage(image, const ui.Offset(20.0, 20.0), ui.Paint()); + canvas.translate(80.0, 0.0); + canvas.drawImageRect(image, srcRect, ui.Rect.fromLTWH(20.0, 20.0, 20.0, 20.0), paints[0]); + canvas.translate(80.0, 0.0); + canvas.drawImageRect(image, srcRect, ui.Rect.fromLTWH(10.0, 10.0, 60.0, 60.0), paints[0]); + canvas.restore(); + completer.complete(); + }); + + return completer.future; } }