Ignore deactivate when no valid EGL display. Fixes #1435

Initialise NativeMapView's EGL variables before Map

Fix hang

Add check for double pause

Add test for double pause
This commit is contained in:
Leith Bade
2015-05-06 12:47:15 +10:00
parent fd099593dc
commit 703e0bc2ee
11 changed files with 161 additions and 96 deletions

View File

@@ -61,9 +61,11 @@ NativeMapView::NativeMapView(JNIEnv *env, jobject obj_)
: mbgl::View(*this),
fileCache(mbgl::android::cachePath + "/mbgl-cache.db"),
fileSource(&fileCache),
map(*this, fileSource, MapMode::Continuous, true) {
map(*this, fileSource, MapMode::Continuous) {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::NativeMapView");
map.pause();
assert(env != nullptr);
assert(obj_ != nullptr);
@@ -116,10 +118,14 @@ void NativeMapView::activate() {
void NativeMapView::deactivate() {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::deactivate");
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d",
eglGetError());
throw new std::runtime_error("eglMakeCurrent() failed");
if (display != EGL_NO_DISPLAY) {
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d",
eglGetError());
throw new std::runtime_error("eglMakeCurrent() failed");
}
} else {
mbgl::Log::Info(mbgl::Event::Android, "Not deactivating as we are not ready");
}
}

View File

@@ -55,11 +55,6 @@ private:
jobject obj = nullptr;
ANativeWindow *window = nullptr;
mbgl::SQLiteCache fileCache;
mbgl::DefaultFileSource fileSource;
mbgl::Map map;
EGLDisplay display = EGL_NO_DISPLAY;
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
@@ -74,6 +69,12 @@ private:
bool fpsEnabled = false;
double fps = 0.0;
// Ensure these are initialised last
mbgl::SQLiteCache fileCache;
mbgl::DefaultFileSource fileSource;
mbgl::Map map;
};
}
}

View File

@@ -31,8 +31,7 @@ class Map : private util::noncopyable {
public:
explicit Map(View&, FileSource&,
MapMode mode = MapMode::Continuous,
bool startPaused = false);
MapMode mode = MapMode::Continuous);
~Map();
// Pauses the render thread. The render thread will stop running but will not be terminated and will not lose state until resumed.
@@ -137,6 +136,7 @@ public:
private:
const std::unique_ptr<MapData> data;
const std::unique_ptr<util::Thread<MapContext>> context;
bool paused = false;
};
}

View File

