-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Map view lags behind annotation views when panning #5489
Comments
Please post more information about the view you’re using — code and a gif would be ideal. Thanks. |
ok, I'll save something as a gif video tomorrow. |
Thanks for the image, @Paladinfeng. Syncing the movement of native views with the map is an ongoing challenge, certainly. |
I suspect #5245 may yield some improvement, specifically disabling animations while updating annotations and coalescing the frame updates into one Core Animation transaction. I’ll need to pull those changes out into a separate PR and see if they improve things on their own, without the other matrix-related changes. |
The changes in #5245 don’t address this issue after all. As far as I can tell, the map is lagging behind the annotation views by one frame every other frame or so. In the screen recording below, keep an eye on the annotation view that initially covers up the word “Washington”. When I scroll up, you can occasionally see “Washington” appear to the south of the annotation view; when I scroll down, you can occasionally see “Washington” appear to the north of the annotation view: |
One potential way to eliminate the "tearing" effect might be to put the annotation updating phase into a custom style layer drawing callback. This would ensure that the Core Graphics and Core Animation drawing commands occur closer to the OpenGL drawing commands and in the same run loop iteration. Ironically, the annotation views would be less performant, but the perceived performance would improve. |
Naive post to related issue, before further investigation: #1813 |
#1813 in some respects addresses the opposite issue: the map was leading the UIView because the map was given the opportunity to advance one step (for a transition) before the UIView got a chance to update. The annotation view implementation addresses this by updating the frame on the "map did finish rendering frame" notification. I think what we're seeing is that Core Animation / Core Graphics manages to maintain 60fps drawing of the annotation views even as MGLMapView struggles to do the same with the underlying map. We mitigated that for the user dot in #3683 by disabling implicit animation, but the root cause can still be reexposed by adding multiple views onto the map. |
Removed unused annotation image code from iosapp, now that bulk-added point annotations are backed by annotation views.
Here's a good debug snippet against 0ae941d that easily shows the problem on panning: diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index df1c446..173bb39 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -75,6 +75,13 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
[self restoreState:nil];
self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
+
+ self.mapView.pitchEnabled = NO;
+ self.mapView.rotateEnabled = NO;
+
+ [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(38.913343209724644, -77.033041982152554) zoomLevel:11 animated:NO];
+
+ [self parseFeaturesAddingCount:100 usingViews:YES];
}
- (void)viewDidAppear:(BOOL)animated
@@ -709,7 +716,7 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
if (!annotationView)
{
annotationView = [[MBXAnnotationView alloc] initWithReuseIdentifier:MBXViewControllerAnnotationViewReuseIdentifer];
- annotationView.frame = CGRectMake(0, 0, 10, 10);
+ annotationView.frame = CGRectMake(0, 0, 50, 50);
annotationView.backgroundColor = [UIColor whiteColor];
// uncomment to make the annotation view draggable |
Probably minor compared to actual proper view syncing, but we very frequently run this pointless conversion for annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self];
|
As we've noted noted in #5787, we've been waiting for #5165 to land (it was just merged) so that we can optimize the |
I've done a number of tests with
The Chasing the rabbit hole of
seems to be |
The above doesn't make sense in the context of the current, pre-annotation view merged |
The primary difference is that we update the user location annotation right inside |
Specifically, a67e802. |
While I can see the potential of what @1ec5 states in #5489 (comment), I can't see why the user dot would behave differently. I even tried just a single annotation view to more closely match the scenarios. But moving things into |
The more I think about this, the more I think it will have the same effect as adding just one annotation view to the map (or the user dot). We've still got to test that scrolling with |
Punting on this for now—couple higher priority issues in the hopper. |
The macOS SDK also sees poorer base map rendering performance compared to the GLFW app, except when you turn off CALayer compositing. Considering that you can't turn off CALayer compositing on iOS, what approaches can we take to speed up the map? Tear out CADisplayLink? What approaches can we take to slow down annotation views? Tie them to CADisplayLink with a slower refresh rate? |
@incanus and @1ec5 . The following WWDC session talks about exactly the same problem (synchronizing opengl map view with UIViews). Can you please also try out that as well? I've copy pasted the relevant links and sections below. WWDC video link Text notes here http://asciiwwdc.com/2015/sessions/233 "Now this may be a problem if you want those two to be in sync, and that could happen, for example, if you had an OpenGL map view, that you wanted to draw UIKit content on top of. In that case, you may want to synchronize those updates in something like this, and there's a property that allows you to do that called Presents With Transaction. It's on CAeagllayer and CAMetalLayer. When this is set to False, which is the default value, then it will get your GPU content to the display as quickly as possible. But when you set it to True, then we synchronize your GPU content with the Core Animation content so they both appear on the display at the same time. |
Yes, but per http://stackoverflow.com/a/30722276/977220 it's iOS 9+ 😞 |
@incanus This should be fine. iOS 9 is over an year old and installed on over 75% devices(as of Jan 2016). We can use respondsToSelector to make sure that things work well on iOS9 devices (while lagging behind on older devices). |
Yeah, good point. We are currently in discussions about dropping iOS 7 but opportunistically using this for 9+ may be an option. |
Will continue to investigate this, but for a lot of use cases (particularly small view annotations) current performance is acceptable. |
@mb12, thanks for the reminder. We previously looked into |
The good news: I have figured out the problem and have a local version working nearly perfectly. The bad news: We need to get a higher frame rate on our core GL draws to solve it. This is essentially what @1ec5 has been hypothesizing since #5489 (comment), but I think I have confirmed it. I tried a number of approaches to get the annotations & Core Animation to slow down and/or draw in sync with the OpenGL frame updates:
None of these reduced jitter since what we perceive as jitter is the position relative to the map, and the map isn't moving as smoothly as it could. Also, just to be sure, I experimented with:
It was that last one that still looked suspect to me, especially when using Apple Maps to compare, and profiling confirmed that I was only ever seeing ~30fps for a default Streets style (on a couple years old but respectable retina iPad mini). I pared back a style in Studio until I could get one that was consistently 55-60fps: Portland This mostly involved getting rid of all labels, symbols, and roads and just leaving fills like water and parks. But: once I did this, and got the OpenGL frame rate to about 60fps, I got some good-looking sync: You can still see this jitter a tiny bit when we dip into the ~55fps range, which is to be expected. The test style URL in question is So, again I think we punt on this for now as there is no magic Core Animation bullet to help us. We need to get our frame rate up with arbitrary styles, which is a more difficult proposition than what Apple Maps does with its one or two default styles. /cc @jfirebaugh @kkaefer |
To be complete: I also changed the |
You can also see the map lagging behind the view in the GIF (!) in #5489 (comment) – that effect wouldn't be possible if not for the map rendering at far less than 60 fps. We added CADisplayLink in order to throttle map redraws (originally to 30 fps, later to 60 fps, nominally). Should we revisit our use of that API? It has its own performance downsides: #2985. |
Will read up on As a clarification, when I say Core Animation in the context of this problem, I mean the mechanism by which native views are composited to the frame buffer on the device. Even though we no longer actually animate our annotation views, the mere movement of them pixel-by-pixel is governed by internal OpenGL rendering on Core Animation's part and that is a solid 60fps, thus highlighting weaknesses in our own frame draws. |
@Paladinfeng, FYI, the equivalent issue on Android is being tracked in #6139. mapbox/mapbox-gl-js#3273 is a conceptually similar issue in GL JS. |
@incanus in the end, can you resolve the sync problem? |
I’ve split out #12740 to track a separate synchronization issue that only affects the user dot but not other annotation views. That issue includes a possible explanation as to why the user dot behaves differently than other annotation views. |
Fixed in #12895. |
*_Platform: iOS 9.3.2
*_Mapbox SDK version: v3.3.0-beta2
I found the MGLAnnotationView scrolling like jello when I use the new iOS SDK. The MGLAnnotationView can't follow the MapView smoothly. I have tested at iPhone 5s and iPhone 6.
The text was updated successfully, but these errors were encountered: