summaryrefslogtreecommitdiff
path: root/src/mbgl/util
diff options
context:
space:
mode:
authorBrad Leege <bleege@gmail.com>2015-05-04 17:04:46 -0500
committerBrad Leege <bleege@gmail.com>2015-05-04 17:04:46 -0500
commit4ce4e979ff85f8fc135fccf675c6a5e8939cdd66 (patch)
treedd49fd5b095445d9ef2ff28ec64157bacbbe2dd5 /src/mbgl/util
parent7f6cc6cc6d462952c02fbc50bd90f4f765a55809 (diff)
parentc2858dd45f735d99b1bc46043cff0b2a6b176c63 (diff)
downloadqtlocation-mapboxgl-4ce4e979ff85f8fc135fccf675c6a5e8939cdd66.tar.gz
Updating from master
Diffstat (limited to 'src/mbgl/util')
-rw-r--r--src/mbgl/util/mat4.cpp4
-rw-r--r--src/mbgl/util/raster.cpp30
-rw-r--r--src/mbgl/util/raster.hpp4
-rw-r--r--src/mbgl/util/run_loop.cpp16
-rw-r--r--src/mbgl/util/run_loop.hpp36
-rw-r--r--src/mbgl/util/thread.hpp65
-rw-r--r--src/mbgl/util/uv.cpp21
-rw-r--r--src/mbgl/util/uv_detail.hpp92
-rw-r--r--src/mbgl/util/worker.cpp71
-rw-r--r--src/mbgl/util/worker.hpp28
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;
};
}