summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Rex <julian.rex@mapbox.com>2019-04-14 00:25:18 -0400
committerJulian Rex <julian.rex@mapbox.com>2019-04-16 11:38:41 -0400
commit4ad8de0be6ea5e0a0b1395c05e222b9540b7b3e0 (patch)
tree08e2ff3a885c05220cef874a24fae68f9925d651
parentafbd6e8e630c901c57e09197606cd07c1115547d (diff)
downloadqtlocation-mapboxgl-4ad8de0be6ea5e0a0b1395c05e222b9540b7b3e0.tar.gz
[ios] Replace flush/glFinish call with call to reduceMemoryUse()
-rw-r--r--platform/ios/Integration Tests/MGLBackgroundIntegrationTest.m92
-rw-r--r--platform/ios/src/MGLMapView.mm14
2 files changed, 97 insertions, 9 deletions
diff --git a/platform/ios/Integration Tests/MGLBackgroundIntegrationTest.m b/platform/ios/Integration Tests/MGLBackgroundIntegrationTest.m
index b4d3eed4e8..a6932dd60c 100644
--- a/platform/ios/Integration Tests/MGLBackgroundIntegrationTest.m
+++ b/platform/ios/Integration Tests/MGLBackgroundIntegrationTest.m
@@ -266,4 +266,96 @@ typedef void (^MGLNotificationBlock)(NSNotification*);
XCTAssert(self.mapView.application.applicationState == UIApplicationStateActive);
}
+- (void)testRendererDelayingAdjustingViewsWhenInBackground {
+
+ XCTAssertFalse(self.mapView.isDormant);
+ XCTAssertFalse(self.mapView.displayLink.isPaused);
+ XCTAssert(self.mapView.application.applicationState == UIApplicationStateActive);
+
+ __weak typeof(self) weakSelf = self;
+
+ //
+ // Enter background
+ //
+
+ XCTestExpectation *didEnterBackgroundExpectation = [self expectationWithDescription:@"didEnterBackground"];
+ didEnterBackgroundExpectation.expectedFulfillmentCount = 1;
+ didEnterBackgroundExpectation.assertForOverFulfill = YES;
+
+ XCTestExpectation *adjustedViewsExpectation = [self expectationWithDescription:@"adjustedViewsExpectation"];
+ adjustedViewsExpectation.expectedFulfillmentCount = 1;
+ adjustedViewsExpectation.assertForOverFulfill = YES;
+
+ __block NSInteger displayLinkCount = 0;
+
+ self.displayLinkDidUpdate = ^{
+ displayLinkCount++;
+ };
+
+ NSTimeInterval delay = 5.0;
+
+ self.didEnterBackground = ^(__unused NSNotification *notification){
+ typeof(self) strongSelf = weakSelf;
+ MGLMapView *mapView = strongSelf.mapView;
+
+ // In general, because order of notifications is not guaranteed
+ // the following asserts are somewhat meaningless (don't do this in
+ // production) - however, because we're mocking their delivery (and
+ // we're tracking a bug)...
+
+ // MGLMapView responds to UIApplicationDidEnterBackgroundNotification and
+ // marks the map view as dormant. However, depending on the order of
+ // creation it's totally possible for client code also responding to
+ // this notification to be called first - and then trigger a scenario where
+ // GL can be rendering in the background - which can cause crashes.
+
+ MGLTestAssert(strongSelf, !mapView.isDormant);
+
+ // However, the display should be paused (because this has now moved
+ // to ...WillResignActive...
+ MGLTestAssert(strongSelf, mapView.displayLink.isPaused);
+
+ // Remove the map view, and re-add to try and force a bad situation
+ // This will delete/re-create the display link
+ UIView *parentView = mapView.superview;
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+
+ displayLinkCount = 0;
+
+ NSLog(@"Removing MGLMapView from super view");
+ [mapView removeFromSuperview];
+
+ // Re-add
+ NSLog(@"Re-adding MGLMapView as child");
+ [parentView addSubview:mapView];
+
+ MGLTestAssert(strongSelf, displayLinkCount == 0, @"updateDisplayLink was called %ld times", displayLinkCount);
+
+ [mapView.topAnchor constraintEqualToAnchor:parentView.topAnchor].active = YES;
+ [mapView.leftAnchor constraintEqualToAnchor:parentView.leftAnchor].active = YES;
+ [mapView.rightAnchor constraintEqualToAnchor:parentView.rightAnchor].active = YES;
+ [mapView.bottomAnchor constraintEqualToAnchor:parentView.bottomAnchor].active = YES;
+
+ [adjustedViewsExpectation fulfill];
+ });
+
+ [didEnterBackgroundExpectation fulfill];
+ };
+
+ [self.mockApplication enterBackground];
+ [self waitForExpectations:@[didEnterBackgroundExpectation] timeout:1.0];
+
+ XCTAssert(self.mapView.isDormant);
+
+ // TODO: What do we want here?
+ XCTAssert(!self.mapView.displayLink || self.mapView.displayLink.isPaused);
+ XCTAssert(self.mapView.application.applicationState == UIApplicationStateBackground);
+
+
+ [self waitForExpectations:@[adjustedViewsExpectation] timeout:delay];
+ XCTAssert(self.mapView.isDormant);
+ XCTAssert(!self.mapView.displayLink || self.mapView.displayLink.isPaused);
+}
+
@end
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 86b4c51c49..6f053f0ac2 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -1524,7 +1524,7 @@ public:
[self resumeGL];
}
-- (BOOL)supportBackgroundRendering
+- (BOOL)supportsBackgroundRendering
{
// If this view targets an external display, such as AirPlay or CarPlay, we
// can safely continue to render OpenGL content without tripping
@@ -1536,7 +1536,7 @@ public:
- (void)resignGL
{
- if ([self supportBackgroundRendering])
+ if ([self supportsBackgroundRendering])
{
return;
}
@@ -1550,15 +1550,16 @@ public:
// 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->flush();
+ _rendererFrontend->reduceMemoryUse();
}
}
- (void)sleepGL:(__unused NSNotification *)notification
{
- if ([self supportBackgroundRendering])
+ if ([self supportsBackgroundRendering])
{
return;
}
@@ -1605,11 +1606,6 @@ public:
[self.glView deleteDrawable];
}
-
- if (_rendererFrontend)
- {
- _rendererFrontend->flush();
- }
}
- (void)wakeGL:(__unused NSNotification *)notification