diff options
author | Brad Leege <bleege@gmail.com> | 2015-05-04 17:04:46 -0500 |
---|---|---|
committer | Brad Leege <bleege@gmail.com> | 2015-05-04 17:04:46 -0500 |
commit | 4ce4e979ff85f8fc135fccf675c6a5e8939cdd66 (patch) | |
tree | dd49fd5b095445d9ef2ff28ec64157bacbbe2dd5 /src/mbgl/util | |
parent | 7f6cc6cc6d462952c02fbc50bd90f4f765a55809 (diff) | |
parent | c2858dd45f735d99b1bc46043cff0b2a6b176c63 (diff) | |
download | qtlocation-mapboxgl-4ce4e979ff85f8fc135fccf675c6a5e8939cdd66.tar.gz |
Updating from master
Diffstat (limited to 'src/mbgl/util')
-rw-r--r-- | src/mbgl/util/mat4.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/util/raster.cpp | 30 | ||||
-rw-r--r-- | src/mbgl/util/raster.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/util/run_loop.cpp | 16 | ||||
-rw-r--r-- | src/mbgl/util/run_loop.hpp | 36 | ||||
-rw-r--r-- | src/mbgl/util/thread.hpp | 65 | ||||
-rw-r--r-- | src/mbgl/util/uv.cpp | 21 | ||||
-rw-r--r-- | src/mbgl/util/uv_detail.hpp | 92 | ||||
-rw-r--r-- | src/mbgl/util/worker.cpp | 71 | ||||
-rw-r--r-- | src/mbgl/util/worker.hpp | 28 |
10 files changed, 202 insertions, 165 deletions
diff --git a/src/mbgl/util/mat4.cpp b/src/mbgl/util/mat4.cpp index 50270d9217..cabd8e2842 100644 --- a/src/mbgl/util/mat4.cpp +++ b/src/mbgl/util/mat4.cpp @@ -87,7 +87,7 @@ void matrix::copy(mat4& out, const mat4& a) { } void matrix::translate(mat4& out, const mat4& a, float x, float y, float z) { - if (a == out) { + if (&a == &out) { out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; @@ -124,7 +124,7 @@ void matrix::rotate_z(mat4& out, const mat4& a, float rad) { a12 = a[6], a13 = a[7]; - if (a != out) { // If the source and destination differ, copy the unchanged last row + if (&a != &out) { // If the source and destination differ, copy the unchanged last row out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; diff --git a/src/mbgl/util/raster.cpp b/src/mbgl/util/raster.cpp index d0e305c33a..f2171a6165 100644 --- a/src/mbgl/util/raster.cpp +++ b/src/mbgl/util/raster.cpp @@ -46,16 +46,7 @@ void Raster::bind(bool linear) { } if (img && !textured) { - texture = texturePool.getTextureID(); - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); -#ifndef GL_ES_VERSION_2_0 - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); -#endif - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img->getData())); - img.reset(); - textured = true; + upload(); } else if (textured) { MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); } @@ -68,24 +59,17 @@ void Raster::bind(bool linear) { } } -// overload ::bind for prerendered raster textures -void Raster::bind(const GLuint custom_texture) { +void Raster::upload() { if (img && !textured) { - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, custom_texture)); + texture = texturePool.getTextureID(); + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); +#ifndef GL_ES_VERSION_2_0 + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); +#endif MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img->getData())); img.reset(); textured = true; - } else if (textured) { - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, custom_texture)); } - - GLuint new_filter = GL_LINEAR; - if (new_filter != this->filter) { - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, new_filter)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, new_filter)); - filter = new_filter; - } - } diff --git a/src/mbgl/util/raster.hpp b/src/mbgl/util/raster.hpp index f19ff7178a..1789ae87f7 100644 --- a/src/mbgl/util/raster.hpp +++ b/src/mbgl/util/raster.hpp @@ -25,8 +25,8 @@ public: // bind current texture void bind(bool linear = false); - // bind prerendered texture - void bind(const GLuint texture); + // uploads the texture if it hasn't been uploaded yet. + void upload(); // loaded status bool isLoaded() const; diff --git a/src/mbgl/util/run_loop.cpp b/src/mbgl/util/run_loop.cpp index fd9ad43060..7f277c9885 100644 --- a/src/mbgl/util/run_loop.cpp +++ b/src/mbgl/util/run_loop.cpp @@ -5,8 +5,13 @@ namespace util { uv::tls<RunLoop> RunLoop::current; -RunLoop::RunLoop() - : async(*loop, std::bind(&RunLoop::process, this)) { +RunLoop::RunLoop(uv_loop_t* loop) + : async(loop, std::bind(&RunLoop::process, this)) { + current.set(this); +} + +RunLoop::~RunLoop() { + current.set(nullptr); } void RunLoop::withMutex(std::function<void()>&& fn) { @@ -24,13 +29,6 @@ void RunLoop::process() { } } -void RunLoop::run() { - assert(!current.get()); - current.set(this); - loop.run(); - current.set(nullptr); -} - void RunLoop::stop() { invoke([&] { async.unref(); }); } diff --git a/src/mbgl/util/run_loop.hpp b/src/mbgl/util/run_loop.hpp index d785854e79..767a47b754 100644 --- a/src/mbgl/util/run_loop.hpp +++ b/src/mbgl/util/run_loop.hpp @@ -14,9 +14,9 @@ namespace util { class RunLoop : private util::noncopyable { public: - RunLoop(); + RunLoop(uv_loop_t*); + ~RunLoop(); - void run(); void stop(); // Invoke fn() in the runloop thread. @@ -29,7 +29,7 @@ public: // Invoke fn() in the runloop thread, then invoke callback(result) in the current thread. template <class Fn, class R> - void invokeWithResult(Fn&& fn, std::function<void (R)> callback) { + void invokeWithResult(Fn&& fn, std::function<void (R)>&& callback) { RunLoop* outer = current.get(); assert(outer); @@ -37,21 +37,35 @@ public: /* With C++14, we could write: - outer->invoke([callback, result = std::move(fn())] () mutable { - callback(std::move(result)); + outer->invoke([cb = std::move(callback), result = std::move(fn())] () mutable { + cb(std::move(result)); }); Instead we're using a workaround with std::bind to obtain move-capturing semantics with C++11: http://stackoverflow.com/a/12744730/52207 */ - outer->invoke(std::bind([callback] (R& result) { - callback(std::move(result)); - }, std::move(fn()))); + outer->invoke(std::bind([] (std::function<void (R)>& cb, R& result) { + cb(std::move(result)); + }, std::move(callback), std::move(fn()))); }); } - uv_loop_t* get() { return *loop; } + // Invoke fn() in the runloop thread, then invoke callback() in the current thread. + template <class Fn> + void invokeWithResult(Fn&& fn, std::function<void ()>&& callback) { + RunLoop* outer = current.get(); + assert(outer); + + invoke([fn, callback, outer] { + fn(); + outer->invoke(std::move(callback)); + }); + } + + uv_loop_t* get() { return async.get()->loop; } + + static uv::tls<RunLoop> current; private: // A movable type-erasing invokable entity wrapper. This allows to store arbitrary invokable @@ -71,15 +85,11 @@ private: using Queue = std::queue<std::unique_ptr<Message>>; - static uv::tls<RunLoop> current; - void withMutex(std::function<void()>&&); void process(); Queue queue; std::mutex mutex; - - uv::loop loop; uv::async async; }; diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp index 4831b9efc2..e97872a502 100644 --- a/src/mbgl/util/thread.hpp +++ b/src/mbgl/util/thread.hpp @@ -3,9 +3,11 @@ #include <future> #include <thread> +#include <atomic> #include <functional> #include <mbgl/util/run_loop.hpp> +#include <mbgl/platform/platform.hpp> namespace { @@ -33,11 +35,16 @@ namespace util { // Thread<> constructor blocks until the thread and the Object are fully created, so after the // object creation, it's safe to obtain the Object stored in this thread. +enum class ThreadPriority : bool { + Regular, + Low, +}; + template <class Object> class Thread { public: template <class... Args> - Thread(const std::string& name, Args&&... args); + Thread(const std::string& name, ThreadPriority priority, Args&&... args); ~Thread(); // Invoke object->fn(args...) in the runloop thread. @@ -48,11 +55,33 @@ public: // Invoke object->fn(args...) in the runloop thread, then invoke callback(result) in the current thread. template <typename Fn, class R, class... Args> - void invokeWithResult(Fn fn, std::function<void (R)> callback, Args&&... args) { - loop->invokeWithResult(std::bind(fn, object, args...), callback); + void invokeWithResult(Fn fn, std::function<void (R)>&& callback, Args&&... args) { + loop->invokeWithResult(std::bind(fn, object, args...), std::move(callback)); + } + + // Invoke object->fn(args...) in the runloop thread, then invoke callback() in the current thread. + template <typename Fn, class... Args> + void invokeWithResult(Fn fn, std::function<void ()>&& callback, Args&&... args) { + loop->invokeWithResult(std::bind(fn, object, args...), std::move(callback)); + } + + // Invoke object->fn(args...) in the runloop thread, and wait for the result. + template <class R, typename Fn, class... Args> + R invokeSync(Fn fn, Args&&... args) { + std::packaged_task<R ()> task(std::bind(fn, object, args...)); + std::future<R> future = task.get_future(); + loop->invoke(std::move(task)); + return future.get(); } - uv_loop_t* get() { return loop->get(); } + // Invoke object->fn(args...) in the runloop thread, and wait for it to complete. + template <typename Fn, class... Args> + void invokeSync(Fn fn, Args&&... args) { + std::packaged_task<void ()> task(std::bind(fn, object, args...)); + std::future<void> future = task.get_future(); + loop->invoke(std::move(task)); + return future.get(); + } private: Thread(const Thread&) = delete; @@ -74,7 +103,7 @@ private: template <class Object> template <class... Args> -Thread<Object>::Thread(const std::string& name, Args&&... args) { +Thread<Object>::Thread(const std::string& name, ThreadPriority priority, Args&&... args) { // Note: We're using std::tuple<> to store the arguments because GCC 4.9 has a bug // when expanding parameters packs captured in lambdas. std::tuple<Args...> params = std::forward_as_tuple(::std::forward<Args>(args)...); @@ -86,6 +115,10 @@ Thread<Object>::Thread(const std::string& name, Args&&... args) { (void(name)); #endif + if (priority == ThreadPriority::Low) { + platform::makeThreadLowPriority(); + } + constexpr auto seq = typename integer_sequence<sizeof...(Args)>::type(); run(std::move(params), seq); }); @@ -96,14 +129,24 @@ Thread<Object>::Thread(const std::string& name, Args&&... args) { template <class Object> template <typename P, std::size_t... I> void Thread<Object>::run(P&& params, index_sequence<I...>) { - Object object_(std::get<I>(std::forward<P>(params))...); - object = &object_; + uv::loop l; + + { + RunLoop loop_(l.get()); + loop = &loop_; - RunLoop loop_; - loop = &loop_; + Object object_(l.get(), std::get<I>(std::forward<P>(params))...); + object = &object_; + + running.set_value(); + l.run(); + + loop = nullptr; + object = nullptr; + } - running.set_value(); - loop_.run(); + // Run the loop again to ensure that async close callbacks have been called. + l.run(); joinable.get_future().get(); } diff --git a/src/mbgl/util/uv.cpp b/src/mbgl/util/uv.cpp index 5dae34ebd0..d76e42f67d 100644 --- a/src/mbgl/util/uv.cpp +++ b/src/mbgl/util/uv.cpp @@ -1,8 +1,29 @@ #include <mbgl/util/uv.hpp> #include <mbgl/util/uv_detail.hpp> +#include <mbgl/util/string.hpp> #include <uv.h> +// Check libuv library version. +const static bool uvVersionCheck = []() { + const unsigned int version = uv_version(); + const unsigned int major = (version >> 16) & 0xFF; + const unsigned int minor = (version >> 8) & 0xFF; + const unsigned int patch = version & 0xFF; + +#ifndef UV_VERSION_PATCH + // 0.10 doesn't have UV_VERSION_PATCH defined, so we "fake" it by using the library patch level. + const unsigned int UV_VERSION_PATCH = version & 0xFF; +#endif + + if (major != UV_VERSION_MAJOR || minor != UV_VERSION_MINOR || patch != UV_VERSION_PATCH) { + throw std::runtime_error(mbgl::util::sprintf<96>( + "libuv version mismatch: headers report %d.%d.%d, but library reports %d.%d.%d", UV_VERSION_MAJOR, + UV_VERSION_MINOR, UV_VERSION_PATCH, major, minor, patch)); + } + return true; +}(); + #if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 int uv_key_create(uv_key_t* key) { diff --git a/src/mbgl/util/uv_detail.hpp b/src/mbgl/util/uv_detail.hpp index 96d5442462..059d7c0ddb 100644 --- a/src/mbgl/util/uv_detail.hpp +++ b/src/mbgl/util/uv_detail.hpp @@ -28,13 +28,6 @@ UV_EXTERN void uv_key_set(uv_key_t* key, void* value); namespace uv { -template <class T> -void close(std::unique_ptr<T> ptr) { - uv_close(reinterpret_cast<uv_handle_t*>(ptr.release()), [](uv_handle_t* handle) { - delete reinterpret_cast<T*>(handle); - }); -} - class loop : public mbgl::util::noncopyable { public: inline loop() { @@ -74,46 +67,93 @@ private: uv_loop_t *l = nullptr; }; -class async : public mbgl::util::noncopyable { +template <class T> +class handle : public mbgl::util::noncopyable { +public: + inline handle() : t(reinterpret_cast<uv_handle_t*>(new T)) { + t->data = this; + } + + inline ~handle() { + uv_close(t.release(), [](uv_handle_t* handle) { + delete reinterpret_cast<T*>(handle); + }); + } + + inline void ref() { + uv_ref(t.get()); + } + + inline void unref() { + uv_unref(t.get()); + } + + inline T* get() { + return reinterpret_cast<T*>(t.get()); + } + +private: + std::unique_ptr<uv_handle_t> t; +}; + +class async : public handle<uv_async_t> { public: inline async(uv_loop_t* loop, std::function<void ()> fn_) - : a(new uv_async_t) - , fn(fn_) - { - a->data = this; - if (uv_async_init(loop, a.get(), async_cb) != 0) { + : fn(fn_) { + if (uv_async_init(loop, get(), async_cb) != 0) { throw std::runtime_error("failed to initialize async"); } } - inline ~async() { - close(std::move(a)); - } - inline void send() { - if (uv_async_send(a.get()) != 0) { + if (uv_async_send(get()) != 0) { throw std::runtime_error("failed to async send"); } } - inline void ref() { - uv_ref(reinterpret_cast<uv_handle_t*>(a.get())); +private: +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + static void async_cb(uv_async_t* a, int) { +#else + static void async_cb(uv_async_t* a) { +#endif + reinterpret_cast<async*>(a->data)->fn(); } - inline void unref() { - uv_unref(reinterpret_cast<uv_handle_t*>(a.get())); + std::function<void ()> fn; +}; + +class timer : public handle<uv_timer_t> { +public: + inline timer(uv_loop_t* loop) { + if (uv_timer_init(loop, get()) != 0) { + throw std::runtime_error("failed to initialize timer"); + } + } + + inline void start(uint64_t timeout, uint64_t repeat, std::function<void ()> fn_) { + fn = fn_; + if (uv_timer_start(get(), timer_cb, timeout, repeat) != 0) { + throw std::runtime_error("failed to start timer"); + } + } + + inline void stop() { + fn = nullptr; + if (uv_timer_stop(get()) != 0) { + throw std::runtime_error("failed to stop timer"); + } } private: #if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 - static void async_cb(uv_async_t* a, int) { + static void timer_cb(uv_timer_t* t, int) { #else - static void async_cb(uv_async_t* a) { + static void timer_cb(uv_timer_t* t) { #endif - reinterpret_cast<async*>(a->data)->fn(); + reinterpret_cast<timer*>(t->data)->fn(); } - std::unique_ptr<uv_async_t> a; std::function<void ()> fn; }; diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp index 3559cdd71f..9792f1a099 100644 --- a/src/mbgl/util/worker.cpp +++ b/src/mbgl/util/worker.cpp @@ -1,73 +1,30 @@ #include <mbgl/util/worker.hpp> +#include <mbgl/platform/platform.hpp> #include <cassert> namespace mbgl { -Worker::Worker(uv_loop_t* loop, std::size_t count) - : queue(new Queue(loop, [this](Fn after) { afterWork(after); })) -{ - queue->unref(); +class Worker::Impl { +public: + Impl(uv_loop_t*) {} - for (std::size_t i = 0; i < count; i++) { - threads.emplace_back(&Worker::workLoop, this); - } -} - -Worker::~Worker() { - MBGL_VERIFY_THREAD(tid); - - if (active++ == 0) { - queue->ref(); - } - - channel.send(Work()); - - for (auto& thread : threads) { - thread.join(); - } - - queue->stop(); -} - -void Worker::send(Fn work, Fn after) { - MBGL_VERIFY_THREAD(tid); - assert(work); - - if (active++ == 0) { - queue->ref(); + void doWork(Fn work) { + work(); } +}; - channel.send({work, after}); -} - -void Worker::workLoop() { -#ifdef __APPLE__ - pthread_setname_np("Worker"); -#endif - - while (true) { - Work item = channel.receive(); - - if (!item.work) - break; - - item.work(); - queue->send(std::move(item.after)); +Worker::Worker(std::size_t count) { + for (std::size_t i = 0; i < count; i++) { + threads.emplace_back(util::make_unique<util::Thread<Impl>>("Worker", util::ThreadPriority::Low)); } - - // Make sure to close all other workers too. - channel.send(Work()); } -void Worker::afterWork(Fn after) { - if (after) { - after(); - } +Worker::~Worker() = default; - if (--active == 0) { - queue->unref(); - } +void Worker::send(Fn&& work, Fn&& after) { + threads[current]->invokeWithResult(&Worker::Impl::doWork, std::move(after), std::move(work)); + current = (current + 1) % threads.size(); } } diff --git a/src/mbgl/util/worker.hpp b/src/mbgl/util/worker.hpp index 86c2e6acf4..d8fbf6df7d 100644 --- a/src/mbgl/util/worker.hpp +++ b/src/mbgl/util/worker.hpp @@ -2,11 +2,8 @@ #define MBGL_UTIL_WORKER #include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/async_queue.hpp> -#include <mbgl/util/channel.hpp> -#include <mbgl/util/util.hpp> +#include <mbgl/util/thread.hpp> -#include <thread> #include <functional> namespace mbgl { @@ -15,28 +12,15 @@ class Worker : public mbgl::util::noncopyable { public: using Fn = std::function<void ()>; - Worker(uv_loop_t* loop, std::size_t count); + Worker(std::size_t count); ~Worker(); - void send(Fn work, Fn after); + void send(Fn&& work, Fn&& after); private: - void workLoop(); - void afterWork(Fn after); - - struct Work { - Fn work; - Fn after; - }; - - using Queue = util::AsyncQueue<std::function<void ()>>; - - std::size_t active = 0; - Queue* queue = nullptr; - Channel<Work> channel; - std::vector<std::thread> threads; - - MBGL_STORE_THREAD(tid) + class Impl; + std::vector<std::unique_ptr<util::Thread<Impl>>> threads; + std::size_t current = 0; }; } |