summaryrefslogtreecommitdiff
path: root/platform/qt
diff options
context:
space:
mode:
Diffstat (limited to 'platform/qt')
-rw-r--r--platform/qt/app/mapwindow.cpp5
-rw-r--r--platform/qt/include/qmapboxgl.hpp24
-rw-r--r--platform/qt/qt.cmake8
-rw-r--r--platform/qt/src/qmapboxgl.cpp379
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.cpp95
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.hpp45
-rw-r--r--platform/qt/src/qmapboxgl_map_renderer.cpp86
-rw-r--r--platform/qt/src/qmapboxgl_map_renderer.hpp63
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp77
-rw-r--r--platform/qt/src/qmapboxgl_renderer_backend.cpp49
-rw-r--r--platform/qt/src/qmapboxgl_renderer_backend.hpp34
-rw-r--r--platform/qt/src/qmapboxgl_renderer_frontend_p.cpp37
-rw-r--r--platform/qt/src/qmapboxgl_renderer_frontend_p.hpp35
-rw-r--r--platform/qt/src/qmapboxgl_renderer_observer.hpp51
-rw-r--r--[-rwxr-xr-x]platform/qt/src/qt_logging.cpp0
-rw-r--r--platform/qt/test/qmapboxgl.test.cpp4
16 files changed, 701 insertions, 291 deletions
diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp
index fc346cdcde..f6d5473192 100644
--- a/platform/qt/app/mapwindow.cpp
+++ b/platform/qt/app/mapwindow.cpp
@@ -442,10 +442,9 @@ void MapWindow::initializeGL()
void MapWindow::paintGL()
{
m_frameDraws++;
- m_map->resize(size(), size() * pixelRatio());
+ m_map->resize(size());
#if QT_VERSION >= 0x050400
- // When we're using QOpenGLWidget, we need to tell Mapbox GL about the framebuffer we're using.
- m_map->setFramebufferObject(defaultFramebufferObject());
+ m_map->setFramebufferObject(defaultFramebufferObject(), size() * pixelRatio());
#endif
m_map->render();
}
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index 8b319b0453..bc18eaba59 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -26,6 +26,11 @@ public:
SharedGLContext
};
+ enum MapMode {
+ Continuous = 0,
+ Static
+ };
+
enum ConstrainMode {
NoConstrain = 0,
ConstrainHeightOnly,
@@ -40,6 +45,9 @@ public:
GLContextMode contextMode() const;
void setContextMode(GLContextMode);
+ MapMode mapMode() const;
+ void setMapMode(MapMode);
+
ConstrainMode constrainMode() const;
void setConstrainMode(ConstrainMode);
@@ -66,6 +74,7 @@ public:
private:
GLContextMode m_contextMode;
+ MapMode m_mapMode;
ConstrainMode m_constrainMode;
ViewportMode m_viewportMode;
@@ -191,8 +200,7 @@ public:
void scaleBy(double scale, const QPointF &center = QPointF());
void rotateBy(const QPointF &first, const QPointF &second);
- void resize(const QSize &size, const QSize &framebufferSize);
- void setFramebufferObject(quint32 fbo);
+ void resize(const QSize &size);
double metersPerPixelAtLatitude(double latitude, double zoom) const;
QMapbox::ProjectedMeters projectedMetersForCoordinate(const QMapbox::Coordinate &) const;
@@ -226,15 +234,27 @@ public:
void setFilter(const QString &layer, const QVariant &filter);
+ // When rendering on a different thread,
+ // should be called on the render thread.
+ void createRenderer();
+ void destroyRenderer();
+ void setFramebufferObject(quint32 fbo, const QSize &size);
+
public slots:
void render();
void connectionEstablished();
+ // Commit changes, load all the resources
+ // and renders the map when completed.
+ void startStaticRender();
+
signals:
void needsRendering();
void mapChanged(QMapboxGL::MapChange);
void copyrightsChanged(const QString &copyrightsHtml);
+ void staticRenderFinished(const QString &error);
+
private:
Q_DISABLE_COPY(QMapboxGL)
diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake
index aaae199650..d1d597bda6 100644
--- a/platform/qt/qt.cmake
+++ b/platform/qt/qt.cmake
@@ -61,8 +61,12 @@ add_library(qmapboxgl SHARED
platform/qt/src/qmapbox.cpp
platform/qt/src/qmapboxgl.cpp
platform/qt/src/qmapboxgl_p.hpp
- platform/qt/src/qmapboxgl_renderer_frontend_p.hpp
- platform/qt/src/qmapboxgl_renderer_frontend_p.cpp
+ platform/qt/src/qmapboxgl_map_observer.cpp
+ 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/default/mbgl/util/default_styles.hpp
)
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 2675d87862..414b65255c 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -1,6 +1,8 @@
#include "qmapboxgl.hpp"
#include "qmapboxgl_p.hpp"
-#include "qmapboxgl_renderer_frontend_p.hpp"
+
+#include "qmapboxgl_map_observer.hpp"
+#include "qmapboxgl_renderer_observer.hpp"
#include "qt_conversion.hpp"
#include "qt_geojson.hpp"
@@ -43,11 +45,8 @@
#if QT_VERSION >= 0x050000
#include <QGuiApplication>
-#include <QWindow>
-#include <QOpenGLContext>
#else
#include <QCoreApplication>
-#include <QGLContext>
#endif
#include <QDebug>
@@ -65,6 +64,10 @@ using namespace QMapbox;
static_assert(mbgl::underlying_type(QMapboxGLSettings::UniqueGLContext) == mbgl::underlying_type(mbgl::GLContextMode::Unique), "error");
static_assert(mbgl::underlying_type(QMapboxGLSettings::SharedGLContext) == mbgl::underlying_type(mbgl::GLContextMode::Shared), "error");
+// mbgl::MapMode
+static_assert(mbgl::underlying_type(QMapboxGLSettings::Continuous) == mbgl::underlying_type(mbgl::MapMode::Continuous), "error");
+static_assert(mbgl::underlying_type(QMapboxGLSettings::Static) == mbgl::underlying_type(mbgl::MapMode::Static), "error");
+
// mbgl::ConstrainMode
static_assert(mbgl::underlying_type(QMapboxGLSettings::NoConstrain) == mbgl::underlying_type(mbgl::ConstrainMode::None), "error");
static_assert(mbgl::underlying_type(QMapboxGLSettings::ConstrainHeightOnly) == mbgl::underlying_type(mbgl::ConstrainMode::HeightOnly), "error");
@@ -165,6 +168,27 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage
*/
/*!
+ \enum QMapboxGLSettings::MapMode
+
+ This enum sets the map rendering mode
+
+ \value Continuous The map will render as data arrives from the network and
+ react immediately to state changes.
+
+ This is the default mode and the preferred when the map is intended to be
+ interactive.
+
+ \value Static The map will no longer react to state changes and will only
+ be rendered when QMapboxGL::startStaticRender is called. After all the
+ resources are loaded, the QMapboxGL::staticRenderFinished signal is emitted.
+
+ This mode is useful for taking a snapshot of the finished rendering result
+ of the map into a QImage.
+
+ \sa mapMode()
+*/
+
+/*!
\enum QMapboxGLSettings::ConstrainMode
This enum determines if the map wraps.
@@ -200,6 +224,7 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage
*/
QMapboxGLSettings::QMapboxGLSettings()
: m_contextMode(QMapboxGLSettings::SharedGLContext)
+ , m_mapMode(QMapboxGLSettings::Continuous)
, m_constrainMode(QMapboxGLSettings::ConstrainHeightOnly)
, m_viewportMode(QMapboxGLSettings::DefaultViewport)
, m_cacheMaximumSize(mbgl::util::DEFAULT_MAX_CACHE_SIZE)
@@ -230,6 +255,31 @@ void QMapboxGLSettings::setContextMode(GLContextMode mode)
}
/*!
+ Returns the map mode. Static mode will emit a signal for
+ rendering a map only when the map is fully loaded.
+ Animations like style transitions and labels fading won't
+ be seen.
+
+ The Continuous mode will emit the signal for every new
+ change on the map and it is usually what you expect for
+ a interactive map.
+
+ By default, it is set to QMapboxGLSettings::Continuous.
+*/
+QMapboxGLSettings::MapMode QMapboxGLSettings::mapMode() const
+{
+ return m_mapMode;
+}
+
+/*!
+ Sets the map \a mode.
+*/
+void QMapboxGLSettings::setMapMode(MapMode mode)
+{
+ m_mapMode = mode;
+}
+
+/*!
Returns the constrain mode. This is used to limit the map to wrap
around the globe horizontally.
@@ -1048,32 +1098,17 @@ void QMapboxGL::rotateBy(const QPointF &first, const QPointF &second)
}
/*!
- Resize the map to \a size and scale to fit at \a framebufferSize. For
- high DPI screens, the size will be smaller than the \a framebufferSize.
-
- This fallowing example will double the pixel density of the map for
- a given \c size:
-
- \code
- map->resize(size / 2, size);
- \endcode
+ Resize the map to \a size_ and scale to fit at the framebuffer. For
+ high DPI screens, the size will be smaller than the framebuffer.
*/
-void QMapboxGL::resize(const QSize& size, const QSize& framebufferSize)
+void QMapboxGL::resize(const QSize& size_)
{
- if (d_ptr->size == size && d_ptr->fbSize == framebufferSize) return;
-
- d_ptr->size = size;
- d_ptr->fbSize = framebufferSize;
+ auto size = sanitizedSize(size_);
- d_ptr->mapObj->setSize(sanitizedSize(size));
-}
+ if (d_ptr->mapObj->getSize() == size)
+ return;
-/*!
- If Mapbox GL needs to rebind the default \a fbo, it will use the
- ID supplied here.
-*/
-void QMapboxGL::setFramebufferObject(quint32 fbo) {
- d_ptr->fbObject = fbo;
+ d_ptr->mapObj->setSize(size);
}
/*!
@@ -1468,6 +1503,51 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
}
/*!
+ Creates the infrastructure needed for rendering the map. It
+ should be called before any call to render().
+
+ Must be called on the render thread.
+*/
+void QMapboxGL::createRenderer()
+{
+ d_ptr->createRenderer();
+}
+
+/*!
+ Destroys the infrastructure needed for rendering the map,
+ releasing resources.
+
+ Must be called on the render thread.
+*/
+void QMapboxGL::destroyRenderer()
+{
+ d_ptr->destroyRenderer();
+}
+
+/*!
+ Start a static rendering of the current state of the map. This
+ should only be called when the map is initialized in static mode.
+
+ \sa QMapboxGLSettings::MapMode
+*/
+void QMapboxGL::startStaticRender()
+{
+ d_ptr->mapObj->renderStill([this](std::exception_ptr err) {
+ QString what;
+
+ try {
+ if (err) {
+ std::rethrow_exception(err);
+ }
+ } catch(const std::exception& e) {
+ what = e.what();
+ }
+
+ emit staticRenderFinished(what);
+ });
+}
+
+/*!
Renders the map using OpenGL draw calls. It will make sure to bind the
framebuffer object before drawing; otherwise a valid OpenGL context is
expected with an appropriate OpenGL viewport state set for the size of
@@ -1475,28 +1555,33 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
This function should be called only after the signal needsRendering() is
emitted at least once.
+
+ Must be called on the render thread.
*/
void QMapboxGL::render()
{
-#if defined(__APPLE__) && QT_VERSION < 0x050000
- // FIXME Qt 4.x provides an incomplete FBO at start.
- // See https://bugreports.qt.io/browse/QTBUG-36802 for details.
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return;
- }
-#endif
-
- d_ptr->dirty = false;
d_ptr->render();
}
/*!
+ If Mapbox GL needs to rebind the default \a fbo, it will use the
+ ID supplied here. \a size is the size of the framebuffer, which
+ on high DPI screens is usually bigger than the map size.
+
+ Must be called on the render thread.
+*/
+void QMapboxGL::setFramebufferObject(quint32 fbo, const QSize& size)
+{
+ d_ptr->setFramebufferObject(fbo, size);
+}
+
+/*!
Informs the map that the network connection has been established, causing
all network requests that previously timed out to be retried immediately.
*/
void QMapboxGL::connectionEstablished()
{
- d_ptr->connectionEstablished();
+ mbgl::NetworkStatus::Reachable();
}
/*!
@@ -1510,6 +1595,16 @@ void QMapboxGL::connectionEstablished()
*/
/*!
+ \fn void QMapboxGL::staticRenderFinished(const QString &error)
+
+ This signal is emitted when a static map is fully drawn. Usually the next
+ step is to extract the map from a framebuffer into a container like a
+ QImage. \a error is set to a message when an error occurs.
+
+ \sa startStaticRender()
+*/
+
+/*!
\fn void QMapboxGL::mapChanged(QMapboxGL::MapChange change)
This signal is emitted when the state of the map has changed. This signal
@@ -1526,186 +1621,140 @@ void QMapboxGL::connectionEstablished()
\a copyrightsHtml is a string with a HTML snippet.
*/
-class QMapboxGLRendererFrontend;
-
-QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings, const QSize &size_, qreal pixelRatio)
+QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings, const QSize &size, qreal pixelRatio_)
: QObject(q)
- , size(size_)
- , q_ptr(q)
- , fileSourceObj(sharedDefaultFileSource(
+ , m_fileSourceObj(sharedDefaultFileSource(
settings.cacheDatabasePath().toStdString(),
settings.assetPath().toStdString(),
settings.cacheDatabaseMaximumSize()))
- , threadPool(mbgl::sharedThreadPool())
+ , m_threadPool(mbgl::sharedThreadPool())
+ , m_mode(settings.contextMode())
+ , m_pixelRatio(pixelRatio_)
{
- // Setup resource transform if needed
+ // Setup the FileSource
+ m_fileSourceObj->setAccessToken(settings.accessToken().toStdString());
+ m_fileSourceObj->setAPIBaseURL(settings.apiBaseUrl().toStdString());
+
if (settings.resourceTransform()) {
- m_resourceTransform =
- std::make_unique< mbgl::Actor<mbgl::ResourceTransform> >( *mbgl::Scheduler::GetCurrent(),
- [callback = settings.resourceTransform()]
- (mbgl::Resource::Kind , const std::string&& url_) -> std::string {
- return callback(std::move(url_));
- }
- );
- fileSourceObj->setResourceTransform(m_resourceTransform->self());
+ m_resourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::Scheduler::GetCurrent(),
+ [callback = settings.resourceTransform()] (mbgl::Resource::Kind, const std::string &&url_) -> std::string {
+ return callback(std::move(url_));
+ });
+ m_fileSourceObj->setResourceTransform(m_resourceTransform->self());
}
- // Setup and connect the renderer frontend
- frontend = std::make_unique<QMapboxGLRendererFrontend>(
- std::make_unique<mbgl::Renderer>(*this, pixelRatio, *fileSourceObj, *threadPool,
- static_cast<mbgl::GLContextMode>(settings.contextMode())),
- *this);
- connect(frontend.get(), SIGNAL(updated()), this, SLOT(invalidate()));
+ // Setup MapObserver
+ m_mapObserver = std::make_unique<QMapboxGLMapObserver>(this);
+
+ qRegisterMetaType<QMapboxGL::MapChange>("QMapboxGL::MapChange");
+
+ connect(m_mapObserver.get(), SIGNAL(mapChanged(QMapboxGL::MapChange)), q, SIGNAL(mapChanged(QMapboxGL::MapChange)));
+ connect(m_mapObserver.get(), SIGNAL(copyrightsChanged(QString)), q, SIGNAL(copyrightsChanged(QString)));
+ // Setup the Map object
mapObj = std::make_unique<mbgl::Map>(
- *frontend,
- *this, sanitizedSize(size),
- pixelRatio, *fileSourceObj, *threadPool,
- mbgl::MapMode::Continuous,
+ *this, // RendererFrontend
+ *m_mapObserver,
+ sanitizedSize(size),
+ m_pixelRatio, *m_fileSourceObj, *m_threadPool,
+ static_cast<mbgl::MapMode>(settings.mapMode()),
static_cast<mbgl::ConstrainMode>(settings.constrainMode()),
static_cast<mbgl::ViewportMode>(settings.viewportMode()));
- qRegisterMetaType<QMapboxGL::MapChange>("QMapboxGL::MapChange");
-
- fileSourceObj->setAccessToken(settings.accessToken().toStdString());
- fileSourceObj->setAPIBaseURL(settings.apiBaseUrl().toStdString());
-
- connect(this, SIGNAL(needsRendering()), q_ptr, SIGNAL(needsRendering()), Qt::QueuedConnection);
- connect(this, SIGNAL(mapChanged(QMapboxGL::MapChange)), q_ptr, SIGNAL(mapChanged(QMapboxGL::MapChange)), Qt::QueuedConnection);
- connect(this, SIGNAL(copyrightsChanged(QString)), q_ptr, SIGNAL(copyrightsChanged(QString)), Qt::QueuedConnection);
+ // Needs to be Queued to give time to discard redundant draw calls via the `renderQueued` flag.
+ connect(this, SIGNAL(needsRendering()), q, SIGNAL(needsRendering()), Qt::QueuedConnection);
}
QMapboxGLPrivate::~QMapboxGLPrivate()
{
}
-mbgl::Size QMapboxGLPrivate::getFramebufferSize() const {
- return sanitizedSize(fbSize);
-}
+void QMapboxGLPrivate::update(std::shared_ptr<mbgl::UpdateParameters> parameters)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
-void QMapboxGLPrivate::updateAssumedState() {
- assumeFramebufferBinding(fbObject);
-#if QT_VERSION >= 0x050600
- assumeViewport(0, 0, getFramebufferSize());
-#endif
-}
+ if (!m_mapRenderer) {
+ return;
+ }
-void QMapboxGLPrivate::bind() {
- setFramebufferBinding(fbObject);
- setViewport(0, 0, getFramebufferSize());
-}
+ m_mapRenderer->updateParameters(std::move(parameters));
-void QMapboxGLPrivate::invalidate()
-{
- if (!dirty) {
- emit needsRendering();
- dirty = true;
- }
+ requestRendering();
}
-void QMapboxGLPrivate::render()
+void QMapboxGLPrivate::setObserver(mbgl::RendererObserver &observer)
{
- frontend->render();
-}
+ m_rendererObserver = std::make_shared<QMapboxGLRendererObserver>(
+ *mbgl::util::RunLoop::Get(), observer);
-void QMapboxGLPrivate::onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode)
-{
- if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
- emit mapChanged(QMapboxGL::MapChangeRegionWillChange);
- } else {
- emit mapChanged(QMapboxGL::MapChangeRegionWillChangeAnimated);
+ std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
+
+ if (m_mapRenderer) {
+ m_mapRenderer->setObserver(m_rendererObserver);
}
}
-void QMapboxGLPrivate::onCameraIsChanging()
+void QMapboxGLPrivate::createRenderer()
{
- emit mapChanged(QMapboxGL::MapChangeRegionIsChanging);
-}
+ std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
-void QMapboxGLPrivate::onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode)
-{
- if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
- emit mapChanged(QMapboxGL::MapChangeRegionDidChange);
- } else {
- emit mapChanged(QMapboxGL::MapChangeRegionDidChangeAnimated);
+ if (m_mapRenderer) {
+ return;
}
-}
-void QMapboxGLPrivate::onWillStartLoadingMap()
-{
- emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
-}
+ m_mapRenderer = std::make_unique<QMapboxGLMapRenderer>(
+ m_pixelRatio,
+ *m_fileSourceObj,
+ *m_threadPool,
+ m_mode
+ );
-void QMapboxGLPrivate::onDidFinishLoadingMap()
-{
- emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingMap);
-}
+ connect(m_mapRenderer.get(), SIGNAL(needsRendering()), this, SLOT(requestRendering()));
-void QMapboxGLPrivate::onDidFailLoadingMap(std::exception_ptr)
-{
- emit mapChanged(QMapboxGL::MapChangeDidFailLoadingMap);
+ m_mapRenderer->setObserver(m_rendererObserver);
}
-void QMapboxGLPrivate::onWillStartRenderingFrame()
+void QMapboxGLPrivate::destroyRenderer()
{
- emit mapChanged(QMapboxGL::MapChangeWillStartRenderingFrame);
-}
+ std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
-void QMapboxGLPrivate::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode)
-{
- if (mode == mbgl::MapObserver::RenderMode::Partial) {
- emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrame);
- } else {
- emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrameFullyRendered);
- }
+ m_mapRenderer.reset();
}
-void QMapboxGLPrivate::onWillStartRenderingMap()
+void QMapboxGLPrivate::render()
{
- emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
-}
+ std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
-void QMapboxGLPrivate::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode)
-{
- if (mode == mbgl::MapObserver::RenderMode::Partial) {
- emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMap);
- } else {
- emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMapFullyRendered);
+ if (!m_mapRenderer) {
+ createRenderer();
}
-}
-void QMapboxGLPrivate::onDidFinishLoadingStyle()
-{
- emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingStyle);
+#if defined(__APPLE__) && QT_VERSION < 0x050000
+ // FIXME Qt 4.x provides an incomplete FBO at start.
+ // See https://bugreports.qt.io/browse/QTBUG-36802 for details.
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ return;
+ }
+#endif
+
+ m_renderQueued.clear();
+ m_mapRenderer->render();
}
-void QMapboxGLPrivate::onSourceChanged(mbgl::style::Source&)
+void QMapboxGLPrivate::setFramebufferObject(quint32 fbo, const QSize& size)
{
- std::string attribution;
- for (const auto& source : mapObj->getStyle().getSources()) {
- // Avoid duplicates by using the most complete attribution HTML snippet.
- if (source->getAttribution() && (attribution.size() < source->getAttribution()->size()))
- attribution = *source->getAttribution();
+ std::lock_guard<std::recursive_mutex> lock(m_mapRendererMutex);
+
+ if (!m_mapRenderer) {
+ createRenderer();
}
- emit copyrightsChanged(QString::fromStdString(attribution));
- emit mapChanged(QMapboxGL::MapChangeSourceDidChange);
-}
-/*!
- Initializes an OpenGL extension function such as Vertex Array Objects (VAOs),
- required by Mapbox GL Native engine.
-*/
-mbgl::gl::ProcAddress QMapboxGLPrivate::getExtensionFunctionPointer(const char* name) {
-#if QT_VERSION >= 0x050000
- QOpenGLContext* thisContext = QOpenGLContext::currentContext();
- return thisContext->getProcAddress(name);
-#else
- const QGLContext* thisContext = QGLContext::currentContext();
- return reinterpret_cast<mbgl::gl::ProcAddress>(thisContext->getProcAddress(name));
-#endif
+ m_mapRenderer->updateFramebuffer(fbo, sanitizedSize(size));
}
-void QMapboxGLPrivate::connectionEstablished()
+void QMapboxGLPrivate::requestRendering()
{
- mbgl::NetworkStatus::Reachable();
+ if (!m_renderQueued.test_and_set()) {
+ emit needsRendering();
+ }
}
diff --git a/platform/qt/src/qmapboxgl_map_observer.cpp b/platform/qt/src/qmapboxgl_map_observer.cpp
new file mode 100644
index 0000000000..e180ed8fda
--- /dev/null
+++ b/platform/qt/src/qmapboxgl_map_observer.cpp
@@ -0,0 +1,95 @@
+#include "qmapboxgl_map_observer.hpp"
+
+#include "qmapboxgl_p.hpp"
+
+QMapboxGLMapObserver::QMapboxGLMapObserver(QMapboxGLPrivate *d)
+ : d_ptr(d)
+{
+}
+
+QMapboxGLMapObserver::~QMapboxGLMapObserver()
+{
+}
+
+void QMapboxGLMapObserver::onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode)
+{
+ if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
+ emit mapChanged(QMapboxGL::MapChangeRegionWillChange);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeRegionWillChangeAnimated);
+ }
+}
+
+void QMapboxGLMapObserver::onCameraIsChanging()
+{
+ emit mapChanged(QMapboxGL::MapChangeRegionIsChanging);
+}
+
+void QMapboxGLMapObserver::onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode)
+{
+ if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
+ emit mapChanged(QMapboxGL::MapChangeRegionDidChange);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeRegionDidChangeAnimated);
+ }
+}
+
+void QMapboxGLMapObserver::onWillStartLoadingMap()
+{
+ emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
+}
+
+void QMapboxGLMapObserver::onDidFinishLoadingMap()
+{
+ emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingMap);
+}
+
+void QMapboxGLMapObserver::onDidFailLoadingMap(std::exception_ptr)
+{
+ emit mapChanged(QMapboxGL::MapChangeDidFailLoadingMap);
+}
+
+void QMapboxGLMapObserver::onWillStartRenderingFrame()
+{
+ emit mapChanged(QMapboxGL::MapChangeWillStartRenderingFrame);
+}
+
+void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode)
+{
+ if (mode == mbgl::MapObserver::RenderMode::Partial) {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrame);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrameFullyRendered);
+ }
+}
+
+void QMapboxGLMapObserver::onWillStartRenderingMap()
+{
+ emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
+}
+
+void QMapboxGLMapObserver::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode)
+{
+ if (mode == mbgl::MapObserver::RenderMode::Partial) {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMap);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMapFullyRendered);
+ }
+}
+
+void QMapboxGLMapObserver::onDidFinishLoadingStyle()
+{
+ emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingStyle);
+}
+
+void QMapboxGLMapObserver::onSourceChanged(mbgl::style::Source&)
+{
+ std::string attribution;
+ for (const auto& source : d_ptr->mapObj->getStyle().getSources()) {
+ // Avoid duplicates by using the most complete attribution HTML snippet.
+ if (source->getAttribution() && (attribution.size() < source->getAttribution()->size()))
+ attribution = *source->getAttribution();
+ }
+ emit copyrightsChanged(QString::fromStdString(attribution));
+ emit mapChanged(QMapboxGL::MapChangeSourceDidChange);
+}
diff --git a/platform/qt/src/qmapboxgl_map_observer.hpp b/platform/qt/src/qmapboxgl_map_observer.hpp
new file mode 100644
index 0000000000..c9d0581a90
--- /dev/null
+++ b/platform/qt/src/qmapboxgl_map_observer.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "qmapboxgl.hpp"
+
+#include <mbgl/map/map_observer.hpp>
+#include <mbgl/style/style.hpp>
+
+#include <QObject>
+
+#include <exception>
+#include <memory>
+
+class QMapboxGLPrivate;
+
+class QMapboxGLMapObserver : public QObject, public mbgl::MapObserver
+{
+ Q_OBJECT
+
+public:
+ explicit QMapboxGLMapObserver(QMapboxGLPrivate *);
+ virtual ~QMapboxGLMapObserver();
+
+ // mbgl::MapObserver implementation.
+ void onCameraWillChange(mbgl::MapObserver::CameraChangeMode) final;
+ void onCameraIsChanging() final;
+ void onCameraDidChange(mbgl::MapObserver::CameraChangeMode) final;
+ void onWillStartLoadingMap() final;
+ void onDidFinishLoadingMap() final;
+ void onDidFailLoadingMap(std::exception_ptr) final;
+ void onWillStartRenderingFrame() final;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) final;
+ void onWillStartRenderingMap() final;
+ void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) final;
+ void onDidFinishLoadingStyle() final;
+ void onSourceChanged(mbgl::style::Source&) final;
+
+signals:
+ void mapChanged(QMapboxGL::MapChange);
+ void copyrightsChanged(const QString &copyrightsHtml);
+
+private:
+ Q_DISABLE_COPY(QMapboxGLMapObserver)
+
+ QMapboxGLPrivate *d_ptr;
+};
diff --git a/platform/qt/src/qmapboxgl_map_renderer.cpp b/platform/qt/src/qmapboxgl_map_renderer.cpp
new file mode 100644
index 0000000000..7a9d1f6f78
--- /dev/null
+++ b/platform/qt/src/qmapboxgl_map_renderer.cpp
@@ -0,0 +1,86 @@
+#include "qmapboxgl_map_renderer.hpp"
+
+#include <QtGlobal>
+
+QMapboxGLMapRenderer::QMapboxGLMapRenderer(qreal pixelRatio,
+ mbgl::DefaultFileSource &fs, mbgl::ThreadPool &tp, QMapboxGLSettings::GLContextMode mode)
+ : m_renderer(std::make_unique<mbgl::Renderer>(m_backend, pixelRatio, fs, tp, static_cast<mbgl::GLContextMode>(mode)))
+ , m_threadWithScheduler(Scheduler::GetCurrent() != nullptr)
+{
+}
+
+QMapboxGLMapRenderer::~QMapboxGLMapRenderer()
+{
+ MBGL_VERIFY_THREAD(tid);
+}
+
+void QMapboxGLMapRenderer::schedule(std::weak_ptr<mbgl::Mailbox> mailbox)
+{
+ std::lock_guard<std::mutex> 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<mbgl::UpdateParameters> newParameters)
+{
+ std::lock_guard<std::mutex> lock(m_updateMutex);
+ m_updateParameters = std::move(newParameters);
+}
+
+void QMapboxGLMapRenderer::updateFramebuffer(quint32 fbo, const mbgl::Size &size)
+{
+ MBGL_VERIFY_THREAD(tid);
+
+ m_backend.updateFramebuffer(fbo, size);
+}
+
+void QMapboxGLMapRenderer::render()
+{
+ MBGL_VERIFY_THREAD(tid);
+
+ std::shared_ptr<mbgl::UpdateParameters> params;
+ {
+ // Lock on the parameters
+ std::lock_guard<std::mutex> lock(m_updateMutex);
+
+ if (!m_updateParameters) {
+ return;
+ }
+
+ // Hold on to the update parameters during render
+ params = m_updateParameters;
+ }
+
+ // 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<std::weak_ptr<mbgl::Mailbox>> taskQueue;
+ {
+ std::unique_lock<std::mutex> lock(m_taskQueueMutex);
+ std::swap(taskQueue, m_taskQueue);
+ }
+
+ while (!taskQueue.empty()) {
+ mbgl::Mailbox::maybeReceive(taskQueue.front());
+ taskQueue.pop();
+ }
+ }
+}
+
+void QMapboxGLMapRenderer::setObserver(std::shared_ptr<mbgl::RendererObserver> observer)
+{
+ m_renderer->setObserver(observer.get());
+}
diff --git a/platform/qt/src/qmapboxgl_map_renderer.hpp b/platform/qt/src/qmapboxgl_map_renderer.hpp
new file mode 100644
index 0000000000..adba11de51
--- /dev/null
+++ b/platform/qt/src/qmapboxgl_map_renderer.hpp
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "qmapboxgl.hpp"
+#include "qmapboxgl_renderer_backend.hpp"
+
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/renderer/renderer_observer.hpp>
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
+#include <mbgl/util/util.hpp>
+
+#include <QtGlobal>
+
+#include <memory>
+#include <mutex>
+#include <queue>
+
+namespace mbgl {
+class Renderer;
+class UpdateParameters;
+} // namespace mbgl
+
+class QMapboxGLRendererBackend;
+
+class QMapboxGLMapRenderer : public QObject, public mbgl::Scheduler
+{
+ Q_OBJECT
+
+public:
+ QMapboxGLMapRenderer(qreal pixelRatio, mbgl::DefaultFileSource &,
+ mbgl::ThreadPool &, QMapboxGLSettings::GLContextMode);
+ virtual ~QMapboxGLMapRenderer();
+
+ // mbgl::Scheduler implementation.
+ void schedule(std::weak_ptr<mbgl::Mailbox> scheduled) final;
+
+ void render();
+ void updateFramebuffer(quint32 fbo, const mbgl::Size &size);
+ void setObserver(std::shared_ptr<mbgl::RendererObserver>);
+
+ // Thread-safe, called by the Frontend
+ void updateParameters(std::shared_ptr<mbgl::UpdateParameters>);
+
+signals:
+ void needsRendering();
+
+private:
+ MBGL_STORE_THREAD(tid)
+
+ Q_DISABLE_COPY(QMapboxGLMapRenderer)
+
+ std::mutex m_updateMutex;
+ std::shared_ptr<mbgl::UpdateParameters> m_updateParameters;
+
+ QMapboxGLRendererBackend m_backend;
+ std::unique_ptr<mbgl::Renderer> m_renderer;
+
+ std::mutex m_taskQueueMutex;
+ std::queue<std::weak_ptr<mbgl::Mailbox>> m_taskQueue;
+
+ bool m_threadWithScheduler;
+};
diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp
index f947c09f48..51c7cb8fc4 100644
--- a/platform/qt/src/qmapboxgl_p.hpp
+++ b/platform/qt/src/qmapboxgl_p.hpp
@@ -1,22 +1,24 @@
#pragma once
#include "qmapboxgl.hpp"
-#include "qmapboxgl_renderer_frontend_p.hpp"
+#include "qmapboxgl_map_observer.hpp"
+#include "qmapboxgl_map_renderer.hpp"
#include <mbgl/actor/actor.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/renderer/renderer_backend.hpp>
-#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/renderer/renderer_frontend.hpp>
#include <mbgl/storage/default_file_source.hpp>
-#include <mbgl/util/geo.hpp>
#include <mbgl/storage/resource_transform.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/geo.hpp>
#include <QObject>
#include <QSize>
+#include <atomic>
#include <memory>
-class QMapboxGLPrivate : public QObject, public mbgl::RendererBackend, public mbgl::MapObserver
+class QMapboxGLPrivate : public QObject, public mbgl::RendererFrontend
{
Q_OBJECT
@@ -24,55 +26,40 @@ public:
explicit QMapboxGLPrivate(QMapboxGL *, const QMapboxGLSettings &, const QSize &size, qreal pixelRatio);
virtual ~QMapboxGLPrivate();
+ // mbgl::RendererFrontend implementation.
+ void reset() final {}
+ void setObserver(mbgl::RendererObserver &) final;
+ void update(std::shared_ptr<mbgl::UpdateParameters>) final;
- // mbgl::RendererBackend implementation.
- void bind() final;
- mbgl::Size getFramebufferSize() const final;
- void updateAssumedState() final;
- void activate() final {}
- void deactivate() final {}
-
- // mbgl::MapObserver implementation.
- void onCameraWillChange(mbgl::MapObserver::CameraChangeMode) final;
- void onCameraIsChanging() final;
- void onCameraDidChange(mbgl::MapObserver::CameraChangeMode) final;
- void onWillStartLoadingMap() final;
- void onDidFinishLoadingMap() final;
- void onDidFailLoadingMap(std::exception_ptr) final;
- void onWillStartRenderingFrame() final;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) final;
- void onWillStartRenderingMap() final;
- void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) final;
- void onDidFinishLoadingStyle() final;
- void onSourceChanged(mbgl::style::Source&) final;
+ // These need to be called on the same thread.
+ void createRenderer();
+ void destroyRenderer();
+ void render();
+ void setFramebufferObject(quint32 fbo, const QSize& size);
mbgl::EdgeInsets margins;
- QSize size { 0, 0 };
- QSize fbSize { 0, 0 };
- quint32 fbObject = 0;
-
- QMapboxGL *q_ptr { nullptr };
-
- std::shared_ptr<mbgl::DefaultFileSource> fileSourceObj;
- std::shared_ptr<mbgl::ThreadPool> threadPool;
- std::unique_ptr<QMapboxGLRendererFrontend> frontend;
std::unique_ptr<mbgl::Map> mapObj;
- bool dirty { false };
-
-private:
- mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) override;
-
public slots:
- void connectionEstablished();
- void invalidate();
- void render();
+ void requestRendering();
signals:
void needsRendering();
- void mapChanged(QMapboxGL::MapChange);
- void copyrightsChanged(const QString &copyrightsHtml);
private:
- std::unique_ptr< mbgl::Actor<mbgl::ResourceTransform> > m_resourceTransform;
+ Q_DISABLE_COPY(QMapboxGLPrivate)
+
+ std::recursive_mutex m_mapRendererMutex;
+ std::shared_ptr<mbgl::RendererObserver> m_rendererObserver;
+
+ std::unique_ptr<QMapboxGLMapObserver> m_mapObserver;
+ std::shared_ptr<mbgl::DefaultFileSource> m_fileSourceObj;
+ std::shared_ptr<mbgl::ThreadPool> m_threadPool;
+ std::unique_ptr<QMapboxGLMapRenderer> m_mapRenderer;
+ std::unique_ptr<mbgl::Actor<mbgl::ResourceTransform>> m_resourceTransform;
+
+ QMapboxGLSettings::GLContextMode m_mode;
+ qreal m_pixelRatio;
+
+ std::atomic_flag m_renderQueued = ATOMIC_FLAG_INIT;
};
diff --git a/platform/qt/src/qmapboxgl_renderer_backend.cpp b/platform/qt/src/qmapboxgl_renderer_backend.cpp
new file mode 100644
index 0000000000..917741f5ce
--- /dev/null
+++ b/platform/qt/src/qmapboxgl_renderer_backend.cpp
@@ -0,0 +1,49 @@
+#include "qmapboxgl_renderer_backend.hpp"
+
+#include <QtGlobal>
+
+#if QT_VERSION >= 0x050000
+#include <QOpenGLContext>
+#else
+#include <QGLContext>
+#endif
+
+void QMapboxGLRendererBackend::updateAssumedState()
+{
+ assumeFramebufferBinding(ImplicitFramebufferBinding);
+ assumeViewport(0, 0, m_size);
+}
+
+void QMapboxGLRendererBackend::bind()
+{
+ assert(mbgl::BackendScope::exists());
+
+ setFramebufferBinding(m_fbo);
+ setViewport(0, 0, m_size);
+}
+
+mbgl::Size QMapboxGLRendererBackend::getFramebufferSize() const
+{
+ return m_size;
+}
+
+void QMapboxGLRendererBackend::updateFramebuffer(quint32 fbo, const mbgl::Size &size)
+{
+ m_fbo = fbo;
+ m_size = size;
+}
+
+/*!
+ Initializes an OpenGL extension function such as Vertex Array Objects (VAOs),
+ required by Mapbox GL Native engine.
+*/
+mbgl::gl::ProcAddress QMapboxGLRendererBackend::getExtensionFunctionPointer(const char* name)
+{
+#if QT_VERSION >= 0x050000
+ QOpenGLContext* thisContext = QOpenGLContext::currentContext();
+ return thisContext->getProcAddress(name);
+#else
+ const QGLContext* thisContext = QGLContext::currentContext();
+ return reinterpret_cast<mbgl::gl::ProcAddress>(thisContext->getProcAddress(name));
+#endif
+}
diff --git a/platform/qt/src/qmapboxgl_renderer_backend.hpp b/platform/qt/src/qmapboxgl_renderer_backend.hpp
new file mode 100644
index 0000000000..de66b035fc
--- /dev/null
+++ b/platform/qt/src/qmapboxgl_renderer_backend.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "qmapboxgl.hpp"
+
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
+
+class QMapboxGLRendererBackend : public mbgl::RendererBackend
+{
+public:
+ QMapboxGLRendererBackend() = default;
+ virtual ~QMapboxGLRendererBackend() = default;
+
+ // mbgl::RendererBackend implementation
+ void updateAssumedState() final;
+ void bind() final;
+ mbgl::Size getFramebufferSize() const final;
+
+ void updateFramebuffer(quint32 fbo, const mbgl::Size &);
+
+protected:
+ mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) final;
+
+ // No-op, implicit mode.
+ void activate() final {}
+ void deactivate() final {}
+
+private:
+ quint32 m_fbo = 0;
+ mbgl::Size m_size = { 0, 0 };
+
+ Q_DISABLE_COPY(QMapboxGLRendererBackend)
+};
diff --git a/platform/qt/src/qmapboxgl_renderer_frontend_p.cpp b/platform/qt/src/qmapboxgl_renderer_frontend_p.cpp
deleted file mode 100644
index ea60851eb4..0000000000
--- a/platform/qt/src/qmapboxgl_renderer_frontend_p.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "qmapboxgl_renderer_frontend_p.hpp"
-
-#include <mbgl/renderer/backend_scope.hpp>
-#include <mbgl/renderer/renderer.hpp>
-
-QMapboxGLRendererFrontend::QMapboxGLRendererFrontend(std::unique_ptr<mbgl::Renderer> renderer_, mbgl::RendererBackend& backend_)
- : renderer(std::move(renderer_))
- , backend(backend_) {
-}
-
-QMapboxGLRendererFrontend::~QMapboxGLRendererFrontend() = default;
-
-void QMapboxGLRendererFrontend::reset() {
- if (renderer) {
- renderer.reset();
- }
-}
-
-void QMapboxGLRendererFrontend::update(std::shared_ptr<mbgl::UpdateParameters> updateParameters_) {
- updateParameters = updateParameters_;
- emit updated();
-}
-
-void QMapboxGLRendererFrontend::setObserver(mbgl::RendererObserver& observer_) {
- if (!renderer) return;
-
- renderer->setObserver(&observer_);
-}
-
-void QMapboxGLRendererFrontend::render() {
- if (!renderer || !updateParameters) return;
-
- // The OpenGL implementation automatically enables the OpenGL context for us.
- mbgl::BackendScope scope { backend, mbgl::BackendScope::ScopeType::Implicit };
-
- renderer->render(*updateParameters);
-}
diff --git a/platform/qt/src/qmapboxgl_renderer_frontend_p.hpp b/platform/qt/src/qmapboxgl_renderer_frontend_p.hpp
deleted file mode 100644
index c5e2bacc34..0000000000
--- a/platform/qt/src/qmapboxgl_renderer_frontend_p.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-#include <mbgl/renderer/renderer_backend.hpp>
-#include <mbgl/renderer/renderer_frontend.hpp>
-
-#include <QObject>
-
-namespace mbgl {
- class Renderer;
-} // namespace mbgl
-
-class QMapboxGLRendererFrontend : public QObject, public mbgl::RendererFrontend
-{
- Q_OBJECT
-
-public:
- explicit QMapboxGLRendererFrontend(std::unique_ptr<mbgl::Renderer>, mbgl::RendererBackend&);
- ~QMapboxGLRendererFrontend() override;
-
- void reset() override;
- void setObserver(mbgl::RendererObserver&) override;
-
- void update(std::shared_ptr<mbgl::UpdateParameters>) override;
-
-public slots:
- void render();
-
-signals:
- void updated();
-
-private:
- std::unique_ptr<mbgl::Renderer> renderer;
- mbgl::RendererBackend& backend;
- std::shared_ptr<mbgl::UpdateParameters> updateParameters;
-};
diff --git a/platform/qt/src/qmapboxgl_renderer_observer.hpp b/platform/qt/src/qmapboxgl_renderer_observer.hpp
new file mode 100644
index 0000000000..ee340113ff
--- /dev/null
+++ b/platform/qt/src/qmapboxgl_renderer_observer.hpp
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/actor/actor_ref.hpp>
+#include <mbgl/actor/mailbox.hpp>
+#include <mbgl/renderer/renderer_observer.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+#include <memory>
+
+// 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<mbgl::Mailbox>(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<mbgl::Mailbox> mailbox;
+ mbgl::ActorRef<mbgl::RendererObserver> delegate;
+};
diff --git a/platform/qt/src/qt_logging.cpp b/platform/qt/src/qt_logging.cpp
index acbe9562d0..acbe9562d0 100755..100644
--- a/platform/qt/src/qt_logging.cpp
+++ b/platform/qt/src/qt_logging.cpp
diff --git a/platform/qt/test/qmapboxgl.test.cpp b/platform/qt/test/qmapboxgl.test.cpp
index 932460b932..2a56b346a3 100644
--- a/platform/qt/test/qmapboxgl.test.cpp
+++ b/platform/qt/test/qmapboxgl.test.cpp
@@ -15,8 +15,8 @@ QMapboxGLTest::QMapboxGLTest() : size(512, 512), fbo((assert(widget.context()->i
this, SLOT(onMapChanged(QMapboxGL::MapChange)));
connect(&map, SIGNAL(needsRendering()),
this, SLOT(onNeedsRendering()));
- map.resize(fbo.size(), fbo.size());
- map.setFramebufferObject(fbo.handle());
+ map.resize(fbo.size());
+ map.setFramebufferObject(fbo.handle(), fbo.size());
map.setCoordinateZoom(QMapbox::Coordinate(60.170448, 24.942046), 14);
}