diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | android/cpp/jni.cpp | 28 | ||||
-rw-r--r-- | android/cpp/native_map_view.cpp | 9 | ||||
-rw-r--r-- | android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java | 22 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | gyp/common.gypi | 1 | ||||
-rw-r--r-- | include/mbgl/android/native_map_view.hpp | 5 | ||||
-rw-r--r-- | include/mbgl/map/map.hpp | 38 | ||||
-rw-r--r-- | include/mbgl/map/view.hpp | 16 | ||||
-rw-r--r-- | include/mbgl/platform/default/glfw_view.hpp | 13 | ||||
-rw-r--r-- | include/mbgl/platform/default/headless_view.hpp | 11 | ||||
-rw-r--r-- | ios/app/mapboxgl-app.gyp | 1 | ||||
-rw-r--r-- | linux/mapboxgl-app.gyp | 4 | ||||
-rw-r--r-- | platform/default/glfw_view.cpp | 9 | ||||
-rw-r--r-- | platform/default/headless_view.cpp | 9 | ||||
-rw-r--r-- | platform/ios/MGLMapView.mm | 31 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 153 | ||||
-rw-r--r-- | src/mbgl/map/source.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/map/view.cpp | 10 |
20 files changed, 183 insertions, 207 deletions
diff --git a/.gitignore b/.gitignore index 3ee0136c6c..59c180c5de 100644 --- a/.gitignore +++ b/.gitignore @@ -4,12 +4,15 @@ *.actual.png *.diff.png *.pyc +/android/debug +/android/sdk /mason_packages /config/*.gypi /build /macosx/build /linux/build /ios/build +/ios/app/build /test/build /test/node_modules /include/mbgl/shader/shaders.hpp @@ -2,12 +2,13 @@ BUILDTYPE ?= Release PYTHON ?= python PREFIX ?= /usr/local ANDROID_ABI ?= arm-v7 -JOBS ?= 1 ifeq ($(shell uname -s), Darwin) HOST ?= osx +JOBS ?= $(shell sysctl -n hw.ncpu) endif HOST ?= linux +JOBS ?= 1 all: mbgl @@ -65,7 +66,7 @@ xtest-proj: Xcode/test open ./build/osx/test/test.xcodeproj xtest: Xcode/test - xcodebuild -project ./build/osx/test/test.xcodeproj -configuration $(BUILDTYPE) -target test -jobs `sysctl -n hw.ncpu` + xcodebuild -project ./build/osx/test/test.xcodeproj -configuration $(BUILDTYPE) -target test -jobs $(JOBS) xtest-%: xtest ./scripts/run_tests.sh "build/osx/Build/Products/$(BUILDTYPE)/test" --gtest_filter=$* @@ -94,7 +95,7 @@ xosx-proj: Xcode/osx open ./build/osx/macosx/mapboxgl-app.xcodeproj xosx: Xcode/osx - xcodebuild -project ./build/osx/macosx/mapboxgl-app.xcodeproj -configuration $(BUILDTYPE) -target osxapp -jobs `sysctl -n hw.ncpu` + xcodebuild -project ./build/osx/macosx/mapboxgl-app.xcodeproj -configuration $(BUILDTYPE) -target osxapp -jobs $(JOBS) run-xosx: xosx "build/osx/Build/Products/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL" @@ -115,10 +116,10 @@ ios-proj: Xcode/ios open ./build/ios/ios/app/mapboxgl-app.xcodeproj ios: Xcode/ios - xcodebuild -sdk iphoneos ARCHS="arm64 armv7 armv7s" PROVISIONING_PROFILE="2b532944-bf3d-4bf4-aa6c-a81676984ae8" -project ./build/ios/ios/app/mapboxgl-app.xcodeproj -configuration Release -target iosapp -jobs `sysctl -n hw.ncpu` + xcodebuild -sdk iphoneos ARCHS="arm64 armv7 armv7s" PROVISIONING_PROFILE="2b532944-bf3d-4bf4-aa6c-a81676984ae8" -project ./build/ios/ios/app/mapboxgl-app.xcodeproj -configuration Release -target iosapp -jobs $(JOBS) isim: Xcode/ios - xcodebuild -sdk iphonesimulator ARCHS="x86_64 i386" -project ./build/ios/ios/app/mapboxgl-app.xcodeproj -configuration Debug -target iosapp -jobs `sysctl -n hw.ncpu` + xcodebuild -sdk iphonesimulator ARCHS="x86_64 i386" -project ./build/ios/ios/app/mapboxgl-app.xcodeproj -configuration Debug -target iosapp -jobs $(JOBS) # Legacy name iproj: ios-proj @@ -194,6 +195,14 @@ Makefile/render: bin/render.gyp config/$(HOST).gypi render: Makefile/render $(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) mbgl-render +.PRECIOUS: Xcode/render +Xcode/render: bin/render.gyp config/osx.gypi styles/styles + deps/run_gyp bin/render.gyp $(CONFIG_osx) $(LIBS_osx) --generator-output=./build/osx -f xcode + +.PHONY: xrender-proj +xrender-proj: Xcode/render + open ./build/osx/bin/render.xcodeproj + ##### Maintenace operations #################################################### diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index 1163c33b57..8a67c0e876 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -291,18 +291,11 @@ void JNICALL nativeRun(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { nativeMapView->getMap().run(); } -void JNICALL nativeRerender(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeRerender"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->getMap().rerender(); -} - void JNICALL nativeUpdate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->getMap().update(); + nativeMapView->getMap().triggerUpdate(); } void JNICALL nativeTerminate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { @@ -312,20 +305,6 @@ void JNICALL nativeTerminate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { nativeMapView->getMap().terminate(); } -jboolean JNICALL nativeNeedsSwap(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeNeedsSwap"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - return nativeMapView->getMap().needsSwap(); -} - -void JNICALL nativeSwapped(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeSwapped"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->getMap().swapped(); -} - void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height, jfloat ratio, jint fbWidth, jint fbHeight) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeResize"); @@ -1002,7 +981,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { // NOTE: if you get java.lang.UnsatisfiedLinkError you likely forgot to set the size of the // array correctly (too large) - std::array<JNINativeMethod, 66> methods = {{ // Can remove the extra brace in C++14 + std::array<JNINativeMethod, 63> methods = {{ // Can remove the extra brace in C++14 {"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", reinterpret_cast<void *>(&nativeCreate)}, {"nativeDestroy", "(J)V", reinterpret_cast<void *>(&nativeDestroy)}, @@ -1018,11 +997,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { {"nativePause", "(J)V", reinterpret_cast<void *>(&nativePause)}, {"nativeResume", "(J)V", reinterpret_cast<void *>(&nativeResume)}, {"nativeRun", "(J)V", reinterpret_cast<void *>(&nativeRun)}, - {"nativeRerender", "(J)V", reinterpret_cast<void *>(&nativeRerender)}, {"nativeUpdate", "(J)V", reinterpret_cast<void *>(&nativeUpdate)}, {"nativeTerminate", "(J)V", reinterpret_cast<void *>(&nativeTerminate)}, - {"nativeNeedsSwap", "(J)Z", reinterpret_cast<void *>(&nativeNeedsSwap)}, - {"nativeSwapped", "(J)V", reinterpret_cast<void *>(&nativeSwapped)}, {"nativeResize", "(JIIFII)V", reinterpret_cast<void *>(static_cast<void JNICALL ( *)(JNIEnv *, jobject, jlong, jint, jint, jfloat, jint, jint)>(&nativeResize))}, diff --git a/android/cpp/native_map_view.cpp b/android/cpp/native_map_view.cpp index 35bb6b88a9..39a777bff2 100644 --- a/android/cpp/native_map_view.cpp +++ b/android/cpp/native_map_view.cpp @@ -121,16 +121,17 @@ void NativeMapView::deactivate() { } } -void NativeMapView::swap() { - mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::swap"); +void NativeMapView::invalidate() { + mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::invalidate"); + + if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) { + map.render(); - if (map.needsSwap() && (display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) { if (!eglSwapBuffers(display, surface)) { mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d", eglGetError()); throw new std::runtime_error("eglSwapBuffers() failed"); } - map.swapped(); updateFps(); } else { mbgl::Log::Info(mbgl::Event::Android, "Not swapping as we are not ready"); diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java index a73a89d2d7..186b391a84 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java @@ -93,26 +93,10 @@ class NativeMapView { nativeRun(mNativeMapViewPtr); } - public void rerender() { - nativeRerender(mNativeMapViewPtr); - } - public void update() { nativeUpdate(mNativeMapViewPtr); } - public void terminate() { - nativeTerminate(mNativeMapViewPtr); - } - - public boolean needsSwap() { - return nativeNeedsSwap(mNativeMapViewPtr); - } - - public void swapped() { - nativeSwapped(mNativeMapViewPtr); - } - public void resize(int width, int height, float ratio, int fbWidth, int fbHeight) { if (width < 0) { @@ -440,16 +424,10 @@ class NativeMapView { private native void nativeRun(long nativeMapViewPtr); - private native void nativeRerender(long nativeMapViewPtr); - private native void nativeUpdate(long nativeMapViewPtr); private native void nativeTerminate(long nativeMapViewPtr); - private native boolean nativeNeedsSwap(long nativeMapViewPtr); - - private native void nativeSwapped(long nativeMapViewPtr); - private native void nativeResize(long nativeMapViewPtr, int width, int height, float ratio, int fbWidth, int fbHeight); @@ -37,7 +37,7 @@ case ${MASON_PLATFORM} in LIBZIP_VERSION=0.11.2 ;; *) - GLFW_VERSION=e1ae9af5 + GLFW_VERSION=3.1 SQLITE_VERSION=3.8.8.1 LIBPNG_VERSION=1.6.16 LIBJPEG_VERSION=v9a diff --git a/gyp/common.gypi b/gyp/common.gypi index 7cf13fff6e..01f1451dd0 100644 --- a/gyp/common.gypi +++ b/gyp/common.gypi @@ -7,7 +7,6 @@ 'conditions': [ ['OS=="mac"', { 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9', 'CLANG_CXX_LIBRARY': 'libc++', 'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', diff --git a/include/mbgl/android/native_map_view.hpp b/include/mbgl/android/native_map_view.hpp index d02d43e58a..62446bf15a 100644 --- a/include/mbgl/android/native_map_view.hpp +++ b/include/mbgl/android/native_map_view.hpp @@ -22,10 +22,9 @@ public: void activate() override; void deactivate() override; - - void swap() override; - void notify() override; + void invalidate() override; + void notifyMapChange(mbgl::MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()) override; mbgl::Map &getMap(); diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 00719aa382..44a560a468 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -65,19 +65,22 @@ public: // frame is completely rendered. void run(); - // Triggers a lazy rerender: only performs a render when the map is not clean. - void rerender(); + // Triggers a synchronous or asynchronous render. + void renderSync(); - // Forces a map update: always triggers a rerender. - void update(); + // Unconditionally performs a render with the current map state. May only be called from the Map + // thread. + void render(); + + // Notifies the Map thread that the state has changed and an update might be necessary. + void triggerUpdate(); + + // Triggers a render. Can be called from any thread. + void triggerRender(); // Releases resources immediately void terminate(); - // Controls buffer swapping. - bool needsSwap(); - void swapped(); - // Styling void addClass(const std::string&); void removeClass(const std::string&); @@ -167,9 +170,6 @@ private: // the stylesheet. void prepare(); - // Unconditionally performs a render with the current map state. - void render(); - enum class Mode : uint8_t { None, // we're not doing any processing Continuous, // continually updating map @@ -185,6 +185,7 @@ private: std::unique_ptr<uv::worker> workers; std::thread thread; std::unique_ptr<uv::async> asyncTerminate; + std::unique_ptr<uv::async> asyncUpdate; std::unique_ptr<uv::async> asyncRender; bool terminating = false; @@ -195,17 +196,10 @@ private: std::mutex mutexPause; std::condition_variable condPause; - // If cleared, the next time the render thread attempts to render the map, it will *actually* - // render the map. - std::atomic_flag isClean = ATOMIC_FLAG_INIT; - - // If this flag is cleared, the current back buffer is ready for being swapped with the front - // buffer (i.e. it has rendered data). - std::atomic_flag isSwapped = ATOMIC_FLAG_INIT; - - // This is cleared once the current front buffer has been presented and the back buffer is - // ready for rendering. - std::atomic_flag isRendered = ATOMIC_FLAG_INIT; + // Used to signal that rendering completed. + bool rendered = false; + std::condition_variable condRendered; + std::mutex mutexRendered; // Stores whether the map thread has been stopped already. std::atomic_bool isStopped; diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp index 7d8c25f445..1ee9d300c5 100644 --- a/include/mbgl/map/view.hpp +++ b/include/mbgl/map/view.hpp @@ -22,13 +22,7 @@ enum MapChange : uint8_t { class View { public: - virtual void initialize(Map *map_) { - map = map_; - } - - // Called from the render (=GL) thread. Signals that the context should - // swap the front and the back buffer. - virtual void swap() = 0; + 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 @@ -41,10 +35,16 @@ public: virtual void notify() = 0; + // Called from the render thread. The implementation must trigger a rerender. + // (i.e. map->renderSync() or map->renderAsync() must be called as a result of this) + virtual void invalidate() = 0; + // Notifies a watcher of map x/y/scale/rotation changes. // Must only be called from the same thread that caused the change. // Must not be called from the render thread. - virtual void notifyMapChange(MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()) = 0; + virtual void notifyMapChange( + MapChange change, + std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()); protected: // Resizes the view diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp index 8f5cfb7281..234568e4b7 100644 --- a/include/mbgl/platform/default/glfw_view.hpp +++ b/include/mbgl/platform/default/glfw_view.hpp @@ -13,12 +13,11 @@ public: GLFWView(bool fullscreen = false); ~GLFWView(); - void initialize(mbgl::Map *map); - void swap(); - void activate(); - void deactivate(); - void notify(); - void notifyMapChange(mbgl::MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()); + void initialize(mbgl::Map *map) override; + void activate() override; + void deactivate() override; + void notify() override; + void invalidate() override; static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods); static void onScroll(GLFWwindow *window, double xoffset, double yoffset); @@ -26,8 +25,6 @@ public: static void onMouseClick(GLFWwindow *window, int button, int action, int modifiers); static void onMouseMove(GLFWwindow *window, double x, double y); - static void eventloop(void *arg); - int run(); void fps(); diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp index 5d0e55d69a..5ba6709a4f 100644 --- a/include/mbgl/platform/default/headless_view.hpp +++ b/include/mbgl/platform/default/headless_view.hpp @@ -13,7 +13,7 @@ typedef long unsigned int XID; typedef XID GLXPbuffer; #endif -#include <mbgl/map/view.hpp> +#include <mbgl/mbgl.hpp> #include <mbgl/platform/gl.hpp> #include <memory> @@ -34,11 +34,10 @@ public: void resize(uint16_t width, uint16_t height, float pixelRatio); std::unique_ptr<uint32_t[]> readPixels(); - void notify(); - void notifyMapChange(MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()); - void activate(); - void deactivate(); - void swap(); + void activate() override; + void deactivate() override; + void notify() override; + void invalidate() override; private: void clearBuffers(); diff --git a/ios/app/mapboxgl-app.gyp b/ios/app/mapboxgl-app.gyp index 7287932fc5..21af226621 100644 --- a/ios/app/mapboxgl-app.gyp +++ b/ios/app/mapboxgl-app.gyp @@ -33,6 +33,7 @@ 'xcode_settings': { 'SDKROOT': 'iphoneos', 'SUPPORTED_PLATFORMS': 'iphonesimulator iphoneos', + 'IPHONEOS_DEPLOYMENT_TARGET': '7.0', 'INFOPLIST_FILE': 'app-info.plist', 'TARGETED_DEVICE_FAMILY': '1,2', 'COMBINE_HIDPI_IMAGES': 'NO', # don't merge @2x.png images into .tiff files diff --git a/linux/mapboxgl-app.gyp b/linux/mapboxgl-app.gyp index afcc3a83a3..e7fc27da10 100644 --- a/linux/mapboxgl-app.gyp +++ b/linux/mapboxgl-app.gyp @@ -40,8 +40,12 @@ ['OS == "mac"', { 'libraries': [ '<@(libraries)' ], 'xcode_settings': { + 'SDKROOT': 'macosx', + 'SUPPORTED_PLATFORMS':'macosx', 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ], 'OTHER_LDFLAGS': [ '<@(ldflags)' ], + 'SDKROOT': 'macosx', + 'MACOSX_DEPLOYMENT_TARGET': '10.9', } }, { 'cflags_cc': [ '<@(cflags_cc)' ], diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 6d23a51ffb..2d0da355b2 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -297,16 +297,13 @@ void GLFWView::notify() { glfwPostEmptyEvent(); } -void GLFWView::swap() { +void GLFWView::invalidate() { + assert(map); + map->render(); glfwSwapBuffers(window); - map->swapped(); fps(); } -void GLFWView::notifyMapChange(mbgl::MapChange /*change*/, std::chrono::steady_clock::duration /*delay*/) { - // no-op -} - void GLFWView::fps() { static int frames = 0; static double timeElapsed = 0; diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index 975e7f58f7..7509c48eec 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -264,10 +264,6 @@ void HeadlessView::notify() { // no-op } -void HeadlessView::notifyMapChange(mbgl::MapChange /*change*/, std::chrono::steady_clock::duration /*delay*/) { - // no-op -} - void HeadlessView::activate() { #if MBGL_USE_CGL CGLError error = CGLSetCurrentContext(glContext); @@ -298,6 +294,9 @@ void HeadlessView::deactivate() { #endif } -void HeadlessView::swap() {} +void HeadlessView::invalidate() { + assert(map); + map->render(); +} } diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 1ab1afcbba..3629430263 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -204,7 +204,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // _glView = [[GLKView alloc] initWithFrame:self.bounds context:_context]; _glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _glView.enableSetNeedsDisplay = NO; + _glView.enableSetNeedsDisplay = YES; _glView.drawableStencilFormat = GLKViewDrawableStencilFormat8; _glView.drawableDepthFormat = GLKViewDrawableDepthFormat16; if ([UIScreen instancesRespondToSelector:@selector(nativeScale)]) { @@ -214,6 +214,8 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; [_glView bindDrawable]; [self addSubview:_glView]; + _glView.contentMode = UIViewContentModeCenter; + [self setBackgroundColor:[UIColor whiteColor]]; // load extensions // @@ -492,16 +494,18 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; [super updateConstraints]; } +// This is the delegate of the GLKView object's display call. - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { mbglView->resize(rect.size.width, rect.size.height, view.contentScaleFactor, view.drawableWidth, view.drawableHeight); + mbglMap->renderSync(); } +// This gets called when the view dimension changes, e.g. because the device is being rotated. - (void)layoutSubviews { - mbglMap->update(); - [super layoutSubviews]; + mbglMap->triggerUpdate(); } #pragma mark - Life Cycle - @@ -1604,13 +1608,10 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; return resourceBundlePath; } -- (void)swap +- (void)invalidate { - if (mbglMap->needsSwap()) - { - [self.glView display]; - mbglMap->swapped(); - } + // This is run in the main/UI thread. + [self.glView setNeedsDisplay]; } class MBGLView : public mbgl::View @@ -1620,12 +1621,12 @@ class MBGLView : public mbgl::View virtual ~MBGLView() {} - void notify() + void notify() override { // no-op } - void notifyMapChange(mbgl::MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()) + void notifyMapChange(mbgl::MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()) override { if (delay != std::chrono::steady_clock::duration::zero()) { @@ -1647,12 +1648,12 @@ class MBGLView : public mbgl::View } } - void activate() + void activate() override { [EAGLContext setCurrentContext:nativeView.context]; } - void deactivate() + void deactivate() override { [EAGLContext setCurrentContext:nil]; } @@ -1661,9 +1662,9 @@ class MBGLView : public mbgl::View View::resize(width, height, ratio, fbWidth, fbHeight); } - void swap() + void invalidate() override { - [nativeView performSelectorOnMainThread:@selector(swap) + [nativeView performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:NO]; } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 0cd7d3621e..29521f9499 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -73,10 +73,6 @@ Map::Map(View& view_, FileSource& fileSource_) painter(util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas)) { view.initialize(this); - // Make sure that we're doing an initial drawing in all cases. - isClean.clear(); - isRendered.clear(); - isSwapped.test_and_set(); } Map::~Map() { @@ -124,28 +120,32 @@ void Map::start(bool startPaused) { // Closes all open handles on the loop. This means that the loop will automatically terminate. asyncRender.reset(); + asyncUpdate.reset(); asyncTerminate.reset(); }); - asyncRender = util::make_unique<uv::async>(env->loop, [this]() { + asyncUpdate = util::make_unique<uv::async>(env->loop, [this] { assert(std::this_thread::get_id() == mapThread); if (state.hasSize()) { - if (isRendered.test_and_set() == false) { - prepare(); - if (isClean.test_and_set() == false) { - render(); - isSwapped.clear(); - view.swap(); - } else { - // We set the rendered flag in the test above, so we have to reset it - // now that we're not actually rendering because the map is clean. - isRendered.clear(); - } - } + prepare(); } }); + asyncRender = util::make_unique<uv::async>(env->loop, [this] { + // Must be called in Map thread. + assert(std::this_thread::get_id() == mapThread); + + render(); + + // Finally, notify all listeners that we have finished rendering this frame. + { + std::lock_guard<std::mutex> lk(mutexRendered); + rendered = true; + } + condRendered.notify_all(); + }); + // Do we need to pause first? if (startPaused) { pause(); @@ -208,7 +208,7 @@ void Map::pause(bool waitForPause) { mutexRun.unlock(); uv_stop(env->loop); - rerender(); // Needed to ensure uv_stop is seen and uv_run exits, otherwise we deadlock on wait_for_pause + triggerUpdate(); // Needed to ensure uv_stop is seen and uv_run exits, otherwise we deadlock on wait_for_pause if (waitForPause) { std::unique_lock<std::mutex> lockPause (mutexPause); @@ -280,6 +280,30 @@ void Map::run() { view.deactivate(); } +void Map::renderSync() { + // Must be called in UI thread. + assert(std::this_thread::get_id() == mainThread); + + triggerRender(); + + std::unique_lock<std::mutex> lock(mutexRendered); + condRendered.wait(lock, [this] { return rendered; }); + rendered = false; +} + +void Map::triggerUpdate() { + if (mode == Mode::Static) { + prepare(); + } else if (asyncUpdate) { + asyncUpdate->send(); + } +} + +void Map::triggerRender() { + assert(asyncRender); + asyncRender->send(); +} + void Map::checkForPause() { std::unique_lock<std::mutex> lockRun (mutexRun); while (pausing) { @@ -300,32 +324,6 @@ void Map::checkForPause() { mutexPause.unlock(); } -void Map::rerender() { - if (mode == Mode::Static) { - prepare(); - } else if (mode == Mode::Continuous) { - // We only send render events if we want to continuously update the map - // (== async rendering). - if (asyncRender) { - asyncRender->send(); - } - } -} - -void Map::update() { - isClean.clear(); - rerender(); -} - -bool Map::needsSwap() { - return isSwapped.test_and_set() == false; -} - -void Map::swapped() { - isRendered.clear(); - rerender(); -} - void Map::terminate() { assert(painter); painter->terminate(); @@ -350,7 +348,6 @@ void Map::setStyleURL(const std::string &url) { } } - void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) { // TODO: Make threadsafe. styleJSON.swap(newStyleJSON); @@ -367,7 +364,7 @@ void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) { const std::string glyphURL = util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken()); glyphStore->setURL(glyphURL); - update(); + triggerUpdate(); } std::string Map::getStyleJSON() const { @@ -393,7 +390,7 @@ void Map::resize(uint16_t width, uint16_t height, float ratio) { void Map::resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight) { if (transform.resize(width, height, ratio, fbWidth, fbHeight)) { - update(); + triggerUpdate(); } } @@ -402,7 +399,7 @@ void Map::resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, void Map::cancelTransitions() { transform.cancelTransitions(); - update(); + triggerUpdate(); } @@ -410,12 +407,12 @@ void Map::cancelTransitions() { void Map::moveBy(double dx, double dy, std::chrono::steady_clock::duration duration) { transform.moveBy(dx, dy, duration); - update(); + triggerUpdate(); } void Map::setLatLng(LatLng latLng, std::chrono::steady_clock::duration duration) { transform.setLatLng(latLng, duration); - update(); + triggerUpdate(); } LatLng Map::getLatLng() const { @@ -424,19 +421,19 @@ LatLng Map::getLatLng() const { void Map::startPanning() { transform.startPanning(); - update(); + triggerUpdate(); } void Map::stopPanning() { transform.stopPanning(); - update(); + triggerUpdate(); } void Map::resetPosition() { transform.setAngle(0); transform.setLatLng(LatLng(0, 0)); transform.setZoom(0); - update(); + triggerUpdate(); } @@ -444,12 +441,12 @@ void Map::resetPosition() { void Map::scaleBy(double ds, double cx, double cy, std::chrono::steady_clock::duration duration) { transform.scaleBy(ds, cx, cy, duration); - update(); + triggerUpdate(); } void Map::setScale(double scale, double cx, double cy, std::chrono::steady_clock::duration duration) { transform.setScale(scale, cx, cy, duration); - update(); + triggerUpdate(); } double Map::getScale() const { @@ -458,7 +455,7 @@ double Map::getScale() const { void Map::setZoom(double zoom, std::chrono::steady_clock::duration duration) { transform.setZoom(zoom, duration); - update(); + triggerUpdate(); } double Map::getZoom() const { @@ -467,7 +464,7 @@ double Map::getZoom() const { void Map::setLatLngZoom(LatLng latLng, double zoom, std::chrono::steady_clock::duration duration) { transform.setLatLngZoom(latLng, zoom, duration); - update(); + triggerUpdate(); } void Map::resetZoom() { @@ -476,12 +473,12 @@ void Map::resetZoom() { void Map::startScaling() { transform.startScaling(); - update(); + triggerUpdate(); } void Map::stopScaling() { transform.stopScaling(); - update(); + triggerUpdate(); } double Map::getMinZoom() const { @@ -497,17 +494,17 @@ double Map::getMaxZoom() const { void Map::rotateBy(double sx, double sy, double ex, double ey, std::chrono::steady_clock::duration duration) { transform.rotateBy(sx, sy, ex, ey, duration); - update(); + triggerUpdate(); } void Map::setBearing(double degrees, std::chrono::steady_clock::duration duration) { transform.setAngle(-degrees * M_PI / 180, duration); - update(); + triggerUpdate(); } void Map::setBearing(double degrees, double cx, double cy) { transform.setAngle(-degrees * M_PI / 180, cx, cy); - update(); + triggerUpdate(); } double Map::getBearing() const { @@ -516,17 +513,17 @@ double Map::getBearing() const { void Map::resetNorth() { transform.setAngle(0, std::chrono::milliseconds(500)); - update(); + triggerUpdate(); } void Map::startRotating() { transform.startRotating(); - update(); + triggerUpdate(); } void Map::stopRotating() { transform.stopRotating(); - update(); + triggerUpdate(); } #pragma mark - Access Token @@ -545,7 +542,7 @@ void Map::setDebug(bool value) { debug = value; assert(painter); painter->setDebug(debug); - update(); + triggerUpdate(); } void Map::toggleDebug() { @@ -562,7 +559,7 @@ void Map::addClass(const std::string& klass) { if (style) { style->cascadeClasses(classes); if (style->hasTransitions()) { - update(); + triggerUpdate(); } } } @@ -573,7 +570,7 @@ void Map::removeClass(const std::string& klass) { if (style) { style->cascadeClasses(classes); if (style->hasTransitions()) { - update(); + triggerUpdate(); } } } @@ -583,7 +580,7 @@ void Map::setClasses(const std::vector<std::string>& classes_) { if (style) { style->cascadeClasses(classes); if (style->hasTransitions()) { - update(); + triggerUpdate(); } } } @@ -637,6 +634,7 @@ void Map::updateSources() { } void Map::updateSources(const util::ptr<StyleLayerGroup> &group) { + assert(std::this_thread::get_id() == mapThread); if (!group) { return; } @@ -649,13 +647,19 @@ void Map::updateSources(const util::ptr<StyleLayerGroup> &group) { } void Map::updateTiles() { - for (const auto& source : activeSources) { + assert(std::this_thread::get_id() == mapThread); + for (const auto &source : activeSources) { source->source->update(*this, *env, getWorker(), style, *glyphAtlas, *glyphStore, - *spriteAtlas, getSprite(), *texturePool, [this]() { update(); }); + *spriteAtlas, getSprite(), *texturePool, [this]() { + assert(std::this_thread::get_id() == mapThread); + triggerUpdate(); + }); } } void Map::prepare() { + assert(std::this_thread::get_id() == mapThread); + if (!style) { style = std::make_shared<Style>(); @@ -692,14 +696,19 @@ void Map::prepare() { spriteAtlas->setSprite(getSprite()); updateTiles(); + + if (mode == Mode::Continuous) { + view.invalidate(); + } } void Map::render() { + assert(std::this_thread::get_id() == mapThread); assert(painter); painter->render(*style, activeSources, state, animationTime); // Schedule another rerender when we definitely need a next frame. if (transform.needsTransition() || style->hasTransitions()) { - update(); + triggerUpdate(); } } diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index ec3a1b8e00..447f25d4b7 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -60,8 +60,7 @@ void Source::load(Map &map, Environment &env) { source->info.parseTileJSONProperties(d); source->loaded = true; - map.update(); - + map.triggerUpdate(); }); } @@ -293,8 +292,9 @@ void Source::update(Map &map, util::ptr<Sprite> sprite, TexturePool &texturePool, std::function<void()> callback) { - if (!loaded || map.getTime() <= updated) + if (!loaded || map.getTime() <= updated) { return; + } bool changed = false; diff --git a/src/mbgl/map/view.cpp b/src/mbgl/map/view.cpp index 3927652ba6..21ba4daf36 100644 --- a/src/mbgl/map/view.cpp +++ b/src/mbgl/map/view.cpp @@ -3,9 +3,19 @@ namespace mbgl { +void View::initialize(Map *map_) { + assert(map_); + map = map_; +} + void View::resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight) { assert(map); map->resize(width, height, ratio, fbWidth, fbHeight); } +void View::notifyMapChange(MapChange, std::chrono::steady_clock::duration) { + // no-op +} + + } |