#include #include #include #include #include #include #include #include namespace mbgl { namespace { class ThreadInfoStore { private: struct ThreadInfo { Environment* env; ThreadType type; std::string name; }; public: ThreadInfoStore() { registerThread(nullptr, ThreadType::Main, "Main"); } ~ThreadInfoStore() { unregisterThread(); assert(threadSet.size() == 0); } void registerThread(Environment* env, ThreadType type, const std::string& name) { std::lock_guard lock(mtx); // FIXME: We should never need to overwrite a thread here and we only allow // this today because on the Static mode, the Map thread and the Main thread // are same. Replace this with emplace() when this gets fixed. threadSet[std::this_thread::get_id()] = ThreadInfo{ env, type, name }; } void unregisterThread() { std::lock_guard lock(mtx); ThreadSet::iterator it = threadSet.find(std::this_thread::get_id()); if (it != threadSet.end()) { threadSet.erase(it); } } const ThreadInfo& getThreadInfo() const { static ThreadInfo emptyInfo; std::lock_guard lock(mtx); ThreadSet::const_iterator it = threadSet.find(std::this_thread::get_id()); if (it != threadSet.end()) { return it->second; } else { return emptyInfo; } } private: typedef std::unordered_map ThreadSet; ThreadSet threadSet; mutable std::mutex mtx; }; unsigned makeEnvironmentID() { static std::atomic id(0); return id++; } ThreadInfoStore threadInfoStore; } // namespace EnvironmentScope::EnvironmentScope(Environment& env, ThreadType type, const std::string& name) : id(std::this_thread::get_id()) { threadInfoStore.registerThread(&env, type, name); } EnvironmentScope::~EnvironmentScope() { assert(id == std::this_thread::get_id()); threadInfoStore.unregisterThread(); } 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); return *env; } bool Environment::inScope() { return threadInfoStore.getThreadInfo().env; } bool Environment::currentlyOn(ThreadType type) { return static_cast(threadInfoStore.getThreadInfo().type) & static_cast(type); } std::string Environment::threadName() { return threadInfoStore.getThreadInfo().name; } unsigned Environment::getID() const { return id; } void Environment::requestAsync(const Resource& resource, std::function callback) { fileSource.request(resource, *this, std::move(callback)); } Request* Environment::request(const Resource& resource, std::function callback) { assert(currentlyOn(ThreadType::Map)); return fileSource.request(resource, loop, *this, std::move(callback)); } void Environment::cancelRequest(Request* req) { assert(currentlyOn(ThreadType::Map)); 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(abandonedVAOs.size()), abandonedVAOs.data())); abandonedVAOs.clear(); } if (!abandonedTextures.empty()) { MBGL_CHECK_ERROR(glDeleteTextures(static_cast(abandonedTextures.size()), abandonedTextures.data())); abandonedTextures.clear(); } if (!abandonedBuffers.empty()) { MBGL_CHECK_ERROR(glDeleteBuffers(static_cast(abandonedBuffers.size()), abandonedBuffers.data())); abandonedBuffers.clear(); } } // ############################################################################################# void Environment::terminate() { fileSource.abort(*this); } }