ryanmcgrath/cacao

`examples/animation.rs` is laggy

Opened this issue · 13 comments

Title. Running on M1 Mac mini and feels like it should be faster. Is there anything making this slower than native Obj-C AppKit?

Just to follow up: if I run the example via

cargo run --release --example animation

Then I don't see any more lag than typical AppKit-based animations in other apps I've written. This is on an M1 2020 MBP... but if I can see a video or find a way to reproduce I'm more than happy to debug it further. :)

Maybe laggy is the wrong word. I'd say it "stutters". It's not 100% clean, but maybe this is just AppKit?

Screen.Recording.2022-08-01.at.00.03.13.mov

Small framerate drops / jumping / skipping. This is in release mode.

Hmmm, okay, so we're on the same page. That I can definitely replicate.

Unfortunately it is hard for me to tell if AppKit can do any better here - whenever I've built ObjC-based apps in the past, I've noticed the animations aren't always the smoothest things in the world unless you're getting down in the CoreLayer/etc weeds. A good example is that even a standard insert-slide-down on an NSTableView row will often be slightly stutter-y for me.

That all being said, I'm definitely open to being proven wrong here - maybe there's something throwing off the smoothness? Everything should be layer-backed by default here, which - as far as I understand things - means that animations should be taking the smoothest path. I don't know if the ObjC/Rust side of things would be enough to interrupt and cause the stutter here, but I suppose anything's possible.

What probably makes sense is for someone to knock together this demo but in straight up ObjC and see if it mirrors with stuttering. If it does, then it's likely AppKit - and maybe we can do something to work with it. If it doesn't, then there may be something on the Rust/cacao side we'd need to look at.

As a quick extra bit, I started a branch (debug/animation-timing) to mess with some things regarding this. In particular it exposes the ability for NSView to combine sublayers into one root layer; if you'd like to re-run the animation example from there, I would be curious if it's any better for you.

(The animation example also has corner radius on the views disabled, but you can uncomment that line in the example to try it with them as well)

Screen.Recording.2022-08-01.at.18.08.37.mov

Still persists. It's the most visible for the last frames of the green rectangle moving down and right.

What probably makes sense is for someone to knock together this demo but in straight up ObjC and see if it mirrors with stuttering. If it does, then it's likely AppKit - and maybe we can do something to work with it. If it doesn't, then there may be something on the Rust/cacao side we'd need to look at.

I personally don't know Objective-C at all, so that'd be hard for me to do. Maybe that'd be something you could try?

Although I don't know what the problem here might be, I find it hard to believe that this is an AppKit bottleneck, since I haven't seen FPS drops like this on other Mac apps before? And I think a simple app like this should run smoothly on modern hardware, no?

I personally don't know Objective-C at all, so that'd be hard for me to do. Maybe that'd be something you could try?

My current schedule is pretty busy but I can look at doing this at some point, yeah - and we can keep this issue open as a tracking issue in case any drive-by contributors want to dig in and see what they can find.

Although I don't know what the problem here might be, I find it hard to believe that this is an AppKit bottleneck, since I haven't seen FPS drops like this on other Mac apps before?

Well, at the end of the day, the flow that's happening here is:

  • A button (w/a/s/d is hit)
  • Closure is created that sets the animation points for the animation
  • NSAnimationContext takes that closure and executes it

Which is all to say that there's not enough overhead here to be causing that, which makes me think that there's something off about how AppKit and layer-backing is working here. I've definitely seen this kind of stuttery animation in other macOS apps before, but that being said there's also absolutely examples of it being smooth - so this is really just about figuring out why it's not smooth. :)

As an aside, I updated the debug/animation-timing branch to expose the ability to set the underlying layer contents redraw policy. The animation example is updated for this as well.

The rationale is that Apple notes that the default layer redraw policy might not necessarily be the ideal one for performance, particularly on layer-backed-views where the layer is handled by AppKit. Even if this isn't necessarily the fix, these are probably good things to provide easy access to for people who'd want to tweak for performance reasons.

(I'd need to clean up the code in this branch before merging it, but this is all still debugging/exploring anyway)

Heya, was curious if you'd had a chance to look at the updates on debug/animation-timing?

Poking one more time~

Will merge my fixes if no response in the next week or so since they are slightly smoother on my machine anyway. Thanks for bringing it up!

@ryanmcgrath Thanks for your work on the bindings.

The animations are pretty smooth on an my Intel MacBook.

CPU: 8350u
GPU: Integrated
macOS: 13.4

Screen.Recording.2023-07-24.at.1.41.28.AM.mov

Perfect, then I'll go ahead and include that branch in 0.4. Thanks for testing!