Flare-Flutter
Flare-Flutter copied to clipboard
Huge performance difference versus Flutter animations
Hi there!
I made a test animation in Flare that moves up and down gradually. On a Google Pixel in profile mode I'm seeing an average 30ms on the GPU thread via the Flutter Performance Overlay.
If I pause the Flare animation and add a repeating SlideTransition doing the same thing, I see 10ms. This makes a huge amount of difference in frame rate on older devices. Is there a way to resolve this, or is it just part of how Flare renders? There's such a big difference it makes me feel like I'm doing something wrong...
I'm able to get comparable - or better - performance by changing from SVG paths to an image on the Flare side.
Found something really bizarre. If I set the height via SizedBox...
height: 610 and above + BoxFit.fitHeight on the FlareActor 41ms GPU
height: 609 and below + BoxFit.fitHeight on the FlareActor 19ms GPU
The frame rate gets cut in half the moment I use height 610 and above in conjunction with BoxFit.fitHeight.
Any idea what's going on here?
Interesting. We have seen cases where certain files cause an increase in GPU usage. We’ve been working with the Skia team to help track down what’s causing this. Could you share your file and perhaps some sample code?
I'm able to reproduce it on an iPhone X now as well, but it's not noticeable.
Here you go.
import 'package:flare_flutter/flare_actor.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
SizedBox(
// On a Google Pixel...
// height: 610: 24ms/avg GPU thread
// height: 609: 13ms/avg GPU thread
// On an iPhone X...
// height: 742: 5.2ms/avg GPU thread
// height: 741: 3.5ms/avg GPU thread
height: 610,
child: FlareActor(
'assets/test.flr',
animation: 'idle',
fit: BoxFit.fitHeight,
),
),
],
);
}
}
We have seen something like this before, where zooming in (or scaling up) vector content causes significantly more GPU usage. We don't have a good solution yet. Flare doesn't create buffers, textures, etc that change with resolution. We've been working with the Skia team to figure out if Flare does something unexpected that causes this, but we haven't found anything yet.
It may be related to graphics memory cache that Skia manages internally (see https://github.com/2d-inc/Flare-Flutter/issues/99).
The odd thing is that (at least on my iPhone X) it's not quite as deterministic as your results. Most of the time switching from a lower resolution to slightly higher causes something like triple the frame time usage (from 4ms/frame to 13.5 ms/frame), but other times I need to sort of bounce back and forth to let it finally bump to using more GPU time. There's definitely some sort of threshold that seems to get crossed which triggers it.
Another odd thing, after hot reloading a few times (just pressing r in the terminal) it bumped down to 5.6 ms/frame from 13.5 ms/frame (while still at the higher res). Then it stayed there until I pressed "r" a few more times (like maybe 10 times) and finally bumped back up to 13.5 ms.
It seems like the higher GPU usage is easier to reproduce in a release build on my iPhone X. Even at 241 pixel height it's using 16.3 ms/per frame. That's suspiciously close to the 16.6 limit before it drops frames. It actually does look like it drops a frame every once and a while.
Taking a screenshot and returning to the app temporarily improves GPU time (maybe GPU context gets re-initialized?) but it will quickly return to using 16.3 ms per frame. Here's a video of that: https://drive.google.com/file/d/1SOzHBo9xD7pjivjseM98PdFGAyJft7u3/view?usp=sharing
I'd like to try to create an example that renders animated vector content (without Flare) that exhibits the issue as I think it'll make it easier for the Flutter team to debug. In the meantime, I will log an issue with this on their side too.
Yeah, I’ve experienced this also. I assumed it was due to this: https://github.com/flutter/flutter/issues/31086
iPhone X refresh rate can essentially become de-synced and drop half the frames. I’ve noticed pulling the control center down and back up fixes it like in your screen cap.
I haven’t tried out the fix there but I’m interested if that fixes this. Any interest in trying that out?
I've submitted an issue on the flutter repo with an isolated example (no Flare) that has similar performance problems reported here.
Regarding the scrolling issue, it seems like that's related to perceived jank from scrolling on iOS, partly due to input events reporting irregularly (and sometimes multiple times) per frame. I'm not sure if that'll help here as I see the problem without any input, but it's worth trying.
@luigi-rosso Watch this...
This is so painful for us. Any update here?
@stx I haven't heard anything else on the Flutter thread. Saw you pinged on there, I'll wait to see if there are further replies.
In the meantime, removing antialiasing can help a lot. We get around the quality hit in Flare by enabling anti-aliasing on the WebGL context (depends on implementation but I think most hardware uses MSAA) and disabling it in Skia. Helps GPU usage quite a bit. Quality hit is noticeable but acceptable when performance is being impacted. I suspect it won't help with the timing issues mentioned in the Flutter issue thread, but it's worth a shot. It may require some tinkering with the Flare codebase, but you could try telling every Paint created by Flare to not use antialiasing and compare results.
@luigi-rosso Oh wow, that makes an incredible difference on Android devices!
As an example, the Google Pixel went from 37.7ms to 13.9ms from with no discernible reduction in image quality. It went from "unusably terrible" to "fantastic" - on our devices, with our style of textures and animation, removing anti-aliasing isn't noticeable unless the device is a few inches from your face.
Specifically, this came from adding ..isAntiAlias = false to FlutterFill.initializeGraphics's ui.Paint() call in flare.dart, but I added it to all the other Paint calls just to be safe with a variety of assets.
This was totally a game changer for our Android release, thank you. I really think this should be a front-facing option without framework hacks. It makes too much of a difference. Unless this is being fixed soon on the Flutter end, of course.
Interestingly, on an iPhone X, this 16ms "stuck" GPU load persists, but it automatically dips back down to 5ms a just a hair bit more often. This doesn't seem to have any real impact on it. Do you have experience otherwise?
If you know of any other performance tweaks like this, please share!
Any updates on this? Currently Flare performance is quite poor on something like a Pixel 1, struggling to maintain even 30fps with a single quarter-screen animation.
Exposing the antialias setting would be a nice start, but hopefully performance overall can be improved?
We'll add an option to expose the aliasing setting soon which should help particularly on devices with older GPUs.
Make sure you're testing in release/profile. Flare is usually GPU bound, unless you're running in debug mode where it is generally CPU bound.
Sweet, that would be great. I was running in profile mode, it was the Teddy anim from your examples, and I was getting about 28fps on device. 40fps or so once I disabled AA. The phone (Pixel1) is about 2.5yrs old, but the Adreno 530 GPU is fairly capable AFAIK.
I am also interested about how to change anti-aliasing option, because on Galaxy J6 a simple flare animation in the background kills performance...
Any update on exposing the anti-alias setting? I had to go through the 'hack' of copying all classes just to edit a few lines of code.
Hey, is there any news about AA turning off? Thanks!
Heelo, they are news about this problem ?
Don’t laugh but I’m interested if AA will help with performance on a device like the nexus 5.
Does anyone have a timeline on when this will be released or is the only workaround to copy down the classes and modify all the paint calls for it to work?
Last question, has there been any solutions to fix that 16ms GPU load on iPhone’s?
Seems like the newest version 2.0.5 has ability to disable anti-aliasing https://pub.dev/packages/flare_flutter/changelog
@orestesgaolin thanks for pointing it out, we merged the PR a few days ago. Let us know if this improved performance!
Where can we find the usage/example of how to disable anti-aliasing?
Where can we find the usage/example of how to disable anti-aliasing?
We update the our 'simple' example with a button that does it on demand.