Files
MapLibreParticleLab/src/mbgl/map/environment.cpp
2015-04-28 14:32:22 -04:00

183 lines
4.9 KiB
C++

#include <mbgl/map/environment.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/platform/gl.hpp>
#include <mbgl/util/run_loop.hpp>
#include <uv.h>
#include <atomic>
#include <cassert>
#include <mutex>
#include <unordered_map>
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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::thread::id, ThreadInfo> ThreadSet;
ThreadSet threadSet;
mutable std::mutex mtx;
};
unsigned makeEnvironmentID() {
static std::atomic<unsigned> 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) {
}
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<uint8_t>(threadInfoStore.getThreadInfo().type) & static_cast<uint8_t>(type);
}
std::string Environment::threadName() {
return threadInfoStore.getThreadInfo().name;
}
unsigned Environment::getID() const {
return id;
}
void Environment::requestAsync(const Resource& resource,
std::function<void(const Response&)> callback) {
fileSource.request(resource, std::move(callback));
}
Request* Environment::request(const Resource& resource,
std::function<void(const Response&)> callback) {
assert(currentlyOn(ThreadType::Map));
return fileSource.request(resource, util::RunLoop::current.get()->get(), 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<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();
}
}
}