summaryrefslogtreecommitdiffstats
path: root/src/render/backend/qrenderaspect.cpp
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2014-11-16 15:31:12 +0000
committerSean Harmer <sean.harmer@kdab.com>2014-11-17 18:35:52 +0100
commit5b8966e089016d18d69d6081eba685b5524799dc (patch)
tree868755ba15422d5ded7e561f771a07e0f0e857bf /src/render/backend/qrenderaspect.cpp
parentb176000312983703f19262664471ccbd3305c259 (diff)
Cleanly exit the render thread
We have to mutex protect accesses to the m_surface variable in the Renderer as the main thread may call destroy() on the corresponding QWindow. This can happen in response to the window being closed or changing QScreens. Calling swapBuffers() on a QSurface that has been destroyed does not fail gracefully but crashes. This change works around this by using the new QPlatformSurfaceEvent in QtGui which is sent to the window or offsceen surface when the platform surface has been created or is about to be destroyed. This event is used to inform the renderer to stop rendering to the window surface in a safe manner, before the native surface gets destroyed. The Renderer::submitRenderViews() now checks at the start of each frame that the m_surface is still valid. There is still another crash at shutdown if applications are sending a lot of updates to the backend. Change-Id: I742226c7ae8f657e218cbcd45f0dff3d2b7bcc18 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/render/backend/qrenderaspect.cpp')
-rw-r--r--src/render/backend/qrenderaspect.cpp38
1 files changed, 37 insertions, 1 deletions
diff --git a/src/render/backend/qrenderaspect.cpp b/src/render/backend/qrenderaspect.cpp
index af2961578..2b4418b67 100644
--- a/src/render/backend/qrenderaspect.cpp
+++ b/src/render/backend/qrenderaspect.cpp
@@ -98,6 +98,7 @@
#include <Qt3DCore/private/qaspectmanager_p.h>
#include <QDebug>
+#include <QOffscreenSurface>
#include <QThread>
#include <QWindow>
@@ -108,11 +109,46 @@ namespace Qt3D {
QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect *qq)
: QAbstractAspectPrivate(qq)
, m_renderer(new Render::Renderer)
+ , m_surfaceEventFilter(new Render::PlatformSurfaceFilter(m_renderer))
, m_initialized(false)
{
m_aspectType = QAbstractAspect::AspectRenderer;
}
+void QRenderAspectPrivate::setSurface(QSurface *surface)
+{
+ if (m_surface == surface)
+ return;
+
+ m_surface = surface;
+
+ // If we have a new surface, install the platform surface event filter onto it
+ // so that we get informed when the underlying platform surface is about to be
+ // deleted and we can tell the renderer about it before it's too late.
+ if (m_surface) {
+ bool hasPlatformSurface = false;
+ switch (m_surface->surfaceClass()) {
+ case QSurface::Window: {
+ QWindow *window = static_cast<QWindow *>(m_surface);
+ m_surfaceEventFilter->setWindow(window);
+ hasPlatformSurface = (window->handle() != Q_NULLPTR);
+ break;
+ }
+
+ case QSurface::Offscreen: {
+ QOffscreenSurface *offscreen = static_cast<QOffscreenSurface *>(m_surface);
+ m_surfaceEventFilter->setOffscreenSurface(offscreen);
+ hasPlatformSurface = (offscreen->handle() != Q_NULLPTR);
+ break;
+ }
+ }
+
+ // If the window/offscreen surface has a native surface, tell the renderer
+ if (hasPlatformSurface)
+ m_renderer->setSurface(surface);
+ }
+}
+
QRenderAspect::QRenderAspect(QObject *parent)
: QAbstractAspect(*new QRenderAspectPrivate(this), parent)
{
@@ -252,7 +288,7 @@ void QRenderAspect::onInitialize(const QVariantMap &data)
surface = v.value<QSurface *>();
if (surface)
- d->m_renderer->setSurface(surface);
+ d->setSurface(surface);
}
void QRenderAspect::onCleanup()