aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@digia.com>2013-12-04 10:20:22 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-12-04 11:00:49 +0100
commit5006158e4d20ac35d64bc7a581c9966401254002 (patch)
treebef40980611b83630d608278362d168f13fada7e /src/quick
parent568c575b97940e6afa5015ef2566d8316aa22cd8 (diff)
Don't leave the GL context current after cleanup.
When shutting down, we left the gl context current on the window even when it was hidden. On mac this was a problem as it would optimize away our makeCurrent when the surface was made visible again, leading to nothing being rendered. So we call doneCurrent regardless during invalidateGL(). We also check and verify that makeCurrent in invalidateGL() actually succeeds. This lead to another problem which is that closing the app using [x] will call QWindow::destroy() on all windows, removing their platform windows and causing makeCurrent to fail. To still gracefully clean up resources, we introduced the concept of an offscreen fallback surface which is temporarirly used during the cleanup when needed. The problem is still present on QWindow+QOpenGLContext level, and I've opened QTBUG-35363 to fix this. Task-number: QTBUG-35234 Change-Id: Ie76dbe5fd4ab935db3da34f3ff63d217a3ba5013 Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp52
1 files changed, 34 insertions, 18 deletions
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index acd07cf6cd..d6a3881086 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -48,6 +48,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
+#include <QtGui/QOffscreenSurface>
#include <QtQuick/QQuickWindow>
#include <private/qquickwindow_p.h>
@@ -205,12 +206,14 @@ public:
class WMTryReleaseEvent : public WMWindowEvent
{
public:
- WMTryReleaseEvent(QQuickWindow *win, bool destroy)
+ WMTryReleaseEvent(QQuickWindow *win, bool destroy, QOffscreenSurface *fallback)
: WMWindowEvent(win, WM_TryRelease)
, inDestructor(destroy)
+ , fallbackSurface(fallback)
{}
bool inDestructor;
+ QOffscreenSurface *fallbackSurface;
};
class WMExposeEvent : public WMWindowEvent
@@ -295,7 +298,7 @@ public:
delete sgrc;
}
- void invalidateOpenGL(QQuickWindow *window, bool inDestructor);
+ void invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *backupSurface);
void initializeOpenGL();
bool event(QEvent *);
@@ -362,17 +365,9 @@ bool QSGRenderThread::event(QEvent *e)
case WM_Expose: {
QSG_RT_DEBUG("WM_Expose");
WMExposeEvent *se = static_cast<WMExposeEvent *>(e);
-
- pendingUpdate |= RepaintRequest;
-
Q_ASSERT(!window || window == se->window);
-
+ pendingUpdate |= RepaintRequest;
windowSize = se->size;
- if (window) {
- QSG_RT_DEBUG(" - window already added...");
- return true;
- }
-
window = se->window;
return true; }
@@ -383,7 +378,7 @@ bool QSGRenderThread::event(QEvent *e)
mutex.lock();
if (window) {
- QSG_RT_DEBUG(" - removed one...");
+ QSG_RT_DEBUG(" - removed window...");
window = 0;
}
waitCondition.wakeOne();
@@ -405,7 +400,7 @@ bool QSGRenderThread::event(QEvent *e)
WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
if (!window || wme->inDestructor) {
QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
- invalidateOpenGL(wme->window, wme->inDestructor);
+ invalidateOpenGL(wme->window, wme->inDestructor, wme->fallbackSurface);
active = gl;
if (sleeping)
stopEventProcessing = true;
@@ -453,7 +448,7 @@ bool QSGRenderThread::event(QEvent *e)
return QThread::event(e);
}
-void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
+void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *fallback)
{
QSG_RT_DEBUG("invalidateOpenGL()");
@@ -469,7 +464,13 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
bool wipeSG = inDestructor || !window->isPersistentSceneGraph();
bool wipeGL = inDestructor || (wipeSG && !window->isPersistentOpenGLContext());
- gl->makeCurrent(window);
+ bool current = gl->makeCurrent(fallback ? static_cast<QSurface *>(fallback) : static_cast<QSurface *>(window));
+ if (!current) {
+#ifndef QT_NO_DEBUG
+ qWarning() << "Scene Graph failed to acquire GL context during cleanup";
+#endif
+ return;
+ }
// The canvas nodes must be cleaned up regardless if we are in the destructor..
if (wipeSG) {
@@ -477,6 +478,7 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
dd->cleanupNodesOnShutdown();
} else {
QSG_RT_DEBUG(" - persistent SG, avoiding cleanup");
+ gl->doneCurrent();
return;
}
@@ -510,7 +512,6 @@ void QSGRenderThread::sync()
if (windowSize.width() > 0 && windowSize.height() > 0)
current = gl->makeCurrent(window);
if (current) {
- gl->makeCurrent(window);
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool hadRenderer = d->renderer != 0;
d->syncSceneGraph();
@@ -528,7 +529,6 @@ void QSGRenderThread::sync()
QSG_RT_DEBUG(" - window has bad size, waiting...");
}
- QSG_RT_DEBUG(" - window has bad size, waiting...");
waitCondition.wakeOne();
mutex.unlock();
}
@@ -1036,9 +1036,25 @@ void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestru
w->thread->mutex.lock();
if (w->thread->isRunning() && w->thread->active) {
+
+ // The platform window might have been destroyed before
+ // hide/release/windowDestroyed is called, so we need to have a
+ // fallback surface to perform the cleanup of the scene graph
+ // and the OpenGL resources.
+ // QOffscreenSurface must be created on the GUI thread, so we
+ // create it here and pass it on to QSGRenderThread::invalidateGL()
+ QOffscreenSurface *fallback = 0;
+ if (!window->handle()) {
+ QSG_GUI_DEBUG(w->window, " - using fallback surface");
+ fallback = new QOffscreenSurface();
+ fallback->create();
+ }
+
QSG_GUI_DEBUG(w->window, " - posting release request to render thread");
- w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor));
+ w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor, fallback));
w->thread->waitCondition.wait(&w->thread->mutex);
+
+ delete fallback;
}
w->thread->mutex.unlock();
}