Flare-Flutter icon indicating copy to clipboard operation
Flare-Flutter copied to clipboard

Huge performance difference versus Flutter animations

Open stx opened this issue 6 years ago • 22 comments

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...

stx avatar Aug 03 '19 01:08 stx

I'm able to get comparable - or better - performance by changing from SVG paths to an image on the Flare side.

stx avatar Aug 03 '19 01:08 stx

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?

stx avatar Aug 03 '19 02:08 stx

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?

luigi-rosso avatar Aug 03 '19 02:08 luigi-rosso

I'm able to reproduce it on an iPhone X now as well, but it's not noticeable.

Here you go.

test.flr.zip

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,
          ),
        ),
      ],
    );
  }
}

stx avatar Aug 03 '19 03:08 stx

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.

luigi-rosso avatar Aug 03 '19 18:08 luigi-rosso

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?

stx avatar Aug 03 '19 21:08 stx

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 avatar Aug 03 '19 21:08 luigi-rosso

@luigi-rosso Watch this...

This is so painful for us. Any update here?

RPReplay_Final1567725727.MP4.zip

stx avatar Sep 05 '19 23:09 stx

@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 avatar Sep 06 '19 07:09 luigi-rosso

@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!

stx avatar Sep 09 '19 00:09 stx

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?

esDotDev avatar Oct 02 '19 07:10 esDotDev

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.

luigi-rosso avatar Oct 02 '19 11:10 luigi-rosso

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.

esDotDev avatar Oct 02 '19 22:10 esDotDev

I am also interested about how to change anti-aliasing option, because on Galaxy J6 a simple flare animation in the background kills performance...

addaedans avatar Oct 06 '19 07:10 addaedans

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.

ovidiu-anghelina avatar Nov 08 '19 10:11 ovidiu-anghelina

Hey, is there any news about AA turning off? Thanks!

tsinis avatar Dec 21 '19 19:12 tsinis

Heelo, they are news about this problem ?

NaosFr avatar Apr 27 '20 12:04 NaosFr

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?

a7medpa avatar May 25 '20 05:05 a7medpa

Seems like the newest version 2.0.5 has ability to disable anti-aliasing https://pub.dev/packages/flare_flutter/changelog

orestesgaolin avatar Jul 31 '20 14:07 orestesgaolin

@orestesgaolin thanks for pointing it out, we merged the PR a few days ago. Let us know if this improved performance!

umberto-sonnino avatar Jul 31 '20 16:07 umberto-sonnino

Where can we find the usage/example of how to disable anti-aliasing?

a7medpa avatar Jul 31 '20 16:07 a7medpa

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.

umberto-sonnino avatar Jul 31 '20 16:07 umberto-sonnino