From ebd2985f785e19f3d4976f2d803ac017b755d0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 20 Mar 2015 18:33:29 +0100 Subject: [PATCH] make style updates a little more threadsafe - we're now always loading and parsing styles in the map thread - adds an atomic enum that stores the actual updates we need to perform - adds a MapData object that mutexes access to variables used from both threads --- include/mbgl/map/map.hpp | 25 ++++++-- src/mbgl/map/map.cpp | 130 ++++++++++++++++++++++++-------------- src/mbgl/map/map_data.hpp | 36 +++++++++++ 3 files changed, 137 insertions(+), 54 deletions(-) create mode 100644 src/mbgl/map/map_data.hpp diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 06ae39d87..9ea5c72f6 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -39,6 +39,7 @@ class LineAtlas; class Environment; class EnvironmentScope; class AnnotationManager; +class MapData; class Map : private util::noncopyable { friend class View; @@ -75,7 +76,12 @@ public: void render(); // Notifies the Map thread that the state has changed and an update might be necessary. - void triggerUpdate(); + using UpdateType = uint32_t; + enum class Update : UpdateType { + Nothing = 0, + StyleInfo = 1 << 0, + }; + void triggerUpdate(Update = Update::Nothing); // Triggers a render. Can be called from any thread. void triggerRender(); @@ -92,8 +98,8 @@ public: void setDefaultTransitionDuration(std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero()); std::chrono::steady_clock::duration getDefaultTransitionDuration(); - void setStyleURL(const std::string &url); - void setStyleJSON(std::string newStyleJSON, const std::string &base = ""); + void setStyleURL(const std::string& url); + void setStyleJSON(const std::string& json, const std::string& base = ""); std::string getStyleJSON() const; // Transition @@ -178,6 +184,13 @@ private: void updateSources(); void updateSources(const util::ptr &group); + // Triggered by triggerUpdate(); + void update(); + + // Loads the style set in the data object. Called by Update::StyleInfo + void reloadStyle(); + void loadStyleJSON(const std::string& json, const std::string& base); + // Prepares a map render by updating the tiles we need for the current view, as well as updating // the stylesheet. void prepare(); @@ -234,8 +247,8 @@ private: std::unique_ptr painter; util::ptr annotationManager; - std::string styleURL; - std::string styleJSON = ""; + const std::unique_ptr data; + std::vector classes; std::string accessToken; @@ -245,6 +258,8 @@ private: std::chrono::steady_clock::time_point animationTime = std::chrono::steady_clock::time_point::min(); std::set> activeSources; + + std::atomic updated; }; } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index ae1cfd20f..57000e040 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,8 @@ Map::Map(View& view_, FileSource& fileSource_) lineAtlas(util::make_unique(512, 512)), texturePool(std::make_shared()), painter(util::make_unique(*spriteAtlas, *glyphAtlas, *lineAtlas)), - annotationManager(util::make_unique()) + annotationManager(util::make_unique()), + data(util::make_unique()) { view.initialize(this); } @@ -138,11 +140,7 @@ void Map::start(bool startPaused) { }); asyncUpdate = util::make_unique(env->loop, [this] { - assert(Environment::currentlyOn(ThreadType::Map)); - - if (state.hasSize()) { - prepare(); - } + update(); }); asyncRender = util::make_unique(env->loop, [this] { @@ -175,6 +173,8 @@ void Map::start(bool startPaused) { isStopped = true; view.notify(); }); + + triggerUpdate(); } void Map::stop(std::function callback) { @@ -252,7 +252,9 @@ void Map::run() { checkForPause(); } - if (mode == Mode::Static && !style && styleURL.empty()) { + auto styleInfo = data->getStyleInfo(); + + if (mode == Mode::Static && !style && (styleInfo.url.empty() && styleInfo.json.empty())) { throw util::Exception("Style is not set"); } @@ -297,7 +299,9 @@ void Map::renderSync() { rendered = false; } -void Map::triggerUpdate() { +void Map::triggerUpdate(const Update u) { + updated |= static_cast(u); + if (mode == Mode::Static) { prepare(); } else if (asyncUpdate) { @@ -345,36 +349,27 @@ void Map::setup() { } void Map::setStyleURL(const std::string &url) { - // TODO: Make threadsafe. + assert(Environment::currentlyOn(ThreadType::Main)); - styleURL = url; - if (mode == Mode::Continuous) { - stop(); - start(); + const size_t pos = url.rfind('/'); + std::string base = ""; + if (pos != std::string::npos) { + base = url.substr(0, pos + 1); } + + data->setStyleInfo({ url, base, "" }); + triggerUpdate(Update::StyleInfo); } -void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) { - // TODO: Make threadsafe. - styleJSON.swap(newStyleJSON); - sprite.reset(); - if (!style) { - style = std::make_shared