diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index af94eb9f7..cf6be2c9a 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -2,6 +2,7 @@ #include "qmapboxgl_p.hpp" #include "qmapboxgl_map_observer.hpp" +#include "qmapboxgl_renderer_observer.hpp" #include "qt_conversion.hpp" #include "qt_geojson.hpp" @@ -1486,6 +1487,7 @@ void QMapboxGL::render() } #endif + d_ptr->renderQueued.clear(); d_ptr->mapRenderer->render(); } @@ -1567,7 +1569,8 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin static_cast(settings.constrainMode()), static_cast(settings.viewportMode())); - connect(this, SIGNAL(needsRendering()), q_ptr, SIGNAL(needsRendering())); + // Needs to be Queued to give time to discard redundant draw calls via the `renderQueued` flag. + connect(this, SIGNAL(needsRendering()), q_ptr, SIGNAL(needsRendering()), Qt::QueuedConnection); } QMapboxGLPrivate::~QMapboxGLPrivate() @@ -1577,5 +1580,16 @@ QMapboxGLPrivate::~QMapboxGLPrivate() void QMapboxGLPrivate::update(std::shared_ptr parameters) { mapRenderer->updateParameters(std::move(parameters)); - emit needsRendering(); + + if (!renderQueued.test_and_set()) { + emit needsRendering(); + } +} + +void QMapboxGLPrivate::setObserver(mbgl::RendererObserver &observer) +{ + m_rendererObserver = std::make_shared( + *mbgl::util::RunLoop::Get(), observer); + + mapRenderer->setObserver(m_rendererObserver); } diff --git a/platform/qt/src/qmapboxgl_map_renderer.cpp b/platform/qt/src/qmapboxgl_map_renderer.cpp index c0293c207..a343d5666 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.cpp +++ b/platform/qt/src/qmapboxgl_map_renderer.cpp @@ -41,3 +41,8 @@ void QMapboxGLMapRenderer::render() m_renderer->render(*params); } + +void QMapboxGLMapRenderer::setObserver(std::shared_ptr observer) +{ + m_renderer->setObserver(observer.get()); +} diff --git a/platform/qt/src/qmapboxgl_map_renderer.hpp b/platform/qt/src/qmapboxgl_map_renderer.hpp index d0c70b97c..5769432f0 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.hpp +++ b/platform/qt/src/qmapboxgl_map_renderer.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -26,6 +27,7 @@ public: virtual ~QMapboxGLMapRenderer(); void render(); + void setObserver(std::shared_ptr); // Thread-safe, called by the Frontend void updateParameters(std::shared_ptr); diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index 55377eb51..b9a4b37ae 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -15,6 +15,7 @@ #include #include +#include #include class QMapboxGLPrivate : public QObject, public mbgl::RendererFrontend @@ -27,7 +28,7 @@ public: // mbgl::RendererFrontend implementation. void reset() final {} - void setObserver(mbgl::RendererObserver &) final {} + void setObserver(mbgl::RendererObserver &) final; void update(std::shared_ptr) final; mbgl::EdgeInsets margins; @@ -40,7 +41,12 @@ public: std::unique_ptr mapObserver; std::unique_ptr mapRenderer; + std::shared_ptr rendererObserver; + QMapboxGLSettings::GLContextMode mode; + qreal pixelRatio; + + std::atomic_flag renderQueued = ATOMIC_FLAG_INIT; signals: void needsRendering(); diff --git a/platform/qt/src/qmapboxgl_renderer_observer.hpp b/platform/qt/src/qmapboxgl_renderer_observer.hpp new file mode 100644 index 000000000..ee340113f --- /dev/null +++ b/platform/qt/src/qmapboxgl_renderer_observer.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +// Forwards RendererObserver signals to the given +// Delegate RendererObserver on the given RunLoop +class QMapboxGLRendererObserver : public mbgl::RendererObserver { +public: + QMapboxGLRendererObserver(mbgl::util::RunLoop& mapRunLoop, mbgl::RendererObserver& delegate_) + : mailbox(std::make_shared(mapRunLoop)) + , delegate(delegate_, mailbox) { + } + + ~QMapboxGLRendererObserver() { + mailbox->close(); + } + + void onInvalidate() final { + delegate.invoke(&mbgl::RendererObserver::onInvalidate); + } + + void onResourceError(std::exception_ptr err) final { + delegate.invoke(&mbgl::RendererObserver::onResourceError, err); + } + + void onWillStartRenderingMap() final { + delegate.invoke(&mbgl::RendererObserver::onWillStartRenderingMap); + } + + void onWillStartRenderingFrame() final { + delegate.invoke(&mbgl::RendererObserver::onWillStartRenderingFrame); + } + + void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded) final { + delegate.invoke(&mbgl::RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded); + } + + void onDidFinishRenderingMap() final { + delegate.invoke(&mbgl::RendererObserver::onDidFinishRenderingMap); + } + +private: + std::shared_ptr mailbox; + mbgl::ActorRef delegate; +};