summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile19
-rw-r--r--android/cpp/jni.cpp28
-rw-r--r--android/cpp/native_map_view.cpp9
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java22
-rwxr-xr-xconfigure2
-rw-r--r--gyp/common.gypi1
-rw-r--r--include/mbgl/android/native_map_view.hpp5
-rw-r--r--include/mbgl/map/map.hpp38
-rw-r--r--include/mbgl/map/view.hpp16
-rw-r--r--include/mbgl/platform/default/glfw_view.hpp13
-rw-r--r--include/mbgl/platform/default/headless_view.hpp11
-rw-r--r--ios/app/mapboxgl-app.gyp1
-rw-r--r--linux/mapboxgl-app.gyp4
-rw-r--r--platform/default/glfw_view.cpp9
-rw-r--r--platform/default/headless_view.cpp9
-rw-r--r--platform/ios/MGLMapView.mm31
-rw-r--r--src/mbgl/map/map.cpp153
-rw-r--r--src/mbgl/map/source.cpp6
-rw-r--r--src/mbgl/map/view.cpp10
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
diff --git a/Makefile b/Makefile
index e1382a7e1f..33135ae96e 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
diff --git a/configure b/configure
index 378adcf292..f80c8b11c6 100755
--- a/configure
+++ b/configure
@@ -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
+}
+
+
}