diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2014-11-16 15:31:12 +0000 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2014-11-17 18:35:52 +0100 |
commit | 5b8966e089016d18d69d6081eba685b5524799dc (patch) | |
tree | 868755ba15422d5ded7e561f771a07e0f0e857bf /src/render/backend/qrenderaspect.cpp | |
parent | b176000312983703f19262664471ccbd3305c259 (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.cpp | 38 |
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() |