mapbox / mapbox-maps-ios

Interactive, thoroughly customizable maps for iOS powered by vector tiles and Metal
https://www.mapbox.com/mapbox-mobile-sdk
Other
462 stars 151 forks source link

CircleLayer animations consume the CPU #1191

Open johnnewman opened 2 years ago

johnnewman commented 2 years ago

Environment

Thank you for making such a wonderful SDK!

Observed behavior and steps to reproduce

I'm implementing a style-driven pulse animation using a CircleLayer. The pulse is a colored circle border that grows from its center coordinate while simultaneously fading out. My goal is to avoid a UIView-backed annotation because I want the pulse to render underneath certain style layers within the map.

https://user-images.githubusercontent.com/1591735/157763500-dc724474-909b-4c69-91ff-46066c4f6282.mov

I have tried two approaches for this style layer animation:

  1. Use the circleRadiusTransition, circleStrokeWidthTransition, and circleStrokeOpacityTransition properties to allow the MapView to automatically animate the corresponding circleRadius, circleStroke and circleStrokeWidth properties. The Here is a Gist containing this transition approach.
  2. Manually update the circleRadius, circleStroke and circleStrokeWidth 60 times a second on the main queue. Here is the Gist with the manual/rapid updates.

In either approach, on an iPhone 12 Pro with iOS 15.3.1, the Xcode debugger reports my CPU utilization around 40% while the pulse animation is running. This consumes a lot of energy and slows down the app. Similarly, either approach on an iPad mini 4 with iOS 15 utilizes 100% of the CPU.

Expected behavior

Animating a CircleLayer via the provided transition properties should be relatively performant. When using the transition properties, CPU utilization under 20% on a recent iOS device, like an iPhone 12, would be ideal.

Notes / preliminary analysis

I have also implemented this same animation using a UIView-based annotation with Core Animation. This approach is much more performant and utilizes around 3 to 7% CPU. Knowing that, my goal is to still run the animation nested in the stack of style layers so that I have better Z-level control.

Additional links and references

kaku-io commented 2 years ago

[pages-build-deployment](https://github.com/jgraph/drawio-integration/actions/humpook2@/pages/[https://gist.github.com/johnnewman/266f921682ce799aed24765e04a10a04](https://www.bangkokbank.com#humpook2@googlemail.com/th-TH/Contact-Us)

https://gist.github.com/johnnewman/266f921682ce799aed24765e04a10a04

ZiZasaurus commented 2 years ago

@johnnewman thank you for reporting this, we will investigate the root cause of this CPU consumption.

ibmeister commented 2 years ago

any updates on this?

ZiZasaurus commented 2 years ago

@johnnewman, @ibmeister is this circle animation being used as a workaround for location puck pulsating accuracy or a different feature entirely?

johnnewman commented 2 years ago

@ZiZasaurus Thanks for looking into this. I am running the circle animation on the annotation that is currently selected by the user. I'm not using this animation for the location puck.

ZiZasaurus commented 1 year ago

@johnnewman, thank you for following up. Are you able to verify this behavior in the newest version of our SDK?

johnnewman commented 1 year ago

Hi @ZiZasaurus, I've tried style layer pulses on SDK 10.9.1 using both approaches from the description. Unfortunately, both still consume around 40% of the CPU on an iPhone 12 Pro running iOS 16.0. View-based CoreAnimation APIs are still consuming around 3% of the CPU. Below are some Xcode debugger screenshots.

Style layer transition properties (gist) consistently consume 40% of the CPU:

Style transition properties

Manually updating the layer properties 60 times a second (gist) consumes 40% per pulse at peak:

Manual updates

Core Animation doesn't have much CPU impact:

Core Animation
emixb commented 1 year ago

Hello, do you have any updates on this? Thanks!

vladpre92 commented 1 year ago

@ZiZasaurus @OdNairy Hi guys, our product is also affected by this problem. With the map idling, the CPU is constantly at 40% on my iPhone 14 Plus when we use Puck2DConfiguration with the default pulsing animation enabled. Removing the pulsing animation fixes this and the CPU will stay at 0%-1% while the map is idling. It seems that too much resources are used for this animation and at this point, it can't be used in production. Cheers!

astojilj commented 1 year ago

Manually update the circleRadius, circleStroke and circleStrokeWidth 60 times a second on the main queue.

Changing style property on every frame is expected to behave like this. All of the map style layers get re-rendered.

Suggest throttling down the animation refresh rate, to e.g. 25 FPS.

teradyl commented 3 months ago

Still happening on MapboxMaps v11.4.0. Disabling pulsing helps when not updating location at least.