From a5ef72a0516495ebc1663e015ca93d4178e9d091 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 6 Jun 2018 14:15:15 +0300 Subject: Use a shared scheduler on threads without a default scheduler Render threads won't have a scheduler, so we create one that is shared by all the maps rendering at this thread. The bad side effect of this is that we need to wake up the render thread to process events. Mapbox GL should get rid of processing events on the render thread. This solution is a workaround. --- platform/qt/qt.cmake | 4 +- platform/qt/src/qmapboxgl_map_renderer.cpp | 67 +++++++++++++++++------------- platform/qt/src/qmapboxgl_map_renderer.hpp | 11 +---- platform/qt/src/qmapboxgl_scheduler.cpp | 38 +++++++++++++++++ platform/qt/src/qmapboxgl_scheduler.hpp | 34 +++++++++++++++ 5 files changed, 115 insertions(+), 39 deletions(-) create mode 100644 platform/qt/src/qmapboxgl_scheduler.cpp create mode 100644 platform/qt/src/qmapboxgl_scheduler.hpp diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake index 989618a59a..dda15174fb 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 7a9d1f6f78..acc4194498 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 adba11de51..0b17542e2f 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 0000000000..e2d39703ee --- /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 0000000000..68636d0d11 --- /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; +}; -- cgit v1.2.1