[ios] Enable/disable presentsWithTransaction to address #14232 (#14307)

This commit is contained in:
Julian Rex
2019-04-03 11:50:11 -04:00
committed by GitHub
parent 100c9b7bc1
commit c7b709c5af
2 changed files with 142 additions and 12 deletions

View File

@@ -24,6 +24,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Added `MGLOrnamentPosition` enum and margin properties to customize scale bar, compass, logo, and attribution position within the map view. ([#13911](https://github.com/mapbox/mapbox-gl-native/pull/13911))
* Added an `MGLMapView.prefetchesTiles` property to configure lower-resolution tile prefetching behavior. ([#14031](https://github.com/mapbox/mapbox-gl-native/pull/14031))
* Speculatively fixed a performance issue seen on iOS 12.2, when an `MGLMapView` is repeatedly removed and re-added in a view hierarchy. ([#14264](https://github.com/mapbox/mapbox-gl-native/pull/14264))
## 4.9.0 - February 27, 2019

View File

@@ -156,6 +156,10 @@ const CGFloat MGLAnnotationImagePaddingForCallout = 1;
const CGSize MGLAnnotationAccessibilityElementMinimumSize = CGSizeMake(10, 10);
/// The number of view annotations (excluding the user location view) that must
/// be descendents of `MGLMapView` before presentsWithTransaction is enabled.
static const NSUInteger MGLPresentsWithTransactionAnnotationCount = 0;
/// An indication that the requested annotation was not found or is nonexistent.
enum { MGLAnnotationTagNotFound = UINT32_MAX };
@@ -252,6 +256,7 @@ public:
@property (nonatomic) MGLAnnotationContainerView *annotationContainerView;
@property (nonatomic) MGLUserLocation *userLocation;
@property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier;
@property (nonatomic) BOOL enablePresentsWithTransaction;
/// Experimental rendering performance measurement.
@property (nonatomic) BOOL experimental_enableFrameRateMeasurement;
@@ -328,6 +333,9 @@ public:
CFTimeInterval _frameCounterStartTime;
NSInteger _frameCount;
CFTimeInterval _frameDurations;
BOOL _atLeastiOS_12_2_0;
}
#pragma mark - Setup & Teardown -
@@ -441,6 +449,7 @@ public:
{
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
_opaque = NO;
_atLeastiOS_12_2_0 = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){12,2,0}];
BOOL background = [UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
if (!background)
@@ -681,6 +690,20 @@ public:
static_cast<uint32_t>(self.glView.drawableHeight) };
}
+ (GLKView *)GLKViewWithFrame:(CGRect)frame context:(EAGLContext *)context opaque:(BOOL)opaque
{
GLKView *glView = [[GLKView alloc] initWithFrame:frame context:context];
glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
glView.enableSetNeedsDisplay = NO;
glView.drawableStencilFormat = GLKViewDrawableStencilFormat8;
glView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
glView.layer.opaque = opaque;
glView.contentMode = UIViewContentModeCenter;
return glView;
}
- (void)createGLView
{
if (_context) return;
@@ -692,21 +715,14 @@ public:
// create GL view
//
_glView = [[GLKView alloc] initWithFrame:self.bounds context:_context];
_glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_glView.enableSetNeedsDisplay = NO;
_glView.drawableStencilFormat = GLKViewDrawableStencilFormat8;
_glView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
_glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
_glView.layer.opaque = _opaque;
_glView = [MGLMapView GLKViewWithFrame:self.bounds context:_context opaque:_opaque];
_glView.delegate = self;
CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
eaglLayer.presentsWithTransaction = YES;
eaglLayer.presentsWithTransaction = NO;
[_glView bindDrawable];
[self insertSubview:_glView atIndex:0];
_glView.contentMode = UIViewContentModeCenter;
}
- (UIImage *)compassImage
@@ -1101,6 +1117,13 @@ public:
{
MGLAssertIsMainThread();
// Not "visible" - this isn't a full definition of visibility, but if
// the map view doesn't have a window then it *cannot* be visible.
if (!self.window) {
return;
}
// Mismatched display link
if (displayLink && displayLink != _displayLink) {
return;
}
@@ -1113,8 +1136,28 @@ public:
[self updateUserLocationAnnotationView];
[self updateAnnotationViews];
[self updateCalloutView];
[self.glView display];
#ifdef MGL_RECREATE_GL_IN_AN_EMERGENCY
// See https://github.com/mapbox/mapbox-gl-native/issues/14232
// glClear can be blocked for 1 second. This code is an "escape hatch",
// an attempt to detect this situation and rebuild the GL views.
if (self.enablePresentsWithTransaction && _atLeastiOS_12_2_0)
{
CFTimeInterval before = CACurrentMediaTime();
[self.glView display];
CFTimeInterval after = CACurrentMediaTime();
if (after-before >= 1.0) {
dispatch_async(dispatch_get_main_queue(), ^{
[self emergencyRecreateGL];
});
}
}
else
#endif
{
[self.glView display];
}
}
if (self.experimental_enableFrameRateMeasurement)
@@ -1231,15 +1274,96 @@ public:
[self updateDisplayLinkPreferredFramesPerSecond];
}
- (void)setEnablePresentsWithTransaction:(BOOL)enablePresentsWithTransaction
{
if (_enablePresentsWithTransaction == enablePresentsWithTransaction)
{
return;
}
_enablePresentsWithTransaction = enablePresentsWithTransaction;
// If the map is visible, change the layer property too
if (self.window) {
CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
eaglLayer.presentsWithTransaction = enablePresentsWithTransaction;
}
}
#ifdef MGL_RECREATE_GL_IN_AN_EMERGENCY
// See https://github.com/mapbox/mapbox-gl-native/issues/14232
- (void)emergencyRecreateGL {
MGLLogError(@"Rendering took too long - creating GL views");
CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
eaglLayer.presentsWithTransaction = NO;
[self sleepGL:nil];
// Just performing a sleepGL/wakeGL pair isn't sufficient - in this case
// we can still get errors when calling bindDrawable. Here we completely
// recreate the GLKView
[self.userLocationAnnotationView removeFromSuperview];
[_glView removeFromSuperview];
_glView = [MGLMapView GLKViewWithFrame:self.bounds context:_context opaque:_opaque];
_glView.delegate = self;
[self insertSubview:_glView atIndex:0];
if (self.annotationContainerView)
{
[_glView insertSubview:self.annotationContainerView atIndex:0];
}
[self updateUserLocationAnnotationView];
// Do not bind...yet
if (self.window) {
[self wakeGL:nil];
CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
eaglLayer.presentsWithTransaction = self.enablePresentsWithTransaction;
}
else {
MGLLogDebug(@"No window - skipping wakeGL");
}
}
#endif
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
[self refreshSupportedInterfaceOrientationsWithWindow:newWindow];
if (!newWindow)
{
// See https://github.com/mapbox/mapbox-gl-native/issues/14232
// In iOS 12.2, CAEAGLLayer.presentsWithTransaction can cause dramatic
// slow down. The exact cause of this is unknown, but this work around
// appears to lessen the effects.
//
// Also, consider calling the new mbgl::Renderer::flush()
CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
eaglLayer.presentsWithTransaction = NO;
// Moved from didMoveToWindow
[self validateDisplayLink];
}
}
- (void)didMoveToWindow
{
[self validateDisplayLink];
[super didMoveToWindow];
if (self.window)
{
// See above comment
CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
eaglLayer.presentsWithTransaction = self.enablePresentsWithTransaction;
[self validateDisplayLink];
}
}
- (void)didMoveToSuperview
@@ -4151,6 +4275,8 @@ public:
[newAnnotationContainerView addSubviews:annotationViews];
[_glView insertSubview:newAnnotationContainerView atIndex:0];
self.annotationContainerView = newAnnotationContainerView;
self.enablePresentsWithTransaction = (self.annotationContainerView.annotationViews.count > MGLPresentsWithTransactionAnnotationCount);
}
/// Initialize and return a default annotation image that depicts a round pin
@@ -4324,6 +4450,8 @@ public:
annotationView.annotation = nil;
[annotationView removeFromSuperview];
[self.annotationContainerView.annotationViews removeObject:annotationView];
self.enablePresentsWithTransaction = (self.annotationContainerView.annotationViews.count > MGLPresentsWithTransactionAnnotationCount);
if (annotationTag == _selectedAnnotationTag)
{