Merge pull request #838 from mapbox/838-fix-rotate-flicker

black flicker on iOS device rotation
This commit is contained in:
Konstantin Käfer
2015-03-12 12:55:59 +01:00
20 changed files with 183 additions and 207 deletions

3
.gitignore vendored
View File

@@ -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

View File

@@ -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 ####################################################

View File

@@ -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))},

View File

@@ -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");

View File

@@ -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);

2
configure vendored
View File

@@ -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

View File

@@ -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',

View File

@@ -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();

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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)' ],

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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];
}

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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
}
}