summaryrefslogtreecommitdiff
path: root/src/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl')
-rw-r--r--src/mbgl/geometry/buffer.hpp3
-rw-r--r--src/mbgl/geometry/line_atlas.cpp6
-rw-r--r--src/mbgl/geometry/sprite_atlas.cpp4
-rw-r--r--src/mbgl/geometry/vao.cpp3
-rw-r--r--src/mbgl/map/annotation.cpp4
-rw-r--r--src/mbgl/map/environment.cpp55
-rw-r--r--src/mbgl/map/environment.hpp42
-rw-r--r--src/mbgl/map/map.cpp237
-rw-r--r--src/mbgl/map/map_data.cpp44
-rw-r--r--src/mbgl/map/map_data.hpp102
-rw-r--r--src/mbgl/map/tile_data.cpp2
-rw-r--r--src/mbgl/util/texture_pool.cpp15
12 files changed, 395 insertions, 122 deletions
diff --git a/src/mbgl/geometry/buffer.hpp b/src/mbgl/geometry/buffer.hpp
index 3649574bbf..4198425ecf 100644
--- a/src/mbgl/geometry/buffer.hpp
+++ b/src/mbgl/geometry/buffer.hpp
@@ -3,6 +3,7 @@
#include <mbgl/platform/gl.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/map/environment.hpp>
#include <cstdlib>
#include <cassert>
@@ -21,7 +22,7 @@ public:
~Buffer() {
cleanup();
if (buffer != 0) {
- MBGL_CHECK_ERROR(glDeleteBuffers(1, &buffer));
+ Environment::Get().abandonBuffer(buffer);
buffer = 0;
}
}
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp
index 8be1a8d53c..507cc7b087 100644
--- a/src/mbgl/geometry/line_atlas.cpp
+++ b/src/mbgl/geometry/line_atlas.cpp
@@ -1,3 +1,4 @@
+#include <mbgl/map/environment.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/platform/gl.hpp>
#include <mbgl/platform/log.hpp>
@@ -18,9 +19,10 @@ LineAtlas::LineAtlas(uint16_t w, uint16_t h)
LineAtlas::~LineAtlas() {
std::lock_guard<std::recursive_mutex> lock(mtx);
- MBGL_CHECK_ERROR(glDeleteTextures(1, &texture));
- delete[] data;
+ Environment::Get().abandonTexture(texture);
texture = 0;
+
+ delete[] data;
}
LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, bool round) {
diff --git a/src/mbgl/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp
index dce772f2e4..bf31c6e38e 100644
--- a/src/mbgl/geometry/sprite_atlas.cpp
+++ b/src/mbgl/geometry/sprite_atlas.cpp
@@ -1,3 +1,4 @@
+#include <mbgl/map/environment.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/platform/gl.hpp>
#include <mbgl/platform/log.hpp>
@@ -293,8 +294,7 @@ void SpriteAtlas::bind(bool linear) {
SpriteAtlas::~SpriteAtlas() {
std::lock_guard<std::recursive_mutex> lock(mtx);
-
- MBGL_CHECK_ERROR(glDeleteTextures(1, &texture));
+ Environment::Get().abandonTexture(texture);
texture = 0;
::operator delete(data), data = nullptr;
}
diff --git a/src/mbgl/geometry/vao.cpp b/src/mbgl/geometry/vao.cpp
index 00976b4d54..fef74396a9 100644
--- a/src/mbgl/geometry/vao.cpp
+++ b/src/mbgl/geometry/vao.cpp
@@ -1,6 +1,7 @@
#include <mbgl/geometry/vao.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/string.hpp>
+#include <mbgl/map/environment.hpp>
namespace mbgl {
@@ -11,7 +12,7 @@ VertexArrayObject::~VertexArrayObject() {
if (!gl::DeleteVertexArrays) return;
if (vao) {
- MBGL_CHECK_ERROR(gl::DeleteVertexArrays(1, &vao));
+ Environment::Get().abandonVAO(vao);
}
}
diff --git a/src/mbgl/map/annotation.cpp b/src/mbgl/map/annotation.cpp
index 0d6da5781e..83739ab46a 100644
--- a/src/mbgl/map/annotation.cpp
+++ b/src/mbgl/map/annotation.cpp
@@ -40,7 +40,9 @@ std::pair<std::vector<Tile::ID>, std::vector<uint32_t>> AnnotationManager::addPo
uint16_t extent = 4096;
- std::vector<uint32_t> annotationIDs(points.size());
+ std::vector<uint32_t> annotationIDs;
+ annotationIDs.reserve(points.size());
+
std::vector<Tile::ID> affectedTiles;
for (uint32_t i = 0; i < points.size(); ++i) {
diff --git a/src/mbgl/map/environment.cpp b/src/mbgl/map/environment.cpp
index 1aea5aa0c9..469790501c 100644
--- a/src/mbgl/map/environment.cpp
+++ b/src/mbgl/map/environment.cpp
@@ -1,5 +1,6 @@
#include <mbgl/map/environment.hpp>
#include <mbgl/storage/file_source.hpp>
+#include <mbgl/platform/gl.hpp>
#include <uv.h>
@@ -76,12 +77,12 @@ ThreadInfoStore threadInfoStore;
} // namespace
-Environment::Scope::Scope(Environment& env, ThreadType type, const std::string& name)
+EnvironmentScope::EnvironmentScope(Environment& env, ThreadType type, const std::string& name)
: id(std::this_thread::get_id()) {
threadInfoStore.registerThread(&env, type, name);
}
-Environment::Scope::~Scope() {
+EnvironmentScope::~EnvironmentScope() {
assert(id == std::this_thread::get_id());
threadInfoStore.unregisterThread();
}
@@ -90,6 +91,12 @@ Environment::Environment(FileSource& fs)
: id(makeEnvironmentID()), fileSource(fs), loop(uv_loop_new()) {
}
+Environment::~Environment() {
+ assert(abandonedVAOs.empty());
+ assert(abandonedTextures.empty());
+ assert(abandonedBuffers.empty());
+}
+
Environment& Environment::Get() {
Environment* env = threadInfoStore.getThreadInfo().env;
assert(env);
@@ -129,6 +136,50 @@ void Environment::cancelRequest(Request* req) {
fileSource.cancel(req);
}
+// #############################################################################################
+
+#pragma mark - OpenGL cleanup
+
+void Environment::abandonVAO(uint32_t vao) {
+ assert(currentlyOn(ThreadType::Map));
+ abandonedVAOs.emplace_back(vao);
+}
+
+void Environment::abandonBuffer(uint32_t buffer) {
+ assert(currentlyOn(ThreadType::Map));
+ abandonedBuffers.emplace_back(buffer);
+}
+
+void Environment::abandonTexture(uint32_t texture) {
+ assert(currentlyOn(ThreadType::Map));
+ abandonedTextures.emplace_back(texture);
+}
+
+// Actually remove the objects we marked as abandoned with the above methods.
+void Environment::performCleanup() {
+ assert(currentlyOn(ThreadType::Map));
+
+ if (!abandonedVAOs.empty()) {
+ MBGL_CHECK_ERROR(gl::DeleteVertexArrays(static_cast<GLsizei>(abandonedVAOs.size()),
+ abandonedVAOs.data()));
+ abandonedVAOs.clear();
+ }
+
+ if (!abandonedTextures.empty()) {
+ MBGL_CHECK_ERROR(glDeleteTextures(static_cast<GLsizei>(abandonedTextures.size()),
+ abandonedTextures.data()));
+ abandonedTextures.clear();
+ }
+
+ if (!abandonedBuffers.empty()) {
+ MBGL_CHECK_ERROR(glDeleteBuffers(static_cast<GLsizei>(abandonedBuffers.size()),
+ abandonedBuffers.data()));
+ abandonedBuffers.clear();
+ }
+}
+
+// #############################################################################################
+
void Environment::terminate() {
fileSource.abort(*this);
}
diff --git a/src/mbgl/map/environment.hpp b/src/mbgl/map/environment.hpp
index b631abf13d..1cd33a5e6d 100644
--- a/src/mbgl/map/environment.hpp
+++ b/src/mbgl/map/environment.hpp
@@ -6,6 +6,7 @@
#include <thread>
#include <functional>
+#include <vector>
typedef struct uv_loop_s uv_loop_t;
@@ -25,16 +26,8 @@ enum class ThreadType : uint8_t {
class Environment final : private util::noncopyable {
public:
- class Scope final {
- public:
- Scope(Environment&, ThreadType, const std::string& name);
- ~Scope();
-
- private:
- std::thread::id id;
- };
-
Environment(FileSource&);
+ ~Environment();
static Environment& Get();
static bool inScope();
@@ -42,10 +35,27 @@ public:
static std::string threadName();
unsigned getID() const;
+
+ // #############################################################################################
+
+ // File request APIs
void requestAsync(const Resource&, std::function<void(const Response&)>);
Request* request(const Resource&, std::function<void(const Response&)>);
void cancelRequest(Request*);
+ // #############################################################################################
+
+ // Mark OpenGL objects for deletion
+ void abandonVAO(uint32_t vao);
+ void abandonBuffer(uint32_t buffer);
+ void abandonTexture(uint32_t texture);
+
+ // Actually remove the objects we marked as abandoned with the above methods.
+ // Only call this while the OpenGL context is exclusive to this thread.
+ void performCleanup();
+
+ // #############################################################################################
+
// Request to terminate the environment.
void terminate();
@@ -53,10 +63,24 @@ private:
unsigned id;
FileSource& fileSource;
+ // Stores OpenGL objects that we marked for deletion
+ std::vector<uint32_t> abandonedVAOs;
+ std::vector<uint32_t> abandonedBuffers;
+ std::vector<uint32_t> abandonedTextures;
+
public:
uv_loop_t* const loop;
};
+class EnvironmentScope final {
+public:
+ EnvironmentScope(Environment&, ThreadType, const std::string& name);
+ ~EnvironmentScope();
+
+private:
+ std::thread::id id;
+};
+
}
#endif
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 22e6cbcebb..bc53d0d0fa 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -1,6 +1,7 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/environment.hpp>
#include <mbgl/map/view.hpp>
+#include <mbgl/map/map_data.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/renderer/painter.hpp>
@@ -61,6 +62,7 @@ using namespace mbgl;
Map::Map(View& view_, FileSource& fileSource_)
: env(util::make_unique<Environment>(fileSource_)),
+ scope(util::make_unique<EnvironmentScope>(*env, ThreadType::Main, "Main")),
view(view_),
transform(view_),
fileSource(fileSource_),
@@ -70,7 +72,8 @@ Map::Map(View& view_, FileSource& fileSource_)
lineAtlas(util::make_unique<LineAtlas>(512, 512)),
texturePool(std::make_shared<TexturePool>()),
painter(util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas)),
- annotationManager(util::make_unique<AnnotationManager>())
+ annotationManager(util::make_unique<AnnotationManager>()),
+ data(util::make_unique<MapData>())
{
view.initialize(this);
}
@@ -80,15 +83,28 @@ Map::~Map() {
stop();
}
+ // Extend the scope to include both Main and Map thread types to ease cleanup.
+ scope.reset();
+ scope = util::make_unique<EnvironmentScope>(
+ *env, static_cast<ThreadType>(static_cast<uint8_t>(ThreadType::Main) |
+ static_cast<uint8_t>(ThreadType::Map)),
+ "MapandMain");
+
// Explicitly reset all pointers.
activeSources.clear();
sprite.reset();
glyphStore.reset();
style.reset();
- texturePool.reset();
workers.reset();
+ painter.reset();
+ annotationManager.reset();
+ lineAtlas.reset();
+ spriteAtlas.reset();
+ glyphAtlas.reset();
uv_run(env->loop, UV_RUN_DEFAULT);
+
+ env->performCleanup();
}
uv::worker &Map::getWorker() {
@@ -125,11 +141,7 @@ void Map::start(bool startPaused) {
});
asyncUpdate = util::make_unique<uv::async>(env->loop, [this] {
- assert(Environment::currentlyOn(ThreadType::Map));
-
- if (state.hasSize()) {
- prepare();
- }
+ update();
});
asyncRender = util::make_unique<uv::async>(env->loop, [this] {
@@ -162,6 +174,8 @@ void Map::start(bool startPaused) {
isStopped = true;
view.notify();
});
+
+ triggerUpdate();
}
void Map::stop(std::function<void ()> callback) {
@@ -233,13 +247,15 @@ void Map::run() {
threadName += "andMain";
}
- Environment::Scope scope(*env, threadType, threadName);
+ EnvironmentScope mapScope(*env, threadType, threadName);
if (mode == Mode::Continuous) {
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");
}
@@ -284,7 +300,9 @@ void Map::renderSync() {
rendered = false;
}
-void Map::triggerUpdate() {
+void Map::triggerUpdate(const Update u) {
+ updated |= static_cast<UpdateType>(u);
+
if (mode == Mode::Static) {
prepare();
} else if (asyncUpdate) {
@@ -332,36 +350,27 @@ void Map::setup() {
}
void Map::setStyleURL(const std::string &url) {
- // TODO: Make threadsafe.
-
- styleURL = url;
- if (mode == Mode::Continuous) {
- stop();
- start();
- }
-}
+ assert(Environment::currentlyOn(ThreadType::Main));
-void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) {
- // TODO: Make threadsafe.
- styleJSON.swap(newStyleJSON);
- sprite.reset();
- if (!style) {
- style = std::make_shared<Style>();
+ const size_t pos = url.rfind('/');
+ std::string base = "";
+ if (pos != std::string::npos) {
+ base = url.substr(0, pos + 1);
}
- style->base = base;
- style->loadJSON((const uint8_t *)styleJSON.c_str());
- style->cascadeClasses(classes);
- style->setDefaultTransitionDuration(defaultTransitionDuration);
+ data->setStyleInfo({ url, base, "" });
+ triggerUpdate(Update::StyleInfo);
+}
- const std::string glyphURL = util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken());
- glyphStore->setURL(glyphURL);
+void Map::setStyleJSON(const std::string& json, const std::string& base) {
+ assert(Environment::currentlyOn(ThreadType::Main));
- triggerUpdate();
+ data->setStyleInfo({ "", base, json });
+ triggerUpdate(Update::StyleInfo);
}
std::string Map::getStyleJSON() const {
- return styleJSON;
+ return data->getStyleInfo().json;
}
util::ptr<Sprite> Map::getSprite() {
@@ -522,11 +531,11 @@ void Map::stopRotating() {
#pragma mark - Access Token
void Map::setAccessToken(const std::string &token) {
- accessToken = token;
+ data->setAccessToken(token);
}
-const std::string &Map::getAccessToken() const {
- return accessToken;
+std::string Map::getAccessToken() const {
+ return data->getAccessToken();
}
#pragma mark - Annotations
@@ -583,69 +592,58 @@ void Map::updateAnnotationTiles(std::vector<Tile::ID>& ids) {
#pragma mark - Toggles
void Map::setDebug(bool value) {
- debug = value;
- assert(painter);
- painter->setDebug(debug);
- triggerUpdate();
+ data->setDebug(value);
+ triggerUpdate(Update::Debug);
}
void Map::toggleDebug() {
- setDebug(!debug);
+ data->toggleDebug();
+ triggerUpdate(Update::Debug);
}
bool Map::getDebug() const {
- return debug;
+ return data->getDebug();
+}
+
+std::chrono::steady_clock::time_point Map::getTime() const {
+ return data->getAnimationTime();
}
void Map::addClass(const std::string& klass) {
- if (hasClass(klass)) return;
- classes.push_back(klass);
- if (style) {
- style->cascadeClasses(classes);
- if (style->hasTransitions()) {
- triggerUpdate();
- }
+ if (data->addClass(klass)) {
+ triggerUpdate(Update::Classes);
}
}
void Map::removeClass(const std::string& klass) {
- if (!hasClass(klass)) return;
- classes.erase(std::remove(classes.begin(), classes.end(), klass), classes.end());
- if (style) {
- style->cascadeClasses(classes);
- if (style->hasTransitions()) {
- triggerUpdate();
- }
+ if (data->removeClass(klass)) {
+ triggerUpdate(Update::Classes);
}
}
-void Map::setClasses(const std::vector<std::string>& classes_) {
- classes = classes_;
- if (style) {
- style->cascadeClasses(classes);
- if (style->hasTransitions()) {
- triggerUpdate();
- }
- }
+void Map::setClasses(const std::vector<std::string>& classes) {
+ data->setClasses(classes);
+ triggerUpdate(Update::Classes);
}
bool Map::hasClass(const std::string& klass) const {
- return std::find(classes.begin(), classes.end(), klass) != classes.end();
+ return data->hasClass(klass);
}
std::vector<std::string> Map::getClasses() const {
- return classes;
+ return data->getClasses();
}
void Map::setDefaultTransitionDuration(std::chrono::steady_clock::duration duration) {
- defaultTransitionDuration = duration;
- if (style) {
- style->setDefaultTransitionDuration(duration);
- }
+ assert(Environment::currentlyOn(ThreadType::Main));
+
+ data->setDefaultTransitionDuration(duration);
+ triggerUpdate(Update::DefaultTransitionDuration);
}
std::chrono::steady_clock::duration Map::getDefaultTransitionDuration() {
- return defaultTransitionDuration;
+ assert(Environment::currentlyOn(ThreadType::Main));
+ return data->getDefaultTransitionDuration();
}
void Map::updateSources() {
@@ -657,7 +655,9 @@ void Map::updateSources() {
}
// Then, reenable all of those that we actually use when drawing this layer.
- updateSources(style->layers);
+ if (style) {
+ updateSources(style->layers);
+ }
// Then, construct or destroy the actual source object, depending on enabled state.
for (const auto& source : activeSources) {
@@ -702,45 +702,94 @@ void Map::updateTiles() {
}
}
-void Map::prepare() {
+void Map::update() {
+ assert(Environment::currentlyOn(ThreadType::Map));
+
+ if (state.hasSize()) {
+ prepare();
+ }
+}
+
+void Map::reloadStyle() {
assert(Environment::currentlyOn(ThreadType::Map));
- if (!style) {
- style = std::make_shared<Style>();
+ style = std::make_shared<Style>();
- env->request({ Resource::Kind::JSON, styleURL}, [&](const Response &res) {
+ const auto styleInfo = data->getStyleInfo();
+
+ if (!styleInfo.url.empty()) {
+ // We have a style URL
+ env->request({ Resource::Kind::JSON, styleInfo.url }, [&](const Response &res) {
if (res.status == Response::Successful) {
- // Calculate the base
- const size_t pos = styleURL.rfind('/');
- std::string base = "";
- if (pos != std::string::npos) {
- base = styleURL.substr(0, pos + 1);
- }
-
- setStyleJSON(res.data, base);
+ loadStyleJSON(res.data, styleInfo.base);
} else {
Log::Error(Event::Setup, "loading style failed: %s", res.message.c_str());
}
});
+ } else {
+ // We got JSON data directly.
+ loadStyleJSON(styleInfo.json, styleInfo.base);
+ }
+}
+
+void Map::loadStyleJSON(const std::string& json, const std::string& base) {
+ assert(Environment::currentlyOn(ThreadType::Map));
+
+ sprite.reset();
+ style = std::make_shared<Style>();
+ style->base = base;
+ style->loadJSON((const uint8_t *)json.c_str());
+ style->cascadeClasses(data->getClasses());
+ style->setDefaultTransitionDuration(data->getDefaultTransitionDuration());
+
+ const std::string glyphURL = util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken());
+ glyphStore->setURL(glyphURL);
+
+ triggerUpdate();
+}
+
+void Map::prepare() {
+ assert(Environment::currentlyOn(ThreadType::Map));
+
+ const auto u = updated.exchange(static_cast<UpdateType>(Update::Nothing));
+ if (u & static_cast<UpdateType>(Update::StyleInfo)) {
+ reloadStyle();
+ }
+ if (u & static_cast<UpdateType>(Update::Debug)) {
+ assert(painter);
+ painter->setDebug(data->getDebug());
+ }
+ if (u & static_cast<UpdateType>(Update::DefaultTransitionDuration)) {
+ if (style) {
+ style->setDefaultTransitionDuration(data->getDefaultTransitionDuration());
+ }
+ }
+ if (u & static_cast<UpdateType>(Update::Classes)) {
+ if (style) {
+ style->cascadeClasses(data->getClasses());
+ }
}
// Update transform transitions.
- animationTime = std::chrono::steady_clock::now();
+
+ const auto animationTime = std::chrono::steady_clock::now();
+ data->setAnimationTime(animationTime);
if (transform.needsTransition()) {
transform.updateTransitions(animationTime);
}
state = transform.currentState();
- animationTime = std::chrono::steady_clock::now();
- updateSources();
- style->updateProperties(state.getNormalizedZoom(), animationTime);
+ if (style) {
+ updateSources();
+ style->updateProperties(state.getNormalizedZoom(), animationTime);
- // Allow the sprite atlas to potentially pull new sprite images if needed.
- spriteAtlas->resize(state.getPixelRatio());
- spriteAtlas->setSprite(getSprite());
+ // Allow the sprite atlas to potentially pull new sprite images if needed.
+ spriteAtlas->resize(state.getPixelRatio());
+ spriteAtlas->setSprite(getSprite());
- updateTiles();
+ updateTiles();
+ }
if (mode == Mode::Continuous) {
view.invalidate();
@@ -749,9 +798,13 @@ void Map::prepare() {
void Map::render() {
assert(Environment::currentlyOn(ThreadType::Map));
+
+ // Cleanup OpenGL objects that we abandoned since the last render call.
+ env->performCleanup();
+
assert(painter);
painter->render(*style, activeSources,
- state, animationTime);
+ state, data->getAnimationTime());
// Schedule another rerender when we definitely need a next frame.
if (transform.needsTransition() || style->hasTransitions()) {
triggerUpdate();
diff --git a/src/mbgl/map/map_data.cpp b/src/mbgl/map/map_data.cpp
new file mode 100644
index 0000000000..23bc094990
--- /dev/null
+++ b/src/mbgl/map/map_data.cpp
@@ -0,0 +1,44 @@
+#include "map_data.hpp"
+
+#include <algorithm>
+
+namespace mbgl {
+
+// Adds the class if it's not yet set. Returns true when it added the class, and false when it
+// was already present.
+bool MapData::addClass(const std::string& klass) {
+ Lock lock(mtx);
+ if (std::find(classes.begin(), classes.end(), klass) != classes.end()) return false;
+ classes.push_back(klass);
+ return true;
+}
+
+// Removes the class if it's present. Returns true when it remvoed the class, and false when it
+// was not present.
+bool MapData::removeClass(const std::string& klass) {
+ Lock lock(mtx);
+ const auto it = std::find(classes.begin(), classes.end(), klass);
+ if (it != classes.end()) {
+ classes.erase(it);
+ return true;
+ }
+ return false;
+}
+
+// Returns true when class is present in the list of currently set classes.
+bool MapData::hasClass(const std::string& klass) const {
+ Lock lock(mtx);
+ return std::find(classes.begin(), classes.end(), klass) != classes.end();
+}
+
+void MapData::setClasses(const std::vector<std::string>& klasses) {
+ Lock lock(mtx);
+ classes = klasses;
+}
+
+std::vector<std::string> MapData::getClasses() const {
+ Lock lock(mtx);
+ return classes;
+}
+
+} \ No newline at end of file
diff --git a/src/mbgl/map/map_data.hpp b/src/mbgl/map/map_data.hpp
new file mode 100644
index 0000000000..c0d57134d9
--- /dev/null
+++ b/src/mbgl/map/map_data.hpp
@@ -0,0 +1,102 @@
+#ifndef MBGL_MAP_MAP_DATA
+#define MBGL_MAP_MAP_DATA
+
+#include <string>
+#include <mutex>
+#include <atomic>
+#include <chrono>
+#include <vector>
+
+namespace mbgl {
+
+struct StyleInfo {
+ std::string url;
+ std::string base;
+ std::string json;
+};
+
+class MapData {
+ using Lock = std::lock_guard<std::mutex>;
+
+public:
+ inline MapData() {
+ setAnimationTime(std::chrono::steady_clock::time_point::min());
+ setDefaultTransitionDuration(std::chrono::steady_clock::duration::zero());
+ }
+
+ inline StyleInfo getStyleInfo() const {
+ Lock lock(mtx);
+ return styleInfo;
+ }
+ inline void setStyleInfo(StyleInfo&& info) {
+ Lock lock(mtx);
+ styleInfo = info;
+ }
+
+ inline std::string getAccessToken() const {
+ Lock lock(mtx);
+ return accessToken;
+ }
+ inline void setAccessToken(const std::string &token) {
+ Lock lock(mtx);
+ accessToken = token;
+ }
+
+ // Adds the class if it's not yet set. Returns true when it added the class, and false when it
+ // was already present.
+ bool addClass(const std::string& klass);
+
+ // Removes the class if it's present. Returns true when it remvoed the class, and false when it
+ // was not present.
+ bool removeClass(const std::string& klass);
+
+ // Returns true when class is present in the list of currently set classes.
+ bool hasClass(const std::string& klass) const;
+
+ // Changes the list of currently set classes to the new list.
+ void setClasses(const std::vector<std::string>& klasses);
+
+ // Returns a list of all currently set classes.
+ std::vector<std::string> getClasses() const;
+
+
+ inline bool getDebug() const {
+ return debug;
+ }
+ inline bool toggleDebug() {
+ return debug ^= 1u;
+ }
+ inline void setDebug(bool value) {
+ debug = value;
+ }
+
+ inline std::chrono::steady_clock::time_point getAnimationTime() const {
+ // We're casting the time_point to and from a duration because libstdc++
+ // has a bug that doesn't allow time_points to be atomic.
+ return std::chrono::steady_clock::time_point(animationTime);
+ }
+ inline void setAnimationTime(std::chrono::steady_clock::time_point timePoint) {
+ animationTime = timePoint.time_since_epoch();
+ };
+
+ inline std::chrono::steady_clock::duration getDefaultTransitionDuration() const {
+ return defaultTransitionDuration;
+ }
+ inline void setDefaultTransitionDuration(std::chrono::steady_clock::duration duration) {
+ defaultTransitionDuration = duration;
+ };
+
+private:
+ mutable std::mutex mtx;
+
+ StyleInfo styleInfo;
+ std::string accessToken;
+ std::vector<std::string> classes;
+ std::atomic<uint8_t> debug { false };
+ std::atomic<std::chrono::steady_clock::time_point::duration> animationTime;
+ std::atomic<std::chrono::steady_clock::duration> defaultTransitionDuration;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp
index aed182671b..1832bd8f0c 100644
--- a/src/mbgl/map/tile_data.cpp
+++ b/src/mbgl/map/tile_data.cpp
@@ -97,7 +97,7 @@ void TileData::reparse(uv::worker& worker, std::function<void()> callback)
new uv::work<util::ptr<TileData>>(
worker,
[this](util::ptr<TileData>& tile) {
- Environment::Scope scope(env, ThreadType::TileWorker, "TileWorker_" + tile->name);
+ EnvironmentScope scope(env, ThreadType::TileWorker, "TileWorker_" + tile->name);
tile->parse();
},
[callback](util::ptr<TileData>&) {
diff --git a/src/mbgl/util/texture_pool.cpp b/src/mbgl/util/texture_pool.cpp
index 33bca01c05..845796f5df 100644
--- a/src/mbgl/util/texture_pool.cpp
+++ b/src/mbgl/util/texture_pool.cpp
@@ -1,4 +1,5 @@
#include <mbgl/util/texture_pool.hpp>
+#include <mbgl/map/environment.hpp>
#include <vector>
@@ -42,17 +43,9 @@ void TexturePool::removeTextureID(GLuint texture_id) {
}
void TexturePool::clearTextureIDs() {
- std::vector<GLuint> ids_to_remove;
- ids_to_remove.reserve(texture_ids.size());
-
- for (std::set<GLuint>::iterator id_iterator = texture_ids.begin();
- id_iterator != texture_ids.end(); ++id_iterator) {
- ids_to_remove.push_back(*id_iterator);
- }
-
- if (!ids_to_remove.empty()) {
- MBGL_CHECK_ERROR(glDeleteTextures((GLsizei)ids_to_remove.size(), &ids_to_remove[0]));
+ auto& env = Environment::Get();
+ for (auto texture : texture_ids) {
+ env.abandonTexture(texture);
}
-
texture_ids.clear();
}