IFTTT/JazzHands

Speed up adding keyframes

dvkch opened this issue · 10 comments

Hi,

Adding keyframes seems to regenerate the animation timeline at each new frame. I understand that to change the behaviour you would have to break the compatibility with previous versions so I propose adding a macro or something to disable the behavior, combined with a new method like commitKeyframes or createTimeline that would sort keyframes and generate the timeline. Also maybe adding an optional parameter (BOOL)commit to the addKeyFrame method on the animation base class could be also nice.

By implementing this I dropped my animation creations from 1.86s down to 0.85s on iPhone4/iOS6. Agreed, I do have a lot of animations, but still this could still be a nice improvement!

I can make a pull request if you want, but I reckon you may prefer do it yourself(ves).

Keep up the good work!

PS: if there is any other room for improvement, I would love to hear about it!

I continued down this path and found out that completely removing the timeline works pretty well. I currently have 52 animations (mostly alpha and frame, but also 4 3D) totalling 171 keyframes, and on iPhone 4 iOS6 it runs at 27FPS in worst case scenario: animating frames + alpha of 15 views between two pages, including 14 views that have a shapeLayer as main layer, and 3 of them are constantly animating their stroke lineWidth. When using the timeline it culminates at 29FPS in the same situation, but creating the time line takes ~2secs (~1sec with above adjustments). I could come back to 29FPS by caching intermediary frames in an NSDictionary using their time for key. This way when the user goes sees multiple time the same animations (say (s)he goes back to re-read something) the animation is fluid. I suggest the following changes:

  • adding a +defaultTimelineMode class-level property, constrained to the following enum values:
    • autoUpdate : current behaviour
    • updateOnCommit : doesn't update the timeline when adding a keyframe, waits for a call to commitKeyFrames
    • ignore : do not generate timeline at all
    • runtimeCache : don't generate timeline, cache computed frames
  • adding a -commitKeyFrames or -updateTimeLine method to force generation of all frames
  • adding -timelineMode with default value set to +defaultTimelineMode but customisable, in case these changes don't play well with some scenarios

Other solutions could involve:

  • overload method addKeyFrames: with -addKeyFrames:commit: and move the code from addKeyFrame: to addKeyFrames: (if you don't consider any other changes, please at least do that one)

Thanks in advance for considering those changes. Again I could make a push request but I'll maybe wait for your opinion on all this before.

Great day to you,

Stan

dvkch commented

I finally created a fork with the above optimizations here is the readme

Ahoy @dvkch, kudos to you on a clean public API and a solid implementation. Your readme mentions:

I use this fork in a app that contains 130 animations and a total of 450 keyframes, on iPhone 4 iOS6 creating the animations went from > 20secs to < 20ms, and moving through the timeline has more than 4x the original performances.

Are these animations created only once, upfront? How does this app perform on newer hardware?

dvkch commented

Hey @jhersh

Thanks!

I use JazzHands for a tutorial. All those animations are created in the view controller viewDidLoad method for the current interfaceOrientation. When user flips the device the animations are created again for the new orientation, so I have 2 animators one for portrait and one for landscape. Once created the animator is kept in memory, so yes I think you can say the animations are created up front. Since I need the view controller to appear quickly 15secs on iPhone 4 had to be improved, it needs to rotate quickly too, and animate if possible in less than 16ms for 60fps rendering. I am now really close to this on iPhone 4, and all devices above (tested on 5 iOS7, 6 iOS 8 and iPad mini 2 iOS 8) perform at 60fps. If you need anymore information feel free to ask. I'm thinking about open sourcing the app asap so you'll be able to test on it.

dvkch commented

These optimization are also needed in my project because I have views backed up by UIBezierPath or custom image processing tools that performs really slow if updated to often

Thanks! I like that these optimizations are opt-in with a default that matches the current behavior. I would be happy to merge a pull request with these changes.

dvkch commented

That was the goal. I am thinking about making an enum for timeline optimization (current behavior allows mutually exclusive options to be enabled together like noCache and onTheFlyCache) and another bitwise enum for other optimization. I'll keep the default behavior + default class method + member property. When done I'll let you review before making a PR. Would that be okay with you?

Sent from my iPhone

On 21 Feb 2015, at 20:08, Jonathan Hersh notifications@github.com wrote:

Thanks! I like that these optimizations are opt-in with a default that matches the current behavior. I would be happy to merge a pull request with these changes.


Reply to this email directly or view it on GitHub.

👍

@dvkch Jazzhands 2.0 gets rid of the animation timeline entirely, switching over to fetching the interpolated values lazily as the animator calls for them. This should get rid of the expensive up-front array allocations that addKeyframe was triggering. I'd love any feedback you have about how the performance looks to you!

dvkch commented

I'll take a look as soon as I get a chance ;) I was done with my fork last week and working on a graph to show which optimization can be best to setup depending on use cases. Great idea removing it by the way! Do you cache the values?

Sent from my iPhone

On 22 Jun 2015, at 19:58, Laura Skelton notifications@github.com wrote:

@dvkch Jazzhands 2.0 gets rid of the animation timeline entirely, switching over to fetching the interpolated values lazily as the animator calls for them. This should get rid of the expensive up-front array allocations that addKeyframe was triggering. I'd love any feedback you have about how the performance looks to you!


Reply to this email directly or view it on GitHub.