mapbox / mapbox/mapbox-maps-ios

CircleLayer animations consume the CPU

Open
#1,191 12 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

auto-triaged bug :beetle:
Dominant language
Swift
Stars
601
Forks
196
PR merge metrics
No merged PRs in 30d

Description

## Environment

- Xcode version: 13.2.1
- iOS version: 15.3.1
- Devices affected: All
- Maps SDK Version: 10.3.0

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.](https://gist.github.com/johnnewman/266f921682ce799aed24765e04a10a04)
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.](https://gist.github.com/johnnewman/b2b76aae3cde66b1e3a0d77555647b93)

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

- [Gist using transition properties](https://gist.github.com/johnnewman/266f921682ce799aed24765e04a10a04)
- [Gist rapidly updating circle properties in a loop](https://gist.github.com/johnnewman/b2b76aae3cde66b1e3a0d77555647b93)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the CircleLayer animation with the transition-property and rapid-update approaches shown in the linked Gists on the listed iOS devices. Profile CPU usage while the pulse runs and compare it with the UIView/Core Animation baseline. Done means identifying and addressing the performance issue so CircleLayer animation approaches the reported under-20% CPU target on a recent device.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, swift
Domain
mobile-dev, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.