summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Rex <julian.rex@gmail.com>2019-04-17 14:13:11 -0400
committerGitHub <noreply@github.com>2019-04-17 14:13:11 -0400
commitf456e054043da4af4793559733f1583df9b31c8d (patch)
tree663f547ca9da5364e3c43df841dbd7cf0fead632
parent8ab6bed74add437abdbbd3111213bdeca58b4a3f (diff)
downloadqtlocation-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.md1
-rw-r--r--platform/ios/src/MGLMapView.mm83
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)