@@ -9,7 +9,6 @@ using UpdateType = uint32_t;
enum class Update : UpdateType {
Nothing = 0,
Debug = 1 << 1,
DefaultTransitionDuration = 1 << 2,
Classes = 1 << 3,
Zoom = 1 << 4,

View File

@@ -173,27 +173,27 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
- (void)setStyleURL:(NSURL *)styleURL
{
if (_isTargetingInterfaceBuilder) return;
if ( ! styleURL)
{
styleURL = MGLURLForBundledStyleNamed([NSString stringWithFormat:@"%@-v%@",
MGLDefaultStyleName.lowercaseString,
MGLStyleVersion]);
}
if ( ! [styleURL scheme])
{
// Assume a relative path into the developer’s bundle.
styleURL = [[NSBundle mainBundle] URLForResource:styleURL.path withExtension:nil];
}
_mbglMap->setStyleURL([[styleURL absoluteString] UTF8String]);
}
- (BOOL)commonInit
{
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
// create context
//
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
@@ -208,7 +208,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
// setup accessibility
//
self.accessibilityLabel = @"Map";
// metrics: initial setup
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
@@ -232,7 +232,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
[self insertSubview:_glView atIndex:0];
_glView.contentMode = UIViewContentModeCenter;
self.backgroundColor = [UIColor clearColor];
self.clipsToBounds = YES;
@@ -272,7 +272,10 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
_mbglFileSource = new mbgl::DefaultFileSource([MGLFileCache obtainSharedCacheWithObject:self]);
// Start paused on the IB canvas
_mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous, _isTargetingInterfaceBuilder);
_mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous);
if (_isTargetingInterfaceBuilder) {
_mbglMap->pause();
}
_mbglMap->resize(self.bounds.size.width, self.bounds.size.height, _glView.contentScaleFactor);
// Notify map object when network reachability status changes.
@@ -433,7 +436,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
- (void)setDelegate:(id<MGLMapViewDelegate>)delegate
{
if (_delegate == delegate) return;
_delegate = delegate;
}
@@ -639,7 +642,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
- (void)layoutSubviews
{
[super layoutSubviews];
if ( ! _isTargetingInterfaceBuilder)
{
_mbglMap->update();
@@ -735,7 +738,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
_mbglMap->moveBy(delta.x, delta.y);
self.centerPoint = CGPointMake(self.centerPoint.x + delta.x, self.centerPoint.y + delta.y);
[self notifyMapChange:@(mbgl::MapChangeRegionDidChangeAnimated)];
}
else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled)
@@ -746,7 +749,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
// Not enough velocity to overcome friction
velocity = CGPointZero;
}
CGFloat duration = UIScrollViewDecelerationRateNormal;
if ( ! CGPointEqualToPoint(velocity, CGPointZero))
{
@@ -821,7 +824,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
velocity = 0;
}
CGFloat duration = velocity > 0 ? 1 : 0.25;
CGFloat scale = self.scale * pinch.scale;
CGFloat newScale = scale;
if (velocity >= 0)
@@ -832,22 +835,22 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
{
newScale += scale / (velocity * duration) * 0.1;
}
if (newScale <= 0 || log2(newScale) < _mbglMap->getMinZoom())
{
velocity = 0;
}
if (velocity)
{
CGPoint pinchCenter = [pinch locationInView:pinch.view];
_mbglMap->setScale(newScale, pinchCenter.x, pinchCenter.y, secondsAsDuration(duration));
}
_mbglMap->setGestureInProgress(false);
[self unrotateIfNeededAnimated:YES];
if (velocity)
{
self.animatingGesture = YES;
@@ -903,37 +906,37 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
{
CGFloat velocity = rotate.velocity;
if (fabs(velocity) > 3)
{
CGFloat radians = self.angle + rotate.rotation;
CGFloat duration = UIScrollViewDecelerationRateNormal;
CGFloat newRadians = radians + velocity * duration * 0.1;
CGFloat newDegrees = [MGLMapView radiansToDegrees:newRadians] * -1;
_mbglMap->setBearing(newDegrees, secondsAsDuration(duration));
_mbglMap->setGestureInProgress(false);
self.animatingGesture = YES;
__weak MGLMapView *weakSelf = self;
[self animateWithDelay:duration animations:^
{
weakSelf.animatingGesture = NO;
[weakSelf unrotateIfNeededAnimated:YES];
[weakSelf notifyMapChange:@(mbgl::MapChangeRegionDidChangeAnimated)];
}];
}
else
{
_mbglMap->setGestureInProgress(false);
[self unrotateIfNeededAnimated:YES];
[self notifyMapChange:@(mbgl::MapChangeRegionDidChange)];
}
}
@@ -1381,14 +1384,14 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
// NOTE: does not disrupt tracking mode
CLLocationCoordinate2D center = CLLocationCoordinate2DMake((northEastCoordinate.latitude + southWestCoordinate.latitude) / 2, (northEastCoordinate.longitude + southWestCoordinate.longitude) / 2);
CGFloat scale = _mbglMap->getScale();
CGFloat scaleX = _mbglMap->getWidth() / (northEastCoordinate.longitude - southWestCoordinate.longitude);
CGFloat scaleY = _mbglMap->getHeight() / (northEastCoordinate.latitude - southWestCoordinate.latitude);
CGFloat minZoom = _mbglMap->getMinZoom();
CGFloat maxZoom = _mbglMap->getMaxZoom();
CGFloat zoomLevel = MAX(MIN(log(scale * MIN(scaleX, scaleY)) / log(2), maxZoom), minZoom);
[self setCenterCoordinate:center zoomLevel:zoomLevel animated:animated];
}
@@ -1660,7 +1663,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
{
assert([annotation conformsToProtocol:@protocol(MGLAnnotation)]);
annotationIDsToRemove.push_back([[[self.annotationIDsByAnnotation objectForKey:annotation]
annotationIDsToRemove.push_back([[[self.annotationIDsByAnnotation objectForKey:annotation]
objectForKey:MGLAnnotationIDKey] unsignedIntValue]);
[self.annotationIDsByAnnotation removeObjectForKey:annotation];
@@ -1696,7 +1699,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
if ( ! annotation) return;
if ( ! [self viewportBounds].contains(coordinateToLatLng(annotation.coordinate))) return;
if (annotation == self.selectedAnnotation) return;
self.userTrackingMode = MGLUserTrackingModeNone;
@@ -1815,22 +1818,22 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
- (void)setShowsUserLocation:(BOOL)showsUserLocation
{
if (showsUserLocation == _showsUserLocation) return;
_showsUserLocation = showsUserLocation;
if (showsUserLocation)
{
if ([self.delegate respondsToSelector:@selector(mapViewWillStartLocatingUser:)])
{
[self.delegate mapViewWillStartLocatingUser:self];
}
self.userLocationAnnotationView = [[MGLUserLocationAnnotationView alloc] initInMapView:self];
self.userLocationAnnotationView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
self.locationManager = [CLLocationManager new];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
// enable iOS 8+ location authorization API
//
@@ -1843,7 +1846,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
[self.locationManager requestWhenInUseAuthorization];
}
#endif
self.locationManager.headingFilter = 5.0;
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
@@ -1861,7 +1864,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
}
[self setUserTrackingMode:MGLUserTrackingModeNone animated:YES];
[self.userLocationAnnotationView removeFromSuperview];
self.userLocationAnnotationView = nil;
}
@@ -2026,7 +2029,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
CLLocationCoordinate2D actualNorthEast = [self convertPoint:CGPointMake(userLocationPoint.x + pixelRadius,
userLocationPoint.y + pixelRadius)
toCoordinateFromView:self];
if (desiredNorthEast.latitude != actualNorthEast.latitude ||
desiredNorthEast.longitude != actualNorthEast.longitude ||
desiredSouthWest.latitude != actualSouthWest.latitude ||
@@ -2429,17 +2432,17 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
- (void)prepareForInterfaceBuilder
{
[super prepareForInterfaceBuilder];
self.layer.borderColor = [UIColor colorWithWhite:184/255. alpha:1].CGColor;
self.layer.borderWidth = 1;
if (self.accessToken)
{
self.layer.backgroundColor = [UIColor colorWithRed:59/255.
green:178/255.
blue:208/255.
alpha:0.8].CGColor;
UIImage *image = [[self class] resourceImageNamed:@"mapbox.png"];
UIImageView *previewView = [[UIImageView alloc] initWithImage:image];
previewView.translatesAutoresizingMaskIntoConstraints = NO;
@@ -2466,7 +2469,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
UIView *diagnosticView = [[UIView alloc] init];
diagnosticView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:diagnosticView];
// Headline
UILabel *headlineLabel = [[UILabel alloc] init];
headlineLabel.text = @"No Access Token";
@@ -2477,7 +2480,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
[headlineLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[diagnosticView addSubview:headlineLabel];
// Explanation
UILabel *explanationLabel = [[UILabel alloc] init];
explanationLabel.text = @"To display a map here, you must provide a Mapbox access token. Get an access token from:";
@@ -2487,7 +2490,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
[explanationLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[diagnosticView addSubview:explanationLabel];
// Link
UIButton *linkButton = [UIButton buttonWithType:UIButtonTypeSystem];
[linkButton setTitle:MGLMapboxAccessTokenManagerURLDisplayString forState:UIControlStateNormal];
@@ -2495,7 +2498,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
[linkButton setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[diagnosticView addSubview:linkButton];
// More explanation
UILabel *explanationLabel2 = [[UILabel alloc] init];
explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector.";
@@ -2505,7 +2508,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
[explanationLabel2 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[diagnosticView addSubview:explanationLabel2];
// Constraints
NSDictionary *views = @{
@"container": diagnosticView,

View File

@@ -9,9 +9,9 @@
namespace mbgl {
Map::Map(View& view, FileSource& fileSource, MapMode mode, bool startPaused)
Map::Map(View& view, FileSource& fileSource, MapMode mode)
: data(util::make_unique<MapData>(view, mode)),
context(util::make_unique<util::Thread<MapContext>>("Map", util::ThreadPriority::Regular, view, fileSource, *data, startPaused))
context(util::make_unique<util::Thread<MapContext>>("Map", util::ThreadPriority::Regular, view, fileSource, *data))
{
view.initialize(this);
}
@@ -23,13 +23,17 @@ Map::~Map() {
void Map::pause() {
assert(data->mode == MapMode::Continuous);
std::unique_lock<std::mutex> lockPause(data->mutexPause);
context->invoke(&MapContext::pause);
data->condPaused.wait(lockPause);
if (!paused) {
std::unique_lock<std::mutex> lockPause(data->mutexPause);
context->invoke(&MapContext::pause);
data->condPaused.wait(lockPause);
paused = true;
}
}
void Map::resume() {
data->condResume.notify_all();
paused = false;
}
void Map::renderStill(StillImageCallback callback) {
@@ -274,12 +278,12 @@ LatLngBounds Map::getBoundsForAnnotations(const std::vector<uint32_t>& annotatio
void Map::setDebug(bool value) {
data->setDebug(value);
update(Update::Debug);
update();
}
void Map::toggleDebug() {
data->toggleDebug();
update(Update::Debug);
update();
}
bool Map::getDebug() const {

View File

@@ -29,7 +29,7 @@
namespace mbgl {
MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, MapData& data_, bool startPaused)
MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, MapData& data_)
: view(view_),
data(data_),
env(fileSource),
@@ -40,20 +40,12 @@ MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, Map
glyphAtlas(util::make_unique<GlyphAtlas>(1024, 1024)),
spriteAtlas(util::make_unique<SpriteAtlas>(512, 512)),
lineAtlas(util::make_unique<LineAtlas>(512, 512)),
texturePool(util::make_unique<TexturePool>()),
painter(util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas))
{
texturePool(util::make_unique<TexturePool>()) {
assert(Environment::currentlyOn(ThreadType::Map));
asyncUpdate->unref();
view.activate();
if (startPaused) {
pause();
}
painter->setup();
}
MapContext::~MapContext() {
@@ -173,11 +165,6 @@ void MapContext::update() {
updated |= data.transform.updateTransitions(now);
transformState = data.transform.currentState();
if (updated & static_cast<UpdateType>(Update::Debug)) {
assert(painter);
painter->setDebug(data.getDebug());
}
if (style) {
if (updated & static_cast<UpdateType>(Update::DefaultTransitionDuration)) {
style->setDefaultTransitionDuration(data.getDefaultTransitionDuration());
@@ -230,8 +217,13 @@ void MapContext::render() {
env.performCleanup();
assert(style);
assert(painter);
if (!painter) {
painter = util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas);
painter->setup();
}
painter->setDebug(data.getDebug());
painter->render(*style, transformState, data.getAnimationTime());
if (data.mode == MapMode::Still && callback && style->isLoaded() && resourceLoader->getSprite()->isLoaded()) {

View File

@@ -35,7 +35,7 @@ struct LatLngBounds;
class MapContext : public ResourceLoader::Observer {
public:
MapContext(uv_loop_t*, View&, FileSource&, MapData&, bool startPaused);
MapContext(uv_loop_t*, View&, FileSource&, MapData&);
~MapContext();
void pause();

View File

@@ -1,22 +1,59 @@
#include "../fixtures/util.hpp"
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/map_data.hpp>
#include <mbgl/map/map_context.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/platform/default/headless_view.hpp>
#include <mbgl/platform/default/headless_display.hpp>
#include <mbgl/storage/default_file_source.hpp>
using namespace mbgl;
TEST(MapContext, DoubleStyleLoad) {
util::RunLoop runLoop(uv_default_loop());
std::shared_ptr<HeadlessDisplay> display = std::make_shared<HeadlessDisplay>();
HeadlessView view(display, 512, 512, 1);
DefaultFileSource fileSource(nullptr);
MapData data(view, MapMode::Continuous);
MapContext context(uv_default_loop(), view, fileSource, data, false);
TEST(Map, PauseResume) {
using namespace mbgl;
context.setStyleJSON("", "");
context.setStyleJSON("", "");
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display);
DefaultFileSource fileSource(nullptr);
Map map(view, fileSource, MapMode::Continuous);
map.pause();
map.resume();
}
TEST(Map, DoublePause) {
using namespace mbgl;
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display);
DefaultFileSource fileSource(nullptr);
Map map(view, fileSource, MapMode::Continuous);
map.pause();
map.pause();
map.resume();
}
TEST(Map, ResumeWithoutPause) {
using namespace mbgl;
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display);
DefaultFileSource fileSource(nullptr);
Map map(view, fileSource, MapMode::Continuous);
map.resume();
}
TEST(Map, DestroyPaused) {
using namespace mbgl;
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display);
DefaultFileSource fileSource(nullptr);
Map map(view, fileSource, MapMode::Continuous);
map.pause();
}

View File

@@ -0,0 +1,22 @@
#include "../fixtures/util.hpp"
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/map_data.hpp>
#include <mbgl/map/map_context.hpp>
#include <mbgl/platform/default/headless_view.hpp>
#include <mbgl/platform/default/headless_display.hpp>
#include <mbgl/storage/default_file_source.hpp>
using namespace mbgl;
TEST(MapContext, DoubleStyleLoad) {
util::RunLoop runLoop(uv_default_loop());
std::shared_ptr<HeadlessDisplay> display = std::make_shared<HeadlessDisplay>();
HeadlessView view(display, 512, 512, 1);
DefaultFileSource fileSource(nullptr);
MapData data(view, MapMode::Continuous);
MapContext context(uv_default_loop(), view, fileSource, data);
context.setStyleJSON("", "");
context.setStyleJSON("", "");
}

View File

@@ -44,6 +44,7 @@
'miscellaneous/enums.cpp',
'miscellaneous/functions.cpp',
'miscellaneous/map.cpp',
'miscellaneous/map_context.cpp',
'miscellaneous/mapbox.cpp',
'miscellaneous/merge_lines.cpp',
'miscellaneous/rotation_range.cpp',