diff --git a/.mason b/.mason index 1d5789dfa..d8597d944 160000 --- a/.mason +++ b/.mason @@ -1 +1 @@ -Subproject commit 1d5789dfadeffa5df8e58770e3326840d1e6d9c9 +Subproject commit d8597d944533dbb5e28d08dfdba22a82c93171b7 diff --git a/Makefile b/Makefile index 59bd1dfef..61f2a4c0c 100644 --- a/Makefile +++ b/Makefile @@ -57,8 +57,11 @@ endif #### All platforms targets ##################################################### -.PHONY: linux xlinux run-linux run-xlinux +.PHONY: linux run-linux run-valgrind-linux linux: ; $(RUN) Makefile/linuxapp +run-linux: linux ; (cd build/linux-x86_64/$(BUILDTYPE) && ./mapbox-gl) +run-valgrind-linux: linux + (cd build/linux-x86_64/$(BUILDTYPE) && valgrind --leak-check=full --suppressions=../../../scripts/valgrind.sup ./mapbox-gl) .PHONY: android android-lib # Builds a particular android architecture. diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index eee6bd8f6..6d7def861 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -409,14 +409,14 @@ void JNICALL nativeUpdate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().update(); + nativeMapView->getMap().update(mbgl::Update::Repaint); } -void JNICALL nativeOnInvalidate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean inProgress) { +void JNICALL nativeOnInvalidate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeOnInvalidate"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->onInvalidate(inProgress); + nativeMapView->onInvalidate(); } void JNICALL nativeViewResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height) { @@ -1440,7 +1440,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { {"nativePause", "(J)V", reinterpret_cast(&nativePause)}, {"nativeResume", "(J)V", reinterpret_cast(&nativeResume)}, {"nativeUpdate", "(J)V", reinterpret_cast(&nativeUpdate)}, - {"nativeOnInvalidate", "(JZ)V", reinterpret_cast(&nativeOnInvalidate)}, + {"nativeOnInvalidate", "(J)V", reinterpret_cast(&nativeOnInvalidate)}, {"nativeViewResize", "(JII)V", reinterpret_cast(static_cast(&nativeViewResize))}, diff --git a/android/cpp/native_map_view.cpp b/android/cpp/native_map_view.cpp index 351833a07..d0581212d 100644 --- a/android/cpp/native_map_view.cpp +++ b/android/cpp/native_map_view.cpp @@ -761,7 +761,7 @@ void NativeMapView::updateFps() { env = nullptr; } -void NativeMapView::onInvalidate(bool inProgress) { +void NativeMapView::onInvalidate() { mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::onInvalidate()"); const bool dirty = !clean.test_and_set(); @@ -776,10 +776,8 @@ void NativeMapView::onInvalidate(bool inProgress) { map.setSourceTileCacheSize(cacheSize); - const bool needsRerender = map.renderSync(); - if (!inProgress) { - map.nudgeTransitions(needsRerender); - } + map.renderSync(); + map.nudgeTransitions(); } } @@ -792,6 +790,7 @@ void NativeMapView::resizeView(int w, int h) { void NativeMapView::resizeFramebuffer(int w, int h) { fbWidth = w; fbHeight = h; + map.update(mbgl::Update::Repaint); } } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java index 2fbc0ccb5..303ccd9da 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java @@ -1365,8 +1365,7 @@ public class MapView extends FrameLayout implements LocationListener { post(new Runnable() { @Override public void run() { - boolean inProgress = mRotateGestureDetector.isInProgress() || mScaleGestureDetector.isInProgress(); - mNativeMapView.invalidate(inProgress); + mNativeMapView.invalidate(); } }); } 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 cc65de52f..774c20a05 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 @@ -96,8 +96,8 @@ class NativeMapView { nativeUpdate(mNativeMapViewPtr); } - public void invalidate(boolean inProgress) { - nativeOnInvalidate(mNativeMapViewPtr, inProgress); + public void invalidate() { + nativeOnInvalidate(mNativeMapViewPtr); } public void resizeView(int width, int height) { @@ -463,7 +463,7 @@ class NativeMapView { private native void nativeUpdate(long nativeMapViewPtr); - private native void nativeOnInvalidate(long nativeMapViewPtr, boolean inProgress); + private native void nativeOnInvalidate(long nativeMapViewPtr); private native void nativeViewResize(long nativeMapViewPtr, int width, int height); diff --git a/include/mbgl/android/native_map_view.hpp b/include/mbgl/android/native_map_view.hpp index 1ea67a0da..3ae3d6ed9 100644 --- a/include/mbgl/android/native_map_view.hpp +++ b/include/mbgl/android/native_map_view.hpp @@ -49,7 +49,7 @@ public: void enableFps(bool enable); void updateFps(); - void onInvalidate(bool inProgress); + void onInvalidate(); void resizeView(int width, int height); void resizeFramebuffer(int width, int height); diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 6e24d177a..ae43dc8a8 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -66,14 +66,14 @@ public: using StillImageCallback = std::function)>; void renderStill(StillImageCallback callback); - // Triggers a synchronous or asynchronous render. - bool renderSync(); + // Triggers a synchronous render. + void renderSync(); - // Nudges transitions one step, possibly notifying of the need for a rerender. - void nudgeTransitions(bool forceRerender); + // Nudges transitions one step, possibly notifying of the need for a rerender, if any. + void nudgeTransitions(); // Notifies the Map thread that the state has changed and an update might be necessary. - void update(Update update = Update::Nothing); + void update(Update update); // Styling void addClass(const std::string&); diff --git a/include/mbgl/map/update.hpp b/include/mbgl/map/update.hpp index d2d6133bc..d5978d80b 100644 --- a/include/mbgl/map/update.hpp +++ b/include/mbgl/map/update.hpp @@ -14,6 +14,7 @@ enum class Update : UpdateType { Classes = 1 << 3, Zoom = 1 << 4, RenderStill = 1 << 5, + Repaint = 1 << 6, }; } diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index fb08b9234..078c26fee 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -288,7 +288,7 @@ void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { view->fbWidth = width; view->fbHeight = height; - view->map->update(); + view->map->update(mbgl::Update::Repaint); } void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) { @@ -336,11 +336,8 @@ void GLFWView::run() { glfwWaitEvents(); const bool dirty = !clean.test_and_set(); if (dirty) { - const bool needsRerender = map->renderSync(); - GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - if (!view->tracking || !view->rotating) { - map->nudgeTransitions(needsRerender); - } + map->renderSync(); + map->nudgeTransitions(); } } } diff --git a/platform/default/png_reader.cpp b/platform/default/png_reader.cpp index 42b694609..ede7e52be 100644 --- a/platform/default/png_reader.cpp +++ b/platform/default/png_reader.cpp @@ -160,8 +160,6 @@ void PngReader::read(unsigned x0, unsigned y0, unsigned w, unsigned h, char * #ifdef PNG_ALPHA_PREMULTIPLIED png_set_alpha_mode(png_ptr, PNG_ALPHA_PREMULTIPLIED, PNG_GAMMA_LINEAR); -#else - // TODO: Manually premultiply the image data. #endif if (x0 == 0 && y0 == 0 && w >= width_ && h >= height_) @@ -180,6 +178,19 @@ void PngReader::read(unsigned x0, unsigned y0, unsigned w, unsigned h, char * for (unsigned row = 0; row < height_; ++row) rows[row] = (png_bytep)image + row * width_ * 4 ; png_read_image(png_ptr, rows.get()); + +#ifndef PNG_ALPHA_PREMULTIPLIED + // Manually premultiply the image if libpng didn't do it for us. + for (unsigned row = 0; row < height_; ++row) { + for (unsigned x = 0; x < width_; x++) { + png_byte* ptr = &(rows[row][x * 4]); + const float a = ptr[3] / 255.0f; + ptr[0] *= a; + ptr[1] *= a; + ptr[2] *= a; + } + } +#endif } else { @@ -193,6 +204,7 @@ void PngReader::read(unsigned x0, unsigned y0, unsigned w, unsigned h, char * png_read_row(png_ptr,row.get(),0); if (i >= y0 && i < (y0 + h)) { + // TODO: premultiply this std::copy(&row[x0 * 4], &row[x0 * 4] + w * 4, image + i * width_* 4); } } diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index e95305d0c..81338f288 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -710,17 +710,11 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) _mbglMap->setSourceTileCacheSize(cacheSize); - bool needsRerender = _mbglMap->renderSync(); + _mbglMap->renderSync(); [self updateUserLocationAnnotationView]; - // don't nudge transitions if in the midst of a gesture. - if (self.pan.state == UIGestureRecognizerStateChanged || - self.pinch.state == UIGestureRecognizerStateChanged || - self.rotate.state == UIGestureRecognizerStateChanged || - self.quickZoom.state == UIGestureRecognizerStateChanged) return; - - _mbglMap->nudgeTransitions(needsRerender); + _mbglMap->nudgeTransitions(); } } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index f357c05e8..fadd4c48d 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -48,36 +48,34 @@ void Map::renderStill(StillImageCallback callback) { FrameData{ view.getFramebufferSize() }, callback); } -bool Map::renderSync() { +void Map::renderSync() { if (renderState == RenderState::never) { view.notifyMapChange(MapChangeWillStartRenderingMap); } view.notifyMapChange(MapChangeWillStartRenderingFrame); - MapContext::RenderResult result = context->invokeSync( - &MapContext::renderSync, transform->getState(), FrameData{ view.getFramebufferSize() }); + const bool fullyLoaded = context->invokeSync( + &MapContext::renderSync, transform->getState(), FrameData { view.getFramebufferSize() }); - view.notifyMapChange(result.fullyLoaded ? + view.notifyMapChange(fullyLoaded ? MapChangeDidFinishRenderingFrameFullyRendered : MapChangeDidFinishRenderingFrame); - if (!result.fullyLoaded) { + if (!fullyLoaded) { renderState = RenderState::partial; } else if (renderState != RenderState::fully) { renderState = RenderState::fully; view.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered); } - - return result.needsRerender; } -void Map::nudgeTransitions(bool forceRerender) { - if (transform->needsTransition()) { - update(Update(transform->updateTransitions(Clock::now()))); - } else if (forceRerender) { - update(); +void Map::nudgeTransitions() { + UpdateType update_ = transform->updateTransitions(Clock::now()); + if (data->getNeedsRepaint()) { + update_ |= static_cast(Update::Repaint); } + update(Update(update_)); } void Map::update(Update update_) { @@ -110,24 +108,24 @@ std::string Map::getStyleJSON() const { void Map::cancelTransitions() { transform->cancelTransitions(); - update(); + update(Update::Repaint); } void Map::setGestureInProgress(bool inProgress) { transform->setGestureInProgress(inProgress); - update(); + update(Update::Repaint); } #pragma mark - Position void Map::moveBy(double dx, double dy, const Duration& duration) { transform->moveBy(dx, dy, duration); - update(); + update(Update::Repaint); } void Map::setLatLng(LatLng latLng, const Duration& duration) { transform->setLatLng(latLng, duration); - update(); + update(Update::Repaint); } LatLng Map::getLatLng() const { @@ -249,17 +247,17 @@ uint16_t Map::getHeight() const { void Map::rotateBy(double sx, double sy, double ex, double ey, const Duration& duration) { transform->rotateBy(sx, sy, ex, ey, duration); - update(); + update(Update::Repaint); } void Map::setBearing(double degrees, const Duration& duration) { transform->setAngle(-degrees * M_PI / 180, duration); - update(); + update(Update::Repaint); } void Map::setBearing(double degrees, double cx, double cy) { transform->setAngle(-degrees * M_PI / 180, cx, cy); - update(); + update(Update::Repaint); } double Map::getBearing() const { @@ -268,7 +266,7 @@ double Map::getBearing() const { void Map::resetNorth() { transform->setAngle(0, std::chrono::milliseconds(500)); - update(); + update(Update::Repaint); } @@ -365,12 +363,12 @@ void Map::removeSprite(const std::string& name) { void Map::setDebug(bool value) { data->setDebug(value); - update(); + update(Update::Repaint); } void Map::toggleDebug() { data->toggleDebug(); - update(); + update(Update::Repaint); } bool Map::getDebug() const { @@ -379,12 +377,12 @@ bool Map::getDebug() const { void Map::setCollisionDebug(bool value) { data->setCollisionDebug(value); - update(); + update(Update::Repaint); } void Map::toggleCollisionDebug() { data->toggleCollisionDebug(); - update(); + update(Update::Repaint); } bool Map::getCollisionDebug() const { diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 56bca24af..33e4e6d18 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -35,7 +35,8 @@ MapContext::MapContext(View& view_, FileSource& fileSource, MapData& data_) data(data_), updated(static_cast(Update::Nothing)), asyncUpdate(std::make_unique(util::RunLoop::getLoop(), [this] { update(); })), - texturePool(std::make_unique()) { + texturePool(std::make_unique()), + viewInvalidated(false) { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); util::ThreadContext::setFileSource(&fileSource); @@ -255,6 +256,9 @@ void MapContext::update() { if (!style) { updated = static_cast(Update::Nothing); + } + + if (updated == static_cast(Update::Nothing)) { return; } @@ -272,15 +276,15 @@ void MapContext::update() { style->update(transformState, *texturePool); if (data.mode == MapMode::Continuous) { - view.invalidate(); - } else if (callback && style->isLoaded()) { + invalidateView(); + } else if (callback && isLoaded()) { renderSync(transformState, frameData); } updated = static_cast(Update::Nothing); } -void MapContext::renderStill(const TransformState& state, const FrameData& frame, StillImageCallback fn) { +void MapContext::renderStill(const TransformState& state, const FrameData& frame, Map::StillImageCallback fn) { if (!fn) { Log::Error(Event::General, "StillImageCallback not set"); return; @@ -314,12 +318,12 @@ void MapContext::renderStill(const TransformState& state, const FrameData& frame asyncUpdate->send(); } -MapContext::RenderResult MapContext::renderSync(const TransformState& state, const FrameData& frame) { +bool MapContext::renderSync(const TransformState& state, const FrameData& frame) { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); // Style was not loaded yet. if (!style) { - return { false, false }; + return false; } transformState = state; @@ -342,10 +346,13 @@ MapContext::RenderResult MapContext::renderSync(const TransformState& state, con view.swap(); - return RenderResult { - style->isLoaded(), - style->hasTransitions() || painter->needsAnimation() - }; + viewInvalidated = false; + + if (style->hasTransitions() || painter->needsAnimation()) { + data.setNeedsRepaint(true); + } + + return isLoaded(); } bool MapContext::isLoaded() const { @@ -370,7 +377,7 @@ void MapContext::setSourceTileCacheSize(size_t size) { for (const auto &source : style->sources) { source->setCacheSize(sourceCacheSize); } - view.invalidate(); + invalidateView(); } } @@ -380,7 +387,7 @@ void MapContext::onLowMemory() { for (const auto &source : style->sources) { source->onLowMemory(); } - view.invalidate(); + invalidateView(); } void MapContext::setSprite(const std::string& name, std::shared_ptr sprite) { @@ -396,6 +403,8 @@ void MapContext::setSprite(const std::string& name, std::shared_ptr(Update::Repaint); asyncUpdate->send(); } @@ -408,4 +417,11 @@ void MapContext::onResourceLoadingFailed(std::exception_ptr error) { } } +void MapContext::invalidateView() { + if (!viewInvalidated) { + viewInvalidated = true; + view.invalidate(); + } +} + } diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 8c8c90ff8..215f5d377 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -37,18 +38,13 @@ public: MapContext(View&, FileSource&, MapData&); ~MapContext(); - struct RenderResult { - bool fullyLoaded; - bool needsRerender; - }; - void pause(); - using StillImageCallback = std::function)>; - void triggerUpdate(const TransformState&, Update = Update::Nothing); - void renderStill(const TransformState&, const FrameData&, StillImageCallback callback); - RenderResult renderSync(const TransformState&, const FrameData&); + void renderStill(const TransformState&, const FrameData&, Map::StillImageCallback callback); + + // Triggers a synchronous render. Returns true if style has been fully loaded. + bool renderSync(const TransformState&, const FrameData&); void setStyleURL(const std::string&); void setStyleJSON(const std::string& json, const std::string& base); @@ -78,6 +74,8 @@ private: // Loads the actual JSON object an creates a new Style object. void loadStyleJSON(const std::string& json, const std::string& base); + void invalidateView(); + View& view; MapData& data; @@ -95,10 +93,11 @@ private: Request* styleRequest = nullptr; - StillImageCallback callback; + Map::StillImageCallback callback; size_t sourceCacheSize; TransformState transformState; FrameData frameData; + bool viewInvalidated; }; } diff --git a/src/mbgl/map/map_data.hpp b/src/mbgl/map/map_data.hpp index aadc8dcd6..9eac6162e 100644 --- a/src/mbgl/map/map_data.hpp +++ b/src/mbgl/map/map_data.hpp @@ -101,6 +101,14 @@ public: defaultTransitionDelay = delay; } + inline bool getNeedsRepaint() const { + return needsRepaint; + } + + inline void setNeedsRepaint(const bool needsRepaint_) { + needsRepaint = needsRepaint_; + } + util::exclusive getAnnotationManager() { return util::exclusive( &annotationManager, @@ -124,6 +132,7 @@ private: std::atomic defaultFadeDuration; std::atomic defaultTransitionDuration; std::atomic defaultTransitionDelay; + std::atomic needsRepaint; // TODO: make private public: diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 08cca3db2..29ca54d78 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -377,10 +377,6 @@ void Transform::startTransition(std::function frame, transitionFinishFn = finish; } -bool Transform::needsTransition() const { - return !!transitionFrameFn; -} - UpdateType Transform::updateTransitions(const TimePoint& now) { return static_cast(transitionFrameFn ? transitionFrameFn(now) : Update::Nothing); } diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index badb811af..f4a78bbcb 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -42,7 +42,6 @@ public: double getAngle() const; // Transitions - bool needsTransition() const; UpdateType updateTransitions(const TimePoint& now); void cancelTransitions();