diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake index 989618a59..dda15174f 100644 --- a/platform/qt/qt.cmake +++ b/platform/qt/qt.cmake @@ -65,8 +65,10 @@ add_library(qmapboxgl SHARED platform/qt/src/qmapboxgl_map_observer.hpp platform/qt/src/qmapboxgl_map_renderer.cpp platform/qt/src/qmapboxgl_map_renderer.hpp - platform/qt/src/qmapboxgl_renderer_backend.hpp platform/qt/src/qmapboxgl_renderer_backend.cpp + platform/qt/src/qmapboxgl_renderer_backend.hpp + platform/qt/src/qmapboxgl_scheduler.cpp + platform/qt/src/qmapboxgl_scheduler.hpp platform/default/mbgl/util/default_styles.hpp ) diff --git a/platform/qt/src/qmapboxgl_map_renderer.cpp b/platform/qt/src/qmapboxgl_map_renderer.cpp index 7a9d1f6f7..acc419449 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.cpp +++ b/platform/qt/src/qmapboxgl_map_renderer.cpp @@ -1,12 +1,47 @@ #include "qmapboxgl_map_renderer.hpp" +#include "qmapboxgl_scheduler.hpp" +#include #include +static bool needsToForceScheduler() { + static QThreadStorage force; + + if (!force.hasLocalData()) { + force.setLocalData(mbgl::Scheduler::GetCurrent() == nullptr); + } + + return force.localData(); +}; + +static auto *getScheduler() { + static QThreadStorage> scheduler; + + if (!scheduler.hasLocalData()) { + scheduler.setLocalData(std::make_shared()); + } + + return scheduler.localData().get(); +}; + QMapboxGLMapRenderer::QMapboxGLMapRenderer(qreal pixelRatio, mbgl::DefaultFileSource &fs, mbgl::ThreadPool &tp, QMapboxGLSettings::GLContextMode mode) : m_renderer(std::make_unique(m_backend, pixelRatio, fs, tp, static_cast(mode))) - , m_threadWithScheduler(Scheduler::GetCurrent() != nullptr) + , m_forceScheduler(needsToForceScheduler()) { + // If we don't have a Scheduler on this thread, which + // is usually the case for render threads, use a shared + // dummy scheduler that needs to be explicitly forced to + // process events. + if (m_forceScheduler) { + auto scheduler = getScheduler(); + + if (mbgl::Scheduler::GetCurrent() == nullptr) { + mbgl::Scheduler::SetCurrent(scheduler); + } + + connect(scheduler, SIGNAL(needsProcessing()), this, SIGNAL(needsRendering())); + } } QMapboxGLMapRenderer::~QMapboxGLMapRenderer() @@ -14,16 +49,6 @@ QMapboxGLMapRenderer::~QMapboxGLMapRenderer() MBGL_VERIFY_THREAD(tid); } -void QMapboxGLMapRenderer::schedule(std::weak_ptr mailbox) -{ - std::lock_guard lock(m_taskQueueMutex); - m_taskQueue.push(mailbox); - - // Need to force the main thread to wake - // up this thread and process the events. - emit needsRendering(); -} - void QMapboxGLMapRenderer::updateParameters(std::shared_ptr newParameters) { std::lock_guard lock(m_updateMutex); @@ -57,26 +82,10 @@ void QMapboxGLMapRenderer::render() // The OpenGL implementation automatically enables the OpenGL context for us. mbgl::BackendScope scope(m_backend, mbgl::BackendScope::ScopeType::Implicit); - // If we don't have a Scheduler on this thread, which - // is usually the case for render threads, use this - // object as scheduler. - if (!m_threadWithScheduler) { - Scheduler::SetCurrent(this); - } - m_renderer->render(*params); - if (!m_threadWithScheduler) { - std::queue> taskQueue; - { - std::unique_lock lock(m_taskQueueMutex); - std::swap(taskQueue, m_taskQueue); - } - - while (!taskQueue.empty()) { - mbgl::Mailbox::maybeReceive(taskQueue.front()); - taskQueue.pop(); - } + if (m_forceScheduler) { + getScheduler()->processEvents(); } } diff --git a/platform/qt/src/qmapboxgl_map_renderer.hpp b/platform/qt/src/qmapboxgl_map_renderer.hpp index adba11de5..0b17542e2 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.hpp +++ b/platform/qt/src/qmapboxgl_map_renderer.hpp @@ -14,7 +14,6 @@ #include #include -#include namespace mbgl { class Renderer; @@ -23,7 +22,7 @@ class UpdateParameters; class QMapboxGLRendererBackend; -class QMapboxGLMapRenderer : public QObject, public mbgl::Scheduler +class QMapboxGLMapRenderer : public QObject { Q_OBJECT @@ -32,9 +31,6 @@ public: mbgl::ThreadPool &, QMapboxGLSettings::GLContextMode); virtual ~QMapboxGLMapRenderer(); - // mbgl::Scheduler implementation. - void schedule(std::weak_ptr scheduled) final; - void render(); void updateFramebuffer(quint32 fbo, const mbgl::Size &size); void setObserver(std::shared_ptr); @@ -56,8 +52,5 @@ private: QMapboxGLRendererBackend m_backend; std::unique_ptr m_renderer; - std::mutex m_taskQueueMutex; - std::queue> m_taskQueue; - - bool m_threadWithScheduler; + bool m_forceScheduler; }; diff --git a/platform/qt/src/qmapboxgl_scheduler.cpp b/platform/qt/src/qmapboxgl_scheduler.cpp new file mode 100644 index 000000000..e2d39703e --- /dev/null +++ b/platform/qt/src/qmapboxgl_scheduler.cpp @@ -0,0 +1,38 @@ +#include "qmapboxgl_scheduler.hpp" + +#include + +#include + +QMapboxGLScheduler::QMapboxGLScheduler() +{ +} + +QMapboxGLScheduler::~QMapboxGLScheduler() +{ + MBGL_VERIFY_THREAD(tid); +} + +void QMapboxGLScheduler::schedule(std::weak_ptr mailbox) +{ + std::lock_guard lock(m_taskQueueMutex); + m_taskQueue.push(mailbox); + + // Need to force the main thread to wake + // up this thread and process the events. + emit needsProcessing(); +} + +void QMapboxGLScheduler::processEvents() +{ + std::queue> taskQueue; + { + std::unique_lock lock(m_taskQueueMutex); + std::swap(taskQueue, m_taskQueue); + } + + while (!taskQueue.empty()) { + mbgl::Mailbox::maybeReceive(taskQueue.front()); + taskQueue.pop(); + } +} diff --git a/platform/qt/src/qmapboxgl_scheduler.hpp b/platform/qt/src/qmapboxgl_scheduler.hpp new file mode 100644 index 000000000..68636d0d1 --- /dev/null +++ b/platform/qt/src/qmapboxgl_scheduler.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include + +class QMapboxGLScheduler : public QObject, public mbgl::Scheduler +{ + Q_OBJECT + +public: + QMapboxGLScheduler(); + virtual ~QMapboxGLScheduler(); + + // mbgl::Scheduler implementation. + void schedule(std::weak_ptr scheduled) final; + + void processEvents(); + +signals: + void needsProcessing(); + +private: + MBGL_STORE_THREAD(tid); + + std::mutex m_taskQueueMutex; + std::queue> m_taskQueue; +};