From 204c7fee032bf8509747046b43a788366a189ae7 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 1 Sep 2015 15:07:17 +0300 Subject: [core] Render from the main thread Do not create a thread for the MapContext anymore. --- include/mbgl/map/map.hpp | 19 +--- include/mbgl/map/view.hpp | 52 +++++------ include/mbgl/platform/default/glfw_view.hpp | 5 +- include/mbgl/platform/default/headless_view.hpp | 19 ++-- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 10 +- .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 24 +---- platform/android/src/jni.cpp | 32 +------ platform/android/src/native_map_view.cpp | 43 +-------- platform/android/src/native_map_view.hpp | 6 +- platform/darwin/src/headless_view_cgl.cpp | 2 +- platform/darwin/src/headless_view_eagl.mm | 2 +- platform/default/glfw_view.cpp | 33 +++---- platform/default/headless_view.cpp | 52 +++-------- platform/default/headless_view_glx.cpp | 2 +- platform/ios/src/MGLMapView.mm | 53 +++-------- platform/node/src/node_map.cpp | 20 ++-- platform/node/src/node_mapbox_gl_native.cpp | 15 +-- platform/node/src/node_mapbox_gl_native.hpp | 9 -- platform/node/test/js/map.test.js | 4 +- platform/osx/src/MGLMapView.mm | 103 ++++++++------------- src/mbgl/map/map.cpp | 82 +++++++--------- src/mbgl/map/map_context.cpp | 33 ++----- src/mbgl/map/map_context.hpp | 3 - src/mbgl/map/map_data.hpp | 17 +--- src/mbgl/util/thread_context.hpp | 2 +- test/api/annotations.cpp | 25 +++++ test/api/api_misuse.cpp | 16 +++- test/api/custom_layer.cpp | 3 + test/api/render_missing.cpp | 11 ++- test/api/repeated_render.cpp | 27 ++++-- test/api/set_style.cpp | 3 + test/map/map.cpp | 48 +--------- test/src/mbgl/test/mock_view.hpp | 3 - test/src/mbgl/test/util.cpp | 14 ++- test/test.gypi | 1 - 35 files changed, 268 insertions(+), 525 deletions(-) delete mode 100644 platform/node/src/node_mapbox_gl_native.hpp diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 9d586d8b8a..b70c388183 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -32,10 +32,6 @@ class ShapeAnnotation; struct CameraOptions; struct AnimationOptions; -namespace util { -template class Thread; -} // namespace util - class Map : private util::noncopyable { friend class View; @@ -46,22 +42,15 @@ public: ConstrainMode constrainMode = ConstrainMode::HeightOnly); ~Map(); - // Pauses the render thread. The render thread will stop running but will not be terminated and will not lose state until resumed. - void pause(); - bool isPaused(); - - // Resumes a paused render thread - void resume(); - // Register a callback that will get called (on the render thread) when all resources have // been loaded and a complete render occurs. using StillImageCallback = std::function; void renderStill(StillImageCallback callback); - // Triggers a synchronous render. - void renderSync(); + // Main render function. + void render(); - // Notifies the Map thread that the state has changed and an update might be necessary. + // Notifies the Map that the state has changed and an update might be necessary. void update(Update update); // Styling @@ -189,7 +178,7 @@ public: private: View& view; const std::unique_ptr transform; - const std::unique_ptr> context; + const std::unique_ptr context; MapData* data; enum class RenderState { diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp index 6f481c4458..fd11080064 100644 --- a/include/mbgl/map/view.hpp +++ b/include/mbgl/map/view.hpp @@ -30,44 +30,42 @@ enum MapChange : uint8_t { class View { public: - // Called from the main thread directly after initialization. Must always return the same value, - // i.e. it may not change over time. + virtual ~View() = default; + + // Called directly after initialization. Must always return the same value, i.e. it may + // not change over time. virtual float getPixelRatio() const = 0; - // Called from the main thread when the View signaled a dimension change. Must return the - // logical dimension of this map in pixels. + // Called when the View signaled a dimension change. Must return the logical dimension + // of this map in pixels. virtual std::array getSize() const = 0; - // Called from the main thread for every frame that is being rendered. Must return the absolute - // dimensions of the current framebuffer. Typically, this is the logical width scaled by the - // pixel ratio, but in case the view was moved to display with a different pixel ratio, it can - // also be different from that rule. + // Called for every frame that is being rendered. Must return the absolute dimensions of + // the current framebuffer. Typically, this is the logical width scaled by the pixel ratio, + // but in case the view was moved to display with a different pixel ratio, it can also be + // different from that rule. virtual std::array getFramebufferSize() const = 0; - // Called from the main thread when this View is associated with a Map object. - virtual void initialize(Map *map_); - - // Called from the render thread. Makes the GL context active in the current - // thread. This is typically just called once at the beginning of the - // renderer setup since the render thread doesn't switch the contexts. + // Called when this View is associated with a Map object. + virtual void initialize(Map*); + + // Called when the view's GL context needs to be made active or inactive. These are called, + // as a matched pair, in four situations: + // + // 1. When releasing GL resources during Map destruction + // 2. When calling a CustomLayerInitializeFunction, during Map::addCustomLayer + // 3. When calling a CustomLayerDeinitializeFunction, during Map::removeCustomLayer + // 4. When rendering for Map::renderStill + // + // They are *not* called for Map::render; it is assumed that the correct context is already + // activated prior to calling Map::render. virtual void activate() = 0; - - // Called from the render thread. Makes the GL context inactive in the current - // thread. This is called once just before the rendering thread terminates. virtual void deactivate() = 0; - virtual void notify() = 0; - - // Called from the render thread. The implementation must trigger a rerender. - // (map->renderSync() from the main thread must be called as a result of this) + // Called when the map needs to be rendered; the view should call Map::render() at some point + // in the near future. (Not called for Map::renderStill() mode.) virtual void invalidate() = 0; - // Called from the render thread before the render begins. - virtual void beforeRender() = 0; - - // Called from the render thread after the render is complete. - virtual void afterRender() = 0; - // Reads the pixel data from the current framebuffer. If your View implementation // doesn't support reading from the framebuffer, return a null pointer. virtual PremultipliedImage readStillImage(); diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp index 802f61b0c0..74a545d31b 100644 --- a/include/mbgl/platform/default/glfw_view.hpp +++ b/include/mbgl/platform/default/glfw_view.hpp @@ -22,13 +22,10 @@ public: std::array getSize() const override; std::array getFramebufferSize() const override; - void initialize(mbgl::Map *map) override; + void initialize(mbgl::Map*) override; void activate() override; void deactivate() override; - void notify() override; void invalidate() override; - void beforeRender() override; - void afterRender() override; static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods); static void onScroll(GLFWwindow *window, double xoffset, double yoffset); diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp index edaa08d01d..9fbbdfd206 100644 --- a/include/mbgl/platform/default/headless_view.hpp +++ b/include/mbgl/platform/default/headless_view.hpp @@ -38,34 +38,31 @@ public: std::array getSize() const override; std::array getFramebufferSize() const override; + void invalidate() override; void activate() override; void deactivate() override; - void notify() override; - void invalidate() override; - void beforeRender() override; - void afterRender() override; + PremultipliedImage readStillImage() override; - void resizeFramebuffer(); void resize(uint16_t width, uint16_t height); private: - void loadExtensions(); - bool isActive() const; - // Implementation specific functions static gl::glProc initializeExtension(const char*); void createContext(); void destroyContext(); void clearBuffers(); + void resizeFramebuffer(); void activateContext(); void deactivateContext(); -private: std::shared_ptr display; const float pixelRatio; std::array dimensions; + bool needsResize = false; + bool extensionsLoaded = false; + bool active = false; #if MBGL_USE_CGL CGLContextObj glContext = nullptr; @@ -82,13 +79,9 @@ private: GLXPbuffer glxPbuffer = 0; #endif - bool extensionsLoaded = false; - GLuint fbo = 0; GLuint fboDepthStencil = 0; GLuint fboColor = 0; - - std::thread::id thread; }; } // namespace mbgl diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index abe0bdc317..963ae8d750 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -521,7 +521,6 @@ public class MapView extends FrameLayout { mConnectivityReceiver = null; mUserLocationView.onPause(); - mNativeMapView.pause(); } /** @@ -533,7 +532,6 @@ public class MapView extends FrameLayout { mConnectivityReceiver = new ConnectivityReceiver(); getContext().registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - mNativeMapView.resume(); mNativeMapView.update(); mUserLocationView.onResume(); @@ -1094,9 +1092,7 @@ public class MapView extends FrameLayout { } int getTopOffsetPixelsForIcon(Icon icon) { - // This method will dead lock if map paused. Causes a freeze if you add a marker in an - // activity's onCreate() - if (mDestroyed || mNativeMapView.isPaused()) { + if (mDestroyed) { return 0; } @@ -1243,11 +1239,11 @@ public class MapView extends FrameLayout { return; } - if (mDestroyed || mNativeMapView.isPaused()) { + if (mDestroyed) { return; } - mNativeMapView.renderSync(); + mNativeMapView.render(); } @Override diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 6b5a02cf06..bf342bdb40 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -119,24 +119,12 @@ final class NativeMapView { nativeDestroySurface(mNativeMapViewPtr); } - public void pause() { - nativePause(mNativeMapViewPtr); - } - - public boolean isPaused() { - return nativeIsPaused(mNativeMapViewPtr); - } - - public void resume() { - nativeResume(mNativeMapViewPtr); - } - public void update() { nativeUpdate(mNativeMapViewPtr); } - public void renderSync() { - nativeRenderSync(mNativeMapViewPtr); + public void render() { + nativeRender(mNativeMapViewPtr); } public void resizeView(int width, int height) { @@ -515,15 +503,9 @@ final class NativeMapView { private native void nativeDestroySurface(long nativeMapViewPtr); - private native void nativePause(long nativeMapViewPtr); - - private native boolean nativeIsPaused(long nativeMapViewPtr); - - private native void nativeResume(long nativeMapViewPtr); - private native void nativeUpdate(long nativeMapViewPtr); - private native void nativeRenderSync(long nativeMapViewPtr); + private native void nativeRender(long nativeMapViewPtr); private native void nativeViewResize(long nativeMapViewPtr, int width, int height); diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 08e5e697ae..e0d5bb65df 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -404,27 +404,6 @@ void nativeDestroySurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr nativeMapView->destroySurface(); } -void nativePause(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativePause"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->pause(); -} - -jboolean nativeIsPaused(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeIsPaused"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().isPaused(); -} - -void nativeResume(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeResume"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->resume(); -} - void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate"); assert(nativeMapViewPtr != 0); @@ -432,11 +411,11 @@ void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { nativeMapView->getMap().update(mbgl::Update::Repaint); } -void nativeRenderSync(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeRenderSync"); +void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeRender"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().renderSync(); + nativeMapView->render(); } void nativeViewResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) { @@ -1815,11 +1794,8 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { MAKE_NATIVE_METHOD(nativeTerminateContext, "(J)V"), MAKE_NATIVE_METHOD(nativeCreateSurface, "(JLandroid/view/Surface;)V"), MAKE_NATIVE_METHOD(nativeDestroySurface, "(J)V"), - MAKE_NATIVE_METHOD(nativePause, "(J)V"), - MAKE_NATIVE_METHOD(nativeIsPaused, "(J)Z"), - MAKE_NATIVE_METHOD(nativeResume, "(J)V"), MAKE_NATIVE_METHOD(nativeUpdate, "(J)V"), - MAKE_NATIVE_METHOD(nativeRenderSync, "(J)V"), + MAKE_NATIVE_METHOD(nativeRender, "(J)V"), MAKE_NATIVE_METHOD(nativeViewResize, "(JII)V"), MAKE_NATIVE_METHOD(nativeFramebufferResize, "(JII)V"), MAKE_NATIVE_METHOD(nativeAddClass, "(JLjava/lang/String;)V"), diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index a645d86d4b..6b1d4ff327 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -90,8 +90,6 @@ NativeMapView::NativeMapView(JNIEnv *env, jobject obj_, float pixelRatio_, int a size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f; map->setSourceTileCacheSize(cacheSize); - - map->pause(); } NativeMapView::~NativeMapView() { @@ -189,20 +187,15 @@ void NativeMapView::invalidate() { detach_jni_thread(vm, &env, detach); } -void NativeMapView::beforeRender() { - mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::beforeRender()"); +void NativeMapView::render() { + activate(); if(sizeChanged){ sizeChanged = false; glViewport(0, 0, fbWidth, fbHeight); } -} - -void NativeMapView::afterRender() { - mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::afterRender()"); - assert(vm != nullptr); - assert(obj != nullptr); + map->render(); if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) { if (!eglSwapBuffers(display, surface)) { @@ -215,11 +208,8 @@ void NativeMapView::afterRender() { } else { mbgl::Log::Info(mbgl::Event::Android, "Not swapping as we are not ready"); } -} -void NativeMapView::notify() { - mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notify()"); - // noop + deactivate(); } mbgl::Map &NativeMapView::getMap() { return *map; } @@ -444,15 +434,11 @@ void NativeMapView::createSurface(ANativeWindow *window_) { throw std::runtime_error("eglMakeCurrent() failed"); } } - - resume(); } void NativeMapView::destroySurface() { mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::destroySurface"); - pause(); - if (surface != EGL_NO_SURFACE) { if (!eglDestroySurface(display, surface)) { mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d", @@ -669,27 +655,6 @@ EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfi return configId; } -void NativeMapView::pause() { - mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::pause"); - - if ((display != EGL_NO_DISPLAY) && (context != EGL_NO_CONTEXT)) { - map->pause(); - } -} - -void NativeMapView::resume() { - mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::resume"); - - assert(display != EGL_NO_DISPLAY); - assert(context != EGL_NO_CONTEXT); - - if (surface != EGL_NO_SURFACE) { - map->resume(); - } else { - mbgl::Log::Debug(mbgl::Event::Android, "Not resuming because we are not ready"); - } -} - void NativeMapView::notifyMapChange(mbgl::MapChange change) { mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notifyMapChange()"); diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 5926f781ae..b0142adb17 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -24,10 +24,7 @@ public: std::array getFramebufferSize() const override; void activate() override; void deactivate() override; - void notify() override; void invalidate() override; - void beforeRender() override; - void afterRender() override; void notifyMapChange(mbgl::MapChange) override; @@ -43,8 +40,7 @@ public: void createSurface(ANativeWindow *window); void destroySurface(); - void resume(); - void pause(); + void render(); void enableFps(bool enable); void updateFps(); diff --git a/platform/darwin/src/headless_view_cgl.cpp b/platform/darwin/src/headless_view_cgl.cpp index 9f408fcbe8..a4f809a250 100644 --- a/platform/darwin/src/headless_view_cgl.cpp +++ b/platform/darwin/src/headless_view_cgl.cpp @@ -76,7 +76,7 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(isActive()); + assert(active); MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); diff --git a/platform/darwin/src/headless_view_eagl.mm b/platform/darwin/src/headless_view_eagl.mm index 26b7922168..a1f335fc6e 100644 --- a/platform/darwin/src/headless_view_eagl.mm +++ b/platform/darwin/src/headless_view_eagl.mm @@ -72,7 +72,7 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(isActive()); + assert(active); MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 6bd5f4e196..768e55ca32 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -428,7 +428,18 @@ void GLFWView::run() { const bool dirty = !clean.test_and_set(); if (dirty) { const double started = glfwGetTime(); - map->renderSync(); + + glfwMakeContextCurrent(window); + glViewport(0, 0, fbWidth, fbHeight); + + map->render(); + + if (showClipMasks) { + renderClipMasks(); + } + + glfwSwapBuffers(window); + report(1000 * (glfwGetTime() - started)); if (benchmark) { map->update(mbgl::Update::Repaint); @@ -460,31 +471,11 @@ void GLFWView::deactivate() { glfwMakeContextCurrent(nullptr); } -void GLFWView::notify() { - glfwPostEmptyEvent(); -} - void GLFWView::invalidate() { clean.clear(); glfwPostEmptyEvent(); } -void GLFWView::beforeRender() { - // This is called from the map thread but `width` and `height` - // can be accessed with no race because the main thread is blocked - // when we render. This will be more straightforward when we move - // rendering to the main thread. - glViewport(0, 0, fbWidth, fbHeight); -} - -void GLFWView::afterRender() { - if (showClipMasks) { - renderClipMasks(); - } - - glfwSwapBuffers(window); -} - void GLFWView::renderClipMasks() { // Read the stencil buffer auto pixels = std::make_unique(fbWidth * fbHeight); diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index a764eb2e06..13ea78a709 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -31,22 +31,6 @@ HeadlessView::~HeadlessView() { destroyContext(); } - -void HeadlessView::loadExtensions() { - if (extensionsLoaded) { - return; - } - - gl::InitializeExtensions(initializeExtension); - - extensionsLoaded = true; -} - - -bool HeadlessView::isActive() const { - return std::this_thread::get_id() == thread; -} - void HeadlessView::resize(const uint16_t width, const uint16_t height) { if(dimensions[0] == width && dimensions[1] == height) { @@ -57,7 +41,7 @@ void HeadlessView::resize(const uint16_t width, const uint16_t height) { } PremultipliedImage HeadlessView::readStillImage() { - assert(isActive()); + assert(active); const unsigned int w = dimensions[0] * pixelRatio; const unsigned int h = dimensions[1] * pixelRatio; @@ -76,9 +60,6 @@ PremultipliedImage HeadlessView::readStillImage() { return image; } -void HeadlessView::notify() { - // no-op -} float HeadlessView::getPixelRatio() const { return pixelRatio; @@ -94,10 +75,7 @@ std::array HeadlessView::getFramebufferSize() const { } void HeadlessView::activate() { - if (thread != std::thread::id()) { - throw std::runtime_error("OpenGL context was already current"); - } - thread = std::this_thread::get_id(); + active = true; if (!glContext) { if (!display) { @@ -107,23 +85,12 @@ void HeadlessView::activate() { } activateContext(); - loadExtensions(); -} -void HeadlessView::deactivate() { - if (thread == std::thread::id()) { - throw std::runtime_error("OpenGL context was not current"); + if (!extensionsLoaded) { + gl::InitializeExtensions(initializeExtension); + extensionsLoaded = true; } - thread = std::thread::id(); - - deactivateContext(); -} - -void HeadlessView::invalidate() { - // no-op -} -void HeadlessView::beforeRender() { if (needsResize) { clearBuffers(); resizeFramebuffer(); @@ -131,8 +98,13 @@ void HeadlessView::beforeRender() { } } -void HeadlessView::afterRender() { - // no-op +void HeadlessView::deactivate() { + deactivateContext(); + active = false; +} + +void HeadlessView::invalidate() { + assert(false); } } // namespace mbgl diff --git a/platform/default/headless_view_glx.cpp b/platform/default/headless_view_glx.cpp index d7ad9f5e55..3b719ab43a 100644 --- a/platform/default/headless_view_glx.cpp +++ b/platform/default/headless_view_glx.cpp @@ -93,7 +93,7 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(isActive()); + assert(active); MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index c989606674..459d3cf011 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -320,7 +320,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) // start paused if in IB if (_isTargetingInterfaceBuilder || background) { self.dormant = YES; - _mbglMap->pause(); } // Notify map object when network reachability status changes. @@ -751,8 +750,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5; _mbglMap->setSourceTileCacheSize(cacheSize); - - _mbglMap->renderSync(); + _mbglMap->render(); [self updateUserLocationAnnotationView]; } @@ -895,7 +893,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) { [self validateDisplayLink]; self.dormant = YES; - _mbglMap->pause(); [self.glView deleteDrawable]; } } @@ -967,8 +964,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) [self.glSnapshotView addSubview:snapshotTint]; } - _mbglMap->pause(); - [self.glView deleteDrawable]; } } @@ -988,8 +983,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) [self.glSnapshotView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; [self.glView bindDrawable]; - - _mbglMap->resume(); _displayLink.paused = NO; @@ -3957,12 +3950,10 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) class MBGLView : public mbgl::View { - public: - MBGLView(MGLMapView* nativeView_, const float scaleFactor_) - : nativeView(nativeView_), scaleFactor(scaleFactor_) { - } - virtual ~MBGLView() {} - +public: + MBGLView(MGLMapView* nativeView_, const float scaleFactor_) + : nativeView(nativeView_), scaleFactor(scaleFactor_) { + } float getPixelRatio() const override { return scaleFactor; @@ -3970,7 +3961,7 @@ class MBGLView : public mbgl::View std::array getSize() const override { return {{ static_cast([nativeView bounds].size.width), - static_cast([nativeView bounds].size.height) }}; + static_cast([nativeView bounds].size.height) }}; } std::array getFramebufferSize() const override { @@ -3978,15 +3969,14 @@ class MBGLView : public mbgl::View static_cast([[nativeView glView] drawableHeight]) }}; } - void notify() override + void notifyMapChange(mbgl::MapChange change) override { - // no-op + [nativeView notifyMapChange:change]; } - void notifyMapChange(mbgl::MapChange change) override + void invalidate() override { - assert([[NSThread currentThread] isMainThread]); - [nativeView notifyMapChange:change]; + [nativeView setNeedsGLDisplay]; } void activate() override @@ -3999,26 +3989,9 @@ class MBGLView : public mbgl::View [EAGLContext setCurrentContext:nil]; } - void invalidate() override - { - [nativeView performSelectorOnMainThread:@selector(setNeedsGLDisplay) - withObject:nil - waitUntilDone:NO]; - } - - void beforeRender() override - { - // no-op - } - - void afterRender() override - { - // no-op - } - - private: - __weak MGLMapView *nativeView = nullptr; - const float scaleFactor; +private: + __weak MGLMapView *nativeView = nullptr; + const float scaleFactor; }; @end diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index 953e485fe9..7968e83554 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -1,10 +1,8 @@ #include "node_map.hpp" #include "node_request.hpp" -#include "node_mapbox_gl_native.hpp" #include #include -#include #include @@ -474,18 +472,16 @@ NodeMap::~NodeMap() { if (valid) release(); } -std::unique_ptr NodeMap::request(const mbgl::Resource& resource, Callback cb1) { - // This function can be called from any thread. Make sure we're executing the - // JS implementation in the node event loop. - return NodeRunLoop().invokeWithCallback([this] (mbgl::Resource res, Callback cb2) { - Nan::HandleScope scope; +std::unique_ptr NodeMap::request(const mbgl::Resource& resource, Callback callback_) { + Nan::HandleScope scope; + + auto requestHandle = NodeRequest::Create(resource, callback_)->ToObject(); + auto callbackHandle = Nan::New(NodeRequest::Respond, requestHandle); - auto requestHandle = NodeRequest::Create(res, cb2)->ToObject(); - auto callbackHandle = Nan::New(NodeRequest::Respond, requestHandle); + v8::Local argv[] = { requestHandle, callbackHandle }; + Nan::MakeCallback(handle()->GetInternalField(1)->ToObject(), "request", 2, argv); - v8::Local argv[] = { requestHandle, callbackHandle }; - Nan::MakeCallback(handle()->GetInternalField(1)->ToObject(), "request", 2, argv); - }, cb1, resource); + return std::make_unique(); } } diff --git a/platform/node/src/node_mapbox_gl_native.cpp b/platform/node/src/node_mapbox_gl_native.cpp index 28df6af01c..26c49918be 100644 --- a/platform/node/src/node_mapbox_gl_native.cpp +++ b/platform/node/src/node_mapbox_gl_native.cpp @@ -5,25 +5,18 @@ #include #pragma GCC diagnostic pop -#include "node_mapbox_gl_native.hpp" +#include + #include "node_map.hpp" #include "node_log.hpp" #include "node_request.hpp" -namespace node_mbgl { - -mbgl::util::RunLoop& NodeRunLoop() { - static mbgl::util::RunLoop nodeRunLoop; - return nodeRunLoop; -} - -} - void RegisterModule(v8::Local target, v8::Local module) { // This has the effect of: // a) Ensuring that the static local variable is initialized before any thread contention. // b) unreffing an async handle, which otherwise would keep the default loop running. - node_mbgl::NodeRunLoop().stop(); + static mbgl::util::RunLoop nodeRunLoop; + nodeRunLoop.stop(); node_mbgl::NodeMap::Init(target); node_mbgl::NodeRequest::Init(target); diff --git a/platform/node/src/node_mapbox_gl_native.hpp b/platform/node/src/node_mapbox_gl_native.hpp deleted file mode 100644 index b98b035fea..0000000000 --- a/platform/node/src/node_mapbox_gl_native.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -namespace node_mbgl { - -mbgl::util::RunLoop& NodeRunLoop(); - -} diff --git a/platform/node/test/js/map.test.js b/platform/node/test/js/map.test.js index 1228900940..12b17126f9 100644 --- a/platform/node/test/js/map.test.js +++ b/platform/node/test/js/map.test.js @@ -298,7 +298,9 @@ test('Map', function(t) { t.test('returning an error', function(t) { var map = new mbgl.Map({ request: function(req, callback) { - callback(new Error('request error')); + setImmediate(function () { + callback(new Error('request error')); + }); }, }); map.load(style); diff --git a/platform/osx/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm index 6f20e957a6..5978251437 100644 --- a/platform/osx/src/MGLMapView.mm +++ b/platform/osx/src/MGLMapView.mm @@ -540,7 +540,6 @@ public: [self deselectAnnotation:self.selectedAnnotation]; if (!self.dormant && !newWindow) { self.dormant = YES; - _mbglMap->pause(); } [self.window removeObserver:self forKeyPath:@"contentLayoutRect"]; @@ -550,7 +549,6 @@ public: - (void)viewDidMoveToWindow { NSWindow *window = self.window; if (self.dormant && window) { - _mbglMap->resume(); self.dormant = NO; } @@ -686,8 +684,31 @@ public: NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5; _mbglMap->setSourceTileCacheSize(cacheSize); - _mbglMap->renderSync(); - + + // Enable vertex buffer objects. + mbgl::gl::InitializeExtensions([](const char *name) { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void *symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast(symbol); + }); + + _mbglMap->render(); + + if (_isPrinting) { + _isPrinting = NO; + std::string png = encodePNG(_mbglView->readStillImage()); + NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()]; + NSImage *image = [[NSImage alloc] initWithData:data]; + [self printWithImage:image]; + } + // [self updateUserLocationAnnotationView]; } } @@ -2270,85 +2291,39 @@ class MGLMapViewImpl : public mbgl::View { public: MGLMapViewImpl(MGLMapView *nativeView_, const float scaleFactor_) : nativeView(nativeView_), scaleFactor(scaleFactor_) {} - virtual ~MGLMapViewImpl() {} - - + float getPixelRatio() const override { return scaleFactor; } - + std::array getSize() const override { return {{ static_cast(nativeView.bounds.size.width), - static_cast(nativeView.bounds.size.height) }}; + static_cast(nativeView.bounds.size.height) }}; } - + std::array getFramebufferSize() const override { NSRect bounds = [nativeView convertRectToBacking:nativeView.bounds]; return {{ static_cast(bounds.size.width), - static_cast(bounds.size.height) }}; + static_cast(bounds.size.height) }}; } - - void notify() override {} - + void notifyMapChange(mbgl::MapChange change) override { - assert([[NSThread currentThread] isMainThread]); [nativeView notifyMapChange:change]; } - + + void invalidate() override { + [nativeView invalidate]; + } + void activate() override { MGLOpenGLLayer *layer = (MGLOpenGLLayer *)nativeView.layer; - if ([NSOpenGLContext currentContext] != layer.openGLContext) { - // Enable our OpenGL context on the Map thread. - [layer.openGLContext makeCurrentContext]; - - // Enable vertex buffer objects. - mbgl::gl::InitializeExtensions([](const char *name) { - static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - if (!framework) { - throw std::runtime_error("Failed to load OpenGL framework."); - } - - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); - void *symbol = CFBundleGetFunctionPointerForName(framework, str); - CFRelease(str); - - return reinterpret_cast(symbol); - }); - } + [layer.openGLContext makeCurrentContext]; } - + void deactivate() override { [NSOpenGLContext clearCurrentContext]; } - - void invalidate() override { - [nativeView performSelectorOnMainThread:@selector(invalidate) - withObject:nil - waitUntilDone:NO]; - } - - void beforeRender() override { - // This normally gets called right away by mbgl::Map, but only on the - // main thread. OpenGL contexts and extensions are thread-local, so this - // has to happen on the Map thread too. - activate(); - -// auto size = getFramebufferSize(); -// MBGL_CHECK_ERROR(glViewport(0, 0, size[0], size[1])); - } - - void afterRender() override { - if (nativeView->_isPrinting) { - nativeView->_isPrinting = NO; - std::string png = encodePNG(readStillImage()); - NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()]; - NSImage *image = [[NSImage alloc] initWithData:data]; - [nativeView performSelectorOnMainThread:@selector(printWithImage:) - withObject:image - waitUntilDone:NO]; - } - } - + mbgl::PremultipliedImage readStillImage() override { auto size = getFramebufferSize(); const unsigned int w = size[0]; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index c9123495cd..7300e5c3bb 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -12,7 +12,6 @@ #include #include -#include #include namespace mbgl { @@ -20,46 +19,24 @@ namespace mbgl { Map::Map(View& view_, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode) : view(view_), transform(std::make_unique(view, constrainMode)), - context(std::make_unique>( - util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, + context(std::make_unique( view, fileSource, mapMode, contextMode, view.getPixelRatio())), - data(&context->invokeSync(&MapContext::getData)) + data(&context->getData()) { view.initialize(this); update(Update::Dimensions); } Map::~Map() { - resume(); - context->invokeSync(&MapContext::cleanup); -} - -void Map::pause() { - assert(data->mode == MapMode::Continuous); - - std::unique_lock lockPause(data->mutexPause); - if (!data->paused) { - context->invoke(&MapContext::pause); - data->condPause.wait(lockPause, [&]{ return data->paused; }); - } -} - -bool Map::isPaused() { - return data->paused; -} - -void Map::resume() { - std::unique_lock lockPause(data->mutexPause); - data->paused = false; - data->condPause.notify_all(); + context->cleanup(); } void Map::renderStill(StillImageCallback callback) { - context->invoke(&MapContext::renderStill, transform->getState(), + context->renderStill(transform->getState(), FrameData { view.getFramebufferSize(), Clock::now() }, callback); } -void Map::renderSync() { +void Map::render() { if (renderState == RenderState::never) { view.notifyMapChange(MapChangeWillStartRenderingMap); } @@ -67,8 +44,7 @@ void Map::renderSync() { view.notifyMapChange(MapChangeWillStartRenderingFrame); const Update flags = transform->updateTransitions(Clock::now()); - const bool fullyLoaded = context->invokeSync( - &MapContext::renderSync, transform->getState(), FrameData { view.getFramebufferSize(), Clock::now() }); + const bool fullyLoaded = context->renderSync(transform->getState(), FrameData { view.getFramebufferSize(), Clock::now() }); view.notifyMapChange(fullyLoaded ? MapChangeDidFinishRenderingFrameFullyRendered : @@ -94,7 +70,7 @@ void Map::renderSync() { void Map::update(Update flags) { if (flags & Update::Dimensions) transform->resize(view.getSize()); - context->invoke(&MapContext::triggerUpdate, transform->getState(), flags); + context->triggerUpdate(transform->getState(), flags); } #pragma mark - Style @@ -102,21 +78,21 @@ void Map::update(Update flags) { void Map::setStyleURL(const std::string &url) { loading = true; view.notifyMapChange(MapChangeWillStartLoadingMap); - context->invoke(&MapContext::setStyleURL, url); + context->setStyleURL(url); } void Map::setStyleJSON(const std::string& json, const std::string& base) { loading = true; view.notifyMapChange(MapChangeWillStartLoadingMap); - context->invoke(&MapContext::setStyleJSON, json, base); + context->setStyleJSON(json, base); } std::string Map::getStyleURL() const { - return context->invokeSync(&MapContext::getStyleURL); + return context->getStyleURL(); } std::string Map::getStyleJSON() const { - return context->invokeSync(&MapContext::getStyleJSON); + return context->getStyleJSON(); } #pragma mark - Transitions @@ -436,15 +412,15 @@ LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const { #pragma mark - Annotations void Map::addAnnotationIcon(const std::string& name, std::shared_ptr sprite) { - context->invoke(&MapContext::addAnnotationIcon, name, sprite); + context->addAnnotationIcon(name, sprite); } void Map::removeAnnotationIcon(const std::string& name) { - context->invoke(&MapContext::removeAnnotationIcon, name); + context->removeAnnotationIcon(name); } double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& symbol) { - return context->invokeSync(&MapContext::getTopOffsetPixelsForAnnotationIcon, symbol); + return context->getTopOffsetPixelsForAnnotationIcon(symbol); } AnnotationID Map::addPointAnnotation(const PointAnnotation& annotation) { @@ -489,17 +465,21 @@ AnnotationIDs Map::getPointAnnotationsInBounds(const LatLngBounds& bounds) { void Map::addCustomLayer(const std::string& id, CustomLayerInitializeFunction initialize, - CustomLayerRenderFunction render, + CustomLayerRenderFunction render_, CustomLayerDeinitializeFunction deinitialize, void* context_, const char* before) { - context->invoke(&MapContext::addLayer, - std::make_unique(id, initialize, render, deinitialize, context_), + view.activate(); + context->addLayer( + std::make_unique(id, initialize, render_, deinitialize, context_), before ? std::string(before) : optional()); + view.deactivate(); } void Map::removeCustomLayer(const std::string& id) { - context->invoke(&MapContext::removeLayer, id); + view.activate(); + context->removeLayer(id); + view.deactivate(); } #pragma mark - Toggles @@ -519,39 +499,39 @@ MapDebugOptions Map::getDebug() const { } bool Map::isFullyLoaded() const { - return context->invokeSync(&MapContext::isLoaded); + return context->isLoaded(); } void Map::addClass(const std::string& className, const PropertyTransition& properties) { - context->invoke(&MapContext::addClass, className, properties); + context->addClass(className, properties); } void Map::removeClass(const std::string& className, const PropertyTransition& properties) { - context->invoke(&MapContext::removeClass, className, properties); + context->removeClass(className, properties); } void Map::setClasses(const std::vector& classNames, const PropertyTransition& properties) { - context->invoke(&MapContext::setClasses, classNames, properties); + context->setClasses(classNames, properties); } bool Map::hasClass(const std::string& className) const { - return context->invokeSync(&MapContext::hasClass, className); + return context->hasClass(className); } std::vector Map::getClasses() const { - return context->invokeSync>(&MapContext::getClasses); + return context->getClasses(); } void Map::setSourceTileCacheSize(size_t size) { - context->invoke(&MapContext::setSourceTileCacheSize, size); + context->setSourceTileCacheSize(size); } void Map::onLowMemory() { - context->invoke(&MapContext::onLowMemory); + context->onLowMemory(); } void Map::dumpDebugLogs() const { - context->invokeSync(&MapContext::dumpDebugLogs); + context->dumpDebugLogs(); } } // namespace mbgl diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 0ea51bf53a..2ff93d2338 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -35,11 +35,7 @@ MapContext::MapContext(View& view_, FileSource& fileSource_, MapMode mode_, GLCo dataPtr(std::make_unique(mode_, contextMode_, pixelRatio_)), data(*dataPtr), asyncUpdate([this] { update(); }), - asyncInvalidate([&view_] { view_.invalidate(); }), texturePool(std::make_unique()) { - assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - - view.activate(); } MapContext::~MapContext() { @@ -48,7 +44,7 @@ MapContext::~MapContext() { } void MapContext::cleanup() { - view.notify(); + view.activate(); styleRequest = nullptr; @@ -64,21 +60,6 @@ void MapContext::cleanup() { view.deactivate(); } -void MapContext::pause() { - MBGL_CHECK_ERROR(glFinish()); - - view.deactivate(); - - std::unique_lock lockPause(data.mutexPause); - data.paused = true; - data.condPause.notify_all(); - data.condPause.wait(lockPause, [&]{ return !data.paused; }); - - view.activate(); - - asyncInvalidate.send(); -} - void MapContext::updateAsync(Update flags) { updateFlags |= flags; asyncUpdate.send(); @@ -180,9 +161,11 @@ void MapContext::update() { style->update(transformState, frameData.timePoint, *texturePool); if (data.mode == MapMode::Continuous) { - asyncInvalidate.send(); + view.invalidate(); } else if (callback && isLoaded()) { + view.activate(); renderSync(transformState, frameData); + view.deactivate(); } updateFlags = Update::Nothing; @@ -229,8 +212,6 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame) return false; } - view.beforeRender(); - transformState = state; frameData = frame; @@ -245,8 +226,6 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame) // Cleanup OpenGL objects that we abandoned since the last render call. glObjectStore.performCleanup(); - view.afterRender(); - if (style->hasTransitions()) { updateAsync(Update::RecalculateStyle); } else if (painter->needsAnimation()) { @@ -312,7 +291,7 @@ void MapContext::setSourceTileCacheSize(size_t size) { sourceCacheSize = size; if (!style) return; style->setSourceTileCacheSize(size); - asyncInvalidate.send(); + view.invalidate(); } } @@ -320,7 +299,7 @@ void MapContext::onLowMemory() { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (!style) return; style->onLowMemory(); - asyncInvalidate.send(); + view.invalidate(); } void MapContext::onResourceLoaded() { diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 5e1d5e70ae..93e7a52b25 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -37,8 +37,6 @@ public: MapData& getData() { return data; } - void pause(); - void triggerUpdate(const TransformState&, Update = Update::Nothing); void renderStill(const TransformState&, const FrameData&, Map::StillImageCallback callback); @@ -97,7 +95,6 @@ private: Update updateFlags = Update::Nothing; util::AsyncTask asyncUpdate; - util::AsyncTask asyncInvalidate; std::unique_ptr texturePool; std::unique_ptr painter; diff --git a/src/mbgl/map/map_data.hpp b/src/mbgl/map/map_data.hpp index 0513d84f87..63a9dbd1e1 100644 --- a/src/mbgl/map/map_data.hpp +++ b/src/mbgl/map/map_data.hpp @@ -1,11 +1,8 @@ #ifndef MBGL_MAP_MAP_DATA #define MBGL_MAP_MAP_DATA -#include -#include #include #include -#include #include #include @@ -14,8 +11,6 @@ namespace mbgl { class MapData { - using Lock = std::lock_guard; - public: inline MapData(MapMode mode_, GLContextMode contextMode_, const float pixelRatio_) : mode(mode_) @@ -46,10 +41,8 @@ public: debugOptions = debugOptions_; } - util::exclusive getAnnotationManager() { - return util::exclusive( - &annotationManager, - std::make_unique>(annotationManagerMutex)); + AnnotationManager* getAnnotationManager() { + return &annotationManager; } public: @@ -58,16 +51,12 @@ public: const float pixelRatio; private: - mutable std::mutex annotationManagerMutex; AnnotationManager annotationManager; - std::atomic debugOptions { MapDebugOptions::NoDebug }; + MapDebugOptions debugOptions { MapDebugOptions::NoDebug }; // TODO: make private public: - bool paused = false; - std::mutex mutexPause; - std::condition_variable condPause; }; } // namespace mbgl diff --git a/src/mbgl/util/thread_context.hpp b/src/mbgl/util/thread_context.hpp index dea98fe3fa..bd591e88a5 100644 --- a/src/mbgl/util/thread_context.hpp +++ b/src/mbgl/util/thread_context.hpp @@ -15,7 +15,7 @@ enum class ThreadPriority : bool { enum class ThreadType : uint8_t { Main, - Map, + Map = Main, Worker, Unknown, }; diff --git a/test/api/annotations.cpp b/test/api/annotations.cpp index 0af64095c1..f403512660 100644 --- a/test/api/annotations.cpp +++ b/test/api/annotations.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,8 @@ void checkRendering(Map& map, const char * name) { } // end namespace TEST(Annotations, PointAnnotation) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -42,6 +45,8 @@ TEST(Annotations, PointAnnotation) { } TEST(Annotations, LineAnnotation) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -61,6 +66,8 @@ TEST(Annotations, LineAnnotation) { } TEST(Annotations, FillAnnotation) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -79,6 +86,8 @@ TEST(Annotations, FillAnnotation) { } TEST(Annotations, StyleSourcedShapeAnnotation) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -94,6 +103,8 @@ TEST(Annotations, StyleSourcedShapeAnnotation) { } TEST(Annotations, AddMultiple) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -111,6 +122,8 @@ TEST(Annotations, AddMultiple) { } TEST(Annotations, NonImmediateAdd) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -131,6 +144,8 @@ TEST(Annotations, NonImmediateAdd) { } TEST(Annotations, UpdateIcon) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -150,6 +165,8 @@ TEST(Annotations, UpdateIcon) { } TEST(Annotations, UpdatePoint) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -168,6 +185,8 @@ TEST(Annotations, UpdatePoint) { } TEST(Annotations, RemovePoint) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -185,6 +204,8 @@ TEST(Annotations, RemovePoint) { } TEST(Annotations, RemoveShape) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -207,6 +228,8 @@ TEST(Annotations, RemoveShape) { } TEST(Annotations, ImmediateRemoveShape) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; @@ -219,6 +242,8 @@ TEST(Annotations, ImmediateRemoveShape) { } TEST(Annotations, SwitchStyle) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; diff --git a/test/api/api_misuse.cpp b/test/api/api_misuse.cpp index 932c4717e8..5e413df369 100644 --- a/test/api/api_misuse.cpp +++ b/test/api/api_misuse.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -15,6 +16,8 @@ TEST(API, RenderWithoutCallback) { FixtureLogObserver* log = new FixtureLogObserver(); Log::setObserver(std::unique_ptr(log)); + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); view.resize(128, 512); @@ -37,6 +40,8 @@ TEST(API, RenderWithoutCallback) { } TEST(API, RenderWithoutStyle) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); view.resize(128, 512); @@ -44,13 +49,16 @@ TEST(API, RenderWithoutStyle) { Map map(view, fileSource, MapMode::Still); - std::promise promise; - map.renderStill([&promise](std::exception_ptr error, PremultipliedImage&&) { - promise.set_value(error); + std::exception_ptr error; + map.renderStill([&](std::exception_ptr error_, PremultipliedImage&&) { + error = error_; + loop.stop(); }); + loop.run(); + try { - std::rethrow_exception(promise.get_future().get()); + std::rethrow_exception(error); } catch (const util::MisuseException& ex) { EXPECT_EQ(std::string(ex.what()), "Map doesn't have a style"); } catch (const std::exception&) { diff --git a/test/api/custom_layer.cpp b/test/api/custom_layer.cpp index 5346fee124..46eecb2250 100644 --- a/test/api/custom_layer.cpp +++ b/test/api/custom_layer.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace mbgl; @@ -68,6 +69,8 @@ public: }; TEST(CustomLayer, Basic) { + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; diff --git a/test/api/render_missing.cpp b/test/api/render_missing.cpp index f29a0c2b9c..bb14416840 100644 --- a/test/api/render_missing.cpp +++ b/test/api/render_missing.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -19,6 +20,8 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { using namespace mbgl; + util::RunLoop loop; + const auto style = util::read_file("test/fixtures/api/water_missing_tiles.json"); auto display = std::make_shared(); @@ -38,8 +41,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { // This host does not respond (== connection error). map.setStyleJSON(style, ""); - std::promise promise; - map.renderStill([&promise, &message](std::exception_ptr err, PremultipliedImage&&) { + map.renderStill([&](std::exception_ptr err, PremultipliedImage&&) { ASSERT_TRUE(err.operator bool()); try { std::rethrow_exception(err); @@ -47,9 +49,10 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { message = ex.what(); EXPECT_TRUE(message.find("connect") != std::string::npos); } - promise.set_value(); + loop.stop(); }); - promise.get_future().get(); + + loop.run(); auto observer = Log::removeObserver(); auto flo = dynamic_cast(observer.get()); diff --git a/test/api/repeated_render.cpp b/test/api/repeated_render.cpp index ef707aa7c4..cf5d115997 100644 --- a/test/api/repeated_render.cpp +++ b/test/api/repeated_render.cpp @@ -7,12 +7,15 @@ #include #include #include +#include #include TEST(API, RepeatedRender) { using namespace mbgl; + util::RunLoop loop; + const auto style = util::read_file("test/fixtures/api/water.json"); auto display = std::make_shared(); @@ -30,11 +33,15 @@ TEST(API, RepeatedRender) { { map.setStyleJSON(style, ""); - std::promise promise; - map.renderStill([&promise](std::exception_ptr, PremultipliedImage&& image) { - promise.set_value(std::move(image)); + PremultipliedImage result; + map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) { + result = std::move(image); }); - auto result = promise.get_future().get(); + + while (!result.size()) { + loop.runOnce(); + } + ASSERT_EQ(256, result.width); ASSERT_EQ(512, result.height); #if !TEST_READ_ONLY @@ -44,11 +51,15 @@ TEST(API, RepeatedRender) { { map.setStyleJSON(style, ""); - std::promise promise; - map.renderStill([&promise](std::exception_ptr, PremultipliedImage&& image) { - promise.set_value(std::move(image)); + PremultipliedImage result; + map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) { + result = std::move(image); }); - auto result = promise.get_future().get(); + + while (!result.size()) { + loop.runOnce(); + } + ASSERT_EQ(256, result.width); ASSERT_EQ(512, result.height); #if !TEST_READ_ONLY diff --git a/test/api/set_style.cpp b/test/api/set_style.cpp index 329ec2801d..317021b8db 100644 --- a/test/api/set_style.cpp +++ b/test/api/set_style.cpp @@ -5,11 +5,14 @@ #include #include #include +#include TEST(API, SetStyle) { using namespace mbgl; + util::RunLoop loop; + auto display = std::make_shared(); HeadlessView view(display, 1); OnlineFileSource fileSource; diff --git a/test/map/map.cpp b/test/map/map.cpp index b1048e97e2..2bc00b4334 100644 --- a/test/map/map.cpp +++ b/test/map/map.cpp @@ -3,59 +3,17 @@ #include #include #include -#include #include -#include #include #include +#include using namespace mbgl; using namespace std::literals::string_literals; -TEST(Map, PauseResume) { - auto display = std::make_shared(); - HeadlessView view(display, 1); - OnlineFileSource fileSource; - - Map map(view, fileSource, MapMode::Continuous); - - map.pause(); - map.resume(); -} - -TEST(Map, DoublePause) { - auto display = std::make_shared(); - HeadlessView view(display, 1); - OnlineFileSource fileSource; - - Map map(view, fileSource, MapMode::Continuous); - - map.pause(); - map.pause(); - map.resume(); -} - -TEST(Map, ResumeWithoutPause) { - auto display = std::make_shared(); - HeadlessView view(display, 1); - OnlineFileSource fileSource; - - Map map(view, fileSource, MapMode::Continuous); - - map.resume(); -} - -TEST(Map, DestroyPaused) { - auto display = std::make_shared(); - HeadlessView view(display, 1); - OnlineFileSource fileSource; - - Map map(view, fileSource, MapMode::Continuous); - - map.pause(); -} - TEST(Map, Offline) { + util::RunLoop runLoop; + auto display = std::make_shared(); HeadlessView view(display, 1); DefaultFileSource fileSource(":memory:", "."); diff --git a/test/src/mbgl/test/mock_view.hpp b/test/src/mbgl/test/mock_view.hpp index e608545da5..50ae466d19 100644 --- a/test/src/mbgl/test/mock_view.hpp +++ b/test/src/mbgl/test/mock_view.hpp @@ -18,10 +18,7 @@ public: void activate() override {}; void deactivate() override {}; - void notify() override {}; void invalidate() override {} - void beforeRender() override {} - void afterRender() override {} }; } diff --git a/test/src/mbgl/test/util.cpp b/test/src/mbgl/test/util.cpp index ca2282a4b5..4021fd89b1 100644 --- a/test/src/mbgl/test/util.cpp +++ b/test/src/mbgl/test/util.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -86,11 +87,16 @@ Server::~Server() { } PremultipliedImage render(Map& map) { - std::promise promise; - map.renderStill([&](std::exception_ptr, PremultipliedImage&& image) { - promise.set_value(std::move(image)); + PremultipliedImage result; + map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) { + result = std::move(image); }); - return promise.get_future().get(); + + while (!result.size()) { + util::RunLoop::Get()->runOnce(); + } + + return result; } void checkImage(const std::string& base, diff --git a/test/test.gypi b/test/test.gypi index 42dab6432c..6b3b43bd0c 100644 --- a/test/test.gypi +++ b/test/test.gypi @@ -41,7 +41,6 @@ 'geometry/binpack.cpp', - 'map/map.cpp', 'map/map_context.cpp', 'map/tile.cpp', 'map/transform.cpp', -- cgit v1.2.1