Unverified Commit 5652351d authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Clean up some documentation around shader warm-up. (#75863)

parent cd324657
...@@ -29,27 +29,35 @@ mixin PaintingBinding on BindingBase, ServicesBinding { ...@@ -29,27 +29,35 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
static PaintingBinding? get instance => _instance; static PaintingBinding? get instance => _instance;
static PaintingBinding? _instance; static PaintingBinding? _instance;
/// [ShaderWarmUp] to be executed during [initInstances]. /// [ShaderWarmUp] instance to be executed during [initInstances].
///
/// Defaults to an instance of [DefaultShaderWarmUp].
/// ///
/// If the application has scenes that require the compilation of complex /// If the application has scenes that require the compilation of complex
/// shaders that are not covered by [DefaultShaderWarmUp], it may cause jank /// shaders that are not covered by [DefaultShaderWarmUp], it may cause jank
/// in the middle of an animation or interaction. In that case, set /// in the middle of an animation or interaction. In that case, setting
/// [shaderWarmUp] to a custom [ShaderWarmUp] before calling [initInstances] /// [shaderWarmUp] to a custom [ShaderWarmUp] before creating the binding
/// (usually before [runApp] for normal Flutter apps, and before /// (usually before [runApp] for normal Flutter apps, and before
/// [enableFlutterDriverExtension] for Flutter driver tests). Paint the scene /// [enableFlutterDriverExtension] for Flutter driver tests) may help if that
/// in the custom [ShaderWarmUp] so Flutter can pre-compile and cache the /// object paints the difficult scene in its [ShaderWarmUp.warmUpOnCanvas]
/// shaders during startup. The warm up is only costly (100ms-200ms, /// method, as this allows Flutter to pre-compile and cache the required
/// depending on the shaders to compile) during the first run after the /// shaders during startup.
/// 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 raster thread which /// Currently the warm-up happens synchronously on the raster thread which
/// means the rendering of the first frame on the raster thread will be /// means the rendering of the first frame on the raster thread will be
/// postponed until the warm-up is finished. /// postponed until the warm-up is finished.
/// ///
/// 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 platform thread so there should be no
/// "Application Not Responding" warning.
///
/// If this is null, no shader warm-up is executed.
///
/// See also: /// See also:
/// ///
/// * [ShaderWarmUp], the interface of how this warm up works. /// * [ShaderWarmUp], the interface for implementing custom warm-up scenes.
/// * <https://flutter.dev/docs/perf/rendering/shader>
static ShaderWarmUp? shaderWarmUp = const DefaultShaderWarmUp(); static ShaderWarmUp? shaderWarmUp = const DefaultShaderWarmUp();
/// The singleton that implements the Flutter framework's image cache. /// The singleton that implements the Flutter framework's image cache.
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:developer'; import 'dart:developer';
import 'dart:ui' as ui; import 'dart:ui' as ui;
...@@ -25,18 +24,16 @@ import 'package:flutter/foundation.dart'; ...@@ -25,18 +24,16 @@ import 'package:flutter/foundation.dart';
/// ///
/// To determine whether a draw operation is useful for warming up shaders, /// To determine whether a draw operation is useful for warming up shaders,
/// check whether it improves the slowest frame rasterization time. Also, /// check whether it improves the slowest frame rasterization time. Also,
/// tracing with `flutter run --profile --trace-skia` may reveal whether /// tracing with `flutter run --profile --trace-skia` may reveal whether there
/// there is shader-compilation-related jank. If there is such jank, some long /// is shader-compilation-related jank. If there is such jank, some long
/// `GrGLProgramBuilder::finalize` calls would appear in the middle of an /// `GrGLProgramBuilder::finalize` calls would appear in the middle of an
/// animation. Their parent calls, which look like `XyzOp` (e.g., `FillRecOp`, /// animation. Their parent calls, which look like `XyzOp` (e.g., `FillRecOp`,
/// `CircularRRectOp`) would suggest Xyz draw operations are causing the /// `CircularRRectOp`) would suggest Xyz draw operations are causing the shaders
/// shaders to be compiled. A useful shader warm-up draw operation would /// to be compiled. A useful shader warm-up draw operation would eliminate such
/// eliminate such long compilation calls in the animation. To double-check /// long compilation calls in the animation. To double-check the warm-up, trace
/// the warm-up, trace with /// with `flutter run --profile --trace-skia --start-paused`. The
/// `flutter run --profile --trace-skia --start-paused`. /// `GrGLProgramBuilder` with the associated `XyzOp` should appear during
/// The `GrGLProgramBuilder` with the associated `XyzOp` should /// startup rather than in the middle of a later animation.
/// appear during startup rather than in the middle of a later animation.
/// ///
/// This warm-up needs to be run on each individual device because the shader /// 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 /// compilation depends on the specific GPU hardware and driver a device has. It
...@@ -51,8 +48,10 @@ import 'package:flutter/foundation.dart'; ...@@ -51,8 +48,10 @@ import 'package:flutter/foundation.dart';
/// ///
/// * [PaintingBinding.shaderWarmUp], the actual instance of [ShaderWarmUp] /// * [PaintingBinding.shaderWarmUp], the actual instance of [ShaderWarmUp]
/// that's used to warm up the shaders. /// that's used to warm up the shaders.
/// * <https://flutter.dev/docs/perf/rendering/shader>
abstract class ShaderWarmUp { abstract class ShaderWarmUp {
/// Allow const constructors for subclasses. /// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const ShaderWarmUp(); const ShaderWarmUp();
/// The size of the warm up image. /// The size of the warm up image.
...@@ -68,33 +67,34 @@ abstract class ShaderWarmUp { ...@@ -68,33 +67,34 @@ abstract class ShaderWarmUp {
/// compilation cache. /// compilation cache.
/// ///
/// To decide which draw operations to be added to your custom warm up /// To decide which draw operations to be added to your custom warm up
/// process, try capture an skp using /// process, consider capturing an skp using `flutter screenshot
/// `flutter screenshot --observatory-uri=<uri> --type=skia` /// --observatory-uri=<uri> --type=skia` and analyzing it with
/// and analyze it with https://debugger.skia.org. /// <https://debugger.skia.org/>. Alternatively, one may run the app with
/// Alternatively, one may run the app with `flutter run --trace-skia` and /// `flutter run --trace-skia` and then examine the raster thread in the
/// then examine the raster thread in the observatory timeline to see which /// observatory timeline to see which Skia draw operations are commonly used,
/// Skia draw operations are commonly used, and which shader compilations /// and which shader compilations are causing jank.
/// are causing jank.
@protected @protected
Future<void> warmUpOnCanvas(ui.Canvas canvas); Future<void> warmUpOnCanvas(ui.Canvas canvas);
/// Construct an offscreen image of [size], and execute [warmUpOnCanvas] on a /// Construct an offscreen image of [size], and execute [warmUpOnCanvas] on a
/// canvas associated with that image. /// canvas associated with that image.
///
/// Currently, this has no effect when [kIsWeb] is true.
Future<void> execute() async { Future<void> execute() async {
final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.PictureRecorder recorder = ui.PictureRecorder();
final ui.Canvas canvas = ui.Canvas(recorder); final ui.Canvas canvas = ui.Canvas(recorder);
await warmUpOnCanvas(canvas); await warmUpOnCanvas(canvas);
final ui.Picture picture = recorder.endRecording(); final ui.Picture picture = recorder.endRecording();
if (!kIsWeb) { // Picture.toImage is not yet implemented on the web.
final TimelineTask shaderWarmUpTask = TimelineTask(); final TimelineTask shaderWarmUpTask = TimelineTask();
shaderWarmUpTask.start('Warm-up shader'); shaderWarmUpTask.start('Warm-up shader');
// Picture.toImage is not yet implemented on the web. try {
if (!kIsWeb) {
await picture.toImage(size.width.ceil(), size.height.ceil()); await picture.toImage(size.width.ceil(), size.height.ceil());
} } finally {
shaderWarmUpTask.finish(); shaderWarmUpTask.finish();
} }
}
}
} }
/// Default way of warming up Skia shader compilations. /// Default way of warming up Skia shader compilations.
...@@ -102,19 +102,37 @@ abstract class ShaderWarmUp { ...@@ -102,19 +102,37 @@ abstract class ShaderWarmUp {
/// The draw operations being warmed up here are decided according to Flutter /// The draw operations being warmed up here are decided according to Flutter
/// engineers' observation and experience based on the apps and the performance /// engineers' observation and experience based on the apps and the performance
/// issues seen so far. /// issues seen so far.
///
/// This is used for the default value of [PaintingBinding.shaderWarmUp].
/// Consider setting that static property to a different value before the
/// binding is initialized to change the warm-up sequence.
///
/// See also:
///
/// * [ShaderWarmUp], the base class for shader warm-up objects.
/// * <https://flutter.dev/docs/perf/rendering/shader>
class DefaultShaderWarmUp extends ShaderWarmUp { class DefaultShaderWarmUp extends ShaderWarmUp {
/// Allow [DefaultShaderWarmUp] to be used as the default value of parameters. /// Create an instance of the default shader warm-up logic.
///
/// Since this constructor is `const`, [DefaultShaderWarmUp] can be used as
/// the default value of parameters.
const DefaultShaderWarmUp({ const DefaultShaderWarmUp({
this.drawCallSpacing = 0.0, this.drawCallSpacing = 0.0,
this.canvasSize = const ui.Size(100.0, 100.0), this.canvasSize = const ui.Size(100.0, 100.0),
}); });
/// Constant that can be used to space out draw calls for visualizing the draws /// Distance to place between draw calls for visualizing the draws for
/// for debugging purposes (example: 80.0). Be sure to also change your canvas /// debugging purposes (e.g. 80.0).
/// size. ///
/// Defaults to 0.0.
///
/// When changing this value, the [canvasSize] must also be changed to
/// accomodate the bigger canvas.
final double drawCallSpacing; final double drawCallSpacing;
/// Value that returned by this.size to control canvas size where draws happen. /// The [size] of the canvas required to paint the shapes in [warmUpOnCanvas].
///
/// When [drawCallSpacing] is 0.0, this should be at least 100.0 by 100.0.
final ui.Size canvasSize; final ui.Size canvasSize;
@override @override
...@@ -126,7 +144,6 @@ class DefaultShaderWarmUp extends ShaderWarmUp { ...@@ -126,7 +144,6 @@ class DefaultShaderWarmUp extends ShaderWarmUp {
Future<void> warmUpOnCanvas(ui.Canvas canvas) async { Future<void> warmUpOnCanvas(ui.Canvas canvas) async {
const ui.RRect rrect = ui.RRect.fromLTRBXY(20.0, 20.0, 60.0, 60.0, 10.0, 10.0); const 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 rrectPath = ui.Path()..addRRect(rrect);
final ui.Path circlePath = ui.Path()..addOval( final ui.Path circlePath = ui.Path()..addOval(
ui.Rect.fromCircle(center: const ui.Offset(40.0, 40.0), radius: 20.0) ui.Rect.fromCircle(center: const ui.Offset(40.0, 40.0), radius: 20.0)
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment