alex-i alex-i - 26 days ago 21
iOS Question

`animateKeyframesWithDuration` - high GPU

I've added a relatively simple animation that runs continuously. This is used to briefly switch to another view for a couple of seconds.

While the animation is running, the GPU jumps from <5% to a constant 30-40% on an iPhone 6 (iOS 9.2.1), while the 'Energy Impact' (Activity Monitor) on the simulator goes way up. Note that the actual animation only takes a small portion of the time (code at bottom), yet the GPU stays high the entire time. Setting a non-transparent background to the views that are animated doesn't improve things.

While the animation looks smooth, this seems weird, so I'm wondering if there's something I miss or doing wrong, or if there's some known bug regarding the

animateKeyframesWithDuration
method.

Below is a simplified code sample that leads to the same high GPU consumption:

v1.alpha = 0;
[UIView animateKeyframesWithDuration:10 delay:0
options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat | UIViewKeyframeAnimationOptionCalculationModeLinear
animations:^
{
[UIView addKeyframeWithRelativeStartTime:0.9/10 relativeDuration:0.1/10 animations:^{
v2.alpha = 0;
v1.alpha = 1;
}];
} completion:nil];


Thanks.

Edit to add some notes:


  1. The animation doesn't go idle, even if there's no animation instructions set for a specific time fraction of the animation (e.g.
    addKeyframeWithRelativeStartTime
    added just for 1/10 of the total animation time).

    Being so,
    animateKeyframesWithDuration:
    may not be the best solution for animations with an 'idle' time (as in the code example above) - a better performance can be achieved by using a timer for instance, which starts the actual animation(s) when needed.

  2. All layers that are part of the animation will animate the entire time (in the example above, v1.layer and v2.layer) - again, if there's no specific instruction set for a given time fraction, it won't go idle (it'll keep redrawing and consuming GPU, unless it's no longer visible).

  3. Regarding the performance, it is comparable to other CoreAnimation animations.

    The draw code for the animations seems to be handled only internally - draw methods from
    UIView
    or
    CALayer
    are not being called during the animation. This makes it that animating any views will have similar performance results (e.g. a view/layer that draws a full rectangle will not be more performant than a
    UILabel
    or a more complex view/layer).



Edit 2:

On iOS 10 (as well as Mac OS Sierra), the animations take up a lot less resources.

Answer

Animation is performed on a background thread and is managed frame by frame on the GPU by a special process (the "animation server"). The duration is of no interest here; you are set up to repeat forever, so that animation server has to keep performing the animation forever. That, as you've discovered, is not free. Every frame is a new calculation and a new drawing. That takes work. It doesn't get easier for the animation server to do this just because it has done the "same" animation once already. (The iPhone is not some sort of magical perpetual motion machine!)