-
Notifications
You must be signed in to change notification settings - Fork 29k
Shader warm up #27660
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shader warm up #27660
Conversation
By how much does this regress the time to first frame benchmarks? |
@chinmaygarde : time to first frame increases about 100ms-200ms for complex_layout and flutter_gallery. Please see my updated PR description. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for discussing the tradeoffs and providing data. The approach looks good to me. I am sure we can do a better job of documenting how users can use this feature but that can be tackled in future commits. LGTM but someone more familiar with dart conventions should probably also take a look.
@@ -757,6 +757,10 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB | |||
/// | |||
/// Initializes the binding using [WidgetsFlutterBinding] if necessary. | |||
/// | |||
/// Provide [customShaderWarmUp] if some specific Skia shaders need to be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be elaborated a bit to make it more useful. Something like, "if the application has scenes that require the compilation of complex shaders, it may cause jank in the middle of an animation or interaction. Painting that scene here tells Flutter to precompute and cache the results of expensive operations so they can be reused later. This should only happen during the very first run of the Flutter application and is typically very small. It is advised that you add tracing here so that such pauses are easier to identify on the timeline. The applications main thread will not be blocked when Flutter is doing this work so you should no expect ANR warnings".
Something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I've combined yours with my original documentation. I omit the tracing part because it's already added to _warmUpSkiaShaderCompilations
which calls either [defaultShaderWarmUp] or [customShaderWarmUp].
CC @sfshaza2 for more API doc review.
To avoid dependency loop
/// to move common shader compilations from animation time to startup time. | ||
/// Alternatively, [customShaderWarmUp] can be provided to [runApp] to replace | ||
/// this default warm up function. | ||
ShaderWarmUp defaultShaderWarmUp = (Canvas canvas) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can define the function as void defaultShaderWarmUp(Canvas canvas) {
and it will still be assignable to ShaderWarmUp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I intentionally wrote ShaderWarmUp
here to clarify that the canvas is expected to have a size of 1000x1000. (Otherwise, I could delete ShaderWarmUp
and just use the signature directly everywhere.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean in terms of how the function is declared:
ShaderWarmUp defaultShaderWarmUp = (Canvas canvas) { | |
void defaultShaderWarmUp(Canvas canvas) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understood that. My intention is that when developers see the signature of defaultShaderWarmUp
, they can discover a link to ShaderWarmUp
and realize that we're doing work on a 1000x1000 canvas. Does that help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you leave a comment in the dartdoc [ShaderWarmup]
they can follow that link as welll
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks!
]; | ||
|
||
// Warm up path stroke and fill shaders. | ||
for (Path path in paths) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're trying to make this as fast as possible, index iteration is slightly faster than an iterator protocol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might want to benchmark this. I'm not sure how true that really is in practice.
@liyuqian Is this ready to land? |
@goderbauer I guess so if the review from @jonahwilliams is a green light on the Dart side. BTW, as I'm digging emails, I see that we're in a tree freeze due to P0 Google3/Fuchsia roll failure. Should I wait the tree to be reopened before merging this? |
per the addition to runApp, I do not have a strong opinion on the API but others might |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with nit
CC @Hixie for the review of API change to |
@@ -0,0 +1,84 @@ | |||
import 'dart:ui'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please see the README in this directory.
This probably belongs in the painting
library, not foundation
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to painting. Painting was my first choice but analyze won't allow me to do that since I used it in scheduler, which creates a dependency loop. Now I've removed all changes to scheduler and ShaderWarmUp
is in painting again.
@@ -5,10 +5,11 @@ | |||
import 'dart:async'; | |||
import 'dart:collection'; | |||
import 'dart:developer'; | |||
import 'dart:ui' show AppLifecycleState; | |||
import 'dart:ui' show AppLifecycleState, Canvas, Image, Picture, PictureRecorder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the scheduler shouldn't know about these things. They have nothing to do with scheduling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed changes to scheduler.
@@ -1 +1,2 @@ | |||
const String kCullOpacityRouteName = '/cull_opacity'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing license
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -1,6 +1,7 @@ | |||
import 'package:flutter/material.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing license
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -0,0 +1,40 @@ | |||
import 'dart:async'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing license
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
/// 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, 1024); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use .0
on integral double literals
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cc @goderbauer |
This patch adds a default shader warm up process which moves shader compilation from the animation time to the startup time. This also provides an extension for This should reduce our worst_frame_rasterizer_time_millis from ~100ms to ~20-30ms for both flutter_gallery and complex_layout benchmarks. Besides, this should also have a significant improvement on 90th and 99th percentile time (50%-100% speedup in some cases, but I haven't tested them thoroughly; I'll let our device lab collect the data afterwards). The tradeoff the is the startup time (time to first frame). Our This also adds a cubic_bezier benchmark to test the custom shader warm up process. This should fix #813 (either by |
This reverts commit a44f174. Reason: start_up tests become flaky. See flutter#28374 TBR: xster
This reverts commit adc8e15.
I saw some back and forth with this PR in master, is now the final version merged? |
I assume that it's still janky when you reopen the app and run the animation for the first time? If so, I guess that it's caused by something else. Can you please run the gallery demo with |
The same happens after closing the app (where closing means really closing, not only sending to the background). Attached the trace. This is of a new installation, where I opened "Studies". Then for each of the 4 items inside, opened it and pressed back. There was jank in all of them (the push animation almost jumps to its finished state, in some more than the others). |
I can confirm that jittering on first startup still exists on iOS (just create any type of app with a list with 30 items with listview.builder and scroll it when you launch the app). |
I recommend that anyone running into slowness on startup file a bug with a small repro test case. There are probably many unrelated causes. This PR was to solve #813 which was specifically about the slowness in the Gallery. |
@Hixie My comment was about the gallery (not sure if you're addressing me as well). |
I think Hixie's comment is only for @msw333 . For that list with 30 items issue, it would helpful if @msw333 could create a new issue, attach the trace and a single-file Flutter app that can allow us to reproduce the issue. For @i-schuetz 's issue, yes it's currently still expected to have a little jank right after the new installation. Your trace is consistent with my local experiment with a new installation. But once I close the app and reopen it on my iPhone6S, the jank would disappear if I open the same item. Can you please confirm that it's also the case in your iPhone6? If not, can you please attach the trace of the second first-run after the installation? |
We care about first-run performance too, very much in fact. :-) |
Ok ;-). Hope that helps. Issue is observable in every flutter app I was using. iPhone X, 12.1.4 (iOS). How to reproduce:
Videos don't give it justice, but show the issue: Code to reproduce (just use as main.dart). Again, I can reproduce it with any flutter app on iOS. Jittering issue increases within apps with higher complexity: |
Moved to #28113 (comment) |
This patch adds a default shader warm up process which moves shader compilation from the animation time to the startup time. This also provides an extension for
runApp
so developers can customize the warm up process.This should reduce our worst_frame_rasterizer_time_millis from ~100ms to ~20-30ms for both flutter_gallery and complex_layout benchmarks. Besides, this should also have a significant improvement on 90th and 99th percentile time (50%-100% speedup in some cases, but I haven't tested them thoroughly; I'll let our device lab collect the data afterwards).
The tradeoff the is the startup time (time to first frame). Our
flutter run --profile --trace-startup
seems to be a little noisy and I see about 100ms-200ms increase in that measurement for complex_layout and flutter_gallery. Note that this only happens on the first run after install or data wipe. Later the Skia persistent cache will remove the overhead.This also adds a cubic_bezier benchmark to test the custom shader warm up process.
This should fix #813 (either by
defaultShaderWarmUp
, or acustomShaderWarmUp
).