diff options
author | Julian Rex <julian.rex@gmail.com> | 2019-04-17 14:13:11 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-17 14:13:11 -0400 |
commit | f456e054043da4af4793559733f1583df9b31c8d (patch) | |
tree | 663f547ca9da5364e3c43df841dbd7cf0fead632 | |
parent | 8ab6bed74add437abdbbd3111213bdeca58b4a3f (diff) | |
download | qtlocation-mapboxgl-f456e054043da4af4793559733f1583df9b31c8d.tar.gz |
[ios] CP #14439 - Ensure glFinish is called when going into the background, and block rendering in the background (#14451)
-rw-r--r-- | platform/ios/CHANGELOG.md | 1 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 83 |
2 files changed, 76 insertions, 8 deletions
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 04976cf1ce..81527a90de 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -14,6 +14,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Added `-[MGLMapViewDelegate mapView:didFailToLoadImage:]` to load missing symbol icons in the style if they are not found. ([#14302](https://github.com/mapbox/mapbox-gl-native/pull/14302)) * Fixed a possible crash with certain expressions containing arguments that evaluate to a dictionary containing `NSArray` or `NSNumber` values. ([#14352](https://github.com/mapbox/mapbox-gl-native/pull/14352)) * Fixed a bug where non-opaque `UIColor` values were ignored when assigned to a style layer color property. ([#14406](https://github.com/mapbox/mapbox-gl-native/pull/14406)) +* Speculatively fixed a bug where GL rendering could occur in the background. ([#14439](https://github.com/mapbox/mapbox-gl-native/pull/14439)) ### Packaging diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index ab9f178380..5326a1a8e0 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -257,6 +257,7 @@ public: @property (nonatomic) MGLUserLocation *userLocation; @property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier; @property (nonatomic) BOOL enablePresentsWithTransaction; +@property (nonatomic) UIImage *lastSnapshotImage; /// Experimental rendering performance measurement. @property (nonatomic) BOOL experimental_enableFrameRateMeasurement; @@ -634,9 +635,11 @@ public: // observe app activity // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTerminate) name:UIApplicationWillTerminateNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationWillEnterForegroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationDidBecomeActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; + // As of 3.7.5, we intentionally do not listen for `UIApplicationWillResignActiveNotification` or call `sleepGL:` in response to it, as doing // so causes a loop when asking for location permission. See: https://github.com/mapbox/mapbox-gl-native/issues/11225 @@ -830,7 +833,12 @@ public: { MGLAssertIsMainThread(); - _rendererFrontend->reduceMemoryUse(); + if ( ! self.dormant && _rendererFrontend) + { + _rendererFrontend->reduceMemoryUse(); + } + + self.lastSnapshotImage = nil; } #pragma mark - Layout - @@ -980,7 +988,7 @@ public: // This is the delegate of the GLKView object's display call. - (void)glkView:(__unused GLKView *)view drawInRect:(__unused CGRect)rect { - if ( ! self.dormant || ! _rendererFrontend) + if ( ! self.dormant && _rendererFrontend) { _rendererFrontend->render(); } @@ -1121,6 +1129,13 @@ public: if (displayLink && displayLink != _displayLink) { return; } + + // Check to ensure rendering doesn't occur in the background + if (([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) && + ![self supportsBackgroundRendering]) + { + return; + } if (_needsDisplayRefresh) { @@ -1461,6 +1476,55 @@ public: [self setNeedsLayout]; } +#pragma mark - Application lifecycle +- (void)willResignActive:(NSNotification *)notification +{ + if ([self supportsBackgroundRendering]) + { + return; + } + + self.lastSnapshotImage = self.glView.snapshot; + + // For OpenGL this calls glFinish as recommended in + // https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/ImplementingaMultitasking-awareOpenGLESApplication/ImplementingaMultitasking-awareOpenGLESApplication.html#//apple_ref/doc/uid/TP40008793-CH5-SW1 + // reduceMemoryUse(), calls performCleanup(), which calls glFinish + if (_rendererFrontend) + { + _rendererFrontend->reduceMemoryUse(); + } +} + +- (void)didEnterBackground:(NSNotification *)notification +{ + [self sleepGL:notification]; +} + +- (void)willEnterForeground:(NSNotification *)notification +{ + // Do nothing, currently if wakeGL is called here it's a no-op. +} + +- (void)didBecomeActive:(NSNotification *)notification +{ + [self wakeGL:notification]; + self.lastSnapshotImage = nil; +} + +#pragma mark - GL / display link wake/sleep + +- (BOOL)supportsBackgroundRendering +{ + // If this view targets an external display, such as AirPlay or CarPlay, we + // can safely continue to render OpenGL content without tripping + // gpus_ReturnNotPermittedKillClient in libGPUSupportMercury, because the + // external connection keeps the application from truly receding to the + // background. + return (self.window.screen != [UIScreen mainScreen]); +} + + + - (void)sleepGL:(__unused NSNotification *)notification { // If this view targets an external display, such as AirPlay or CarPlay, we @@ -1468,7 +1532,7 @@ public: // gpus_ReturnNotPermittedKillClient in libGPUSupportMercury, because the // external connection keeps the application from truly receding to the // background. - if (self.window.screen != [UIScreen mainScreen]) + if ([self supportsBackgroundRendering]) { return; } @@ -1481,7 +1545,10 @@ public: // Compromise position: release everything but currently rendering tiles // A possible improvement would be to store a copy of the GL buffers that we could use to rapidly // restart, but that we could also discard in response to a memory warning. - _rendererFrontend->reduceMemoryUse(); + if (_rendererFrontend) + { + _rendererFrontend->reduceMemoryUse(); + } if ( ! self.dormant) { @@ -1501,7 +1568,7 @@ public: [self insertSubview:self.glSnapshotView aboveSubview:self.glView]; } - self.glSnapshotView.image = self.glView.snapshot; + self.glSnapshotView.image = self.lastSnapshotImage; self.glSnapshotView.hidden = NO; if (self.debugMask && [self.glSnapshotView.subviews count] == 0) |