Support shutting down the render thread without an OpenGL context.
authorGunnar Sletta <gunnar.sletta@jollamobile.com>
Fri, 11 Apr 2014 14:21:54 +0000 (16:21 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 23 Apr 2014 07:10:18 +0000 (09:10 +0200)
[ChangeLog][QtQuick][SceneGraph] There might not be an OpenGL context
bound when QQuickWindow::sceneGraphInvalidated() is emitted if an
error occurs while cleaning up the scene graph (such as
EGL_CONTEXT_LOST). This is according to the documentation, but has
never occurred in practice before.

Change-Id: I13dbfbb4b6d0d27fa42fcb8b54df16ea02284807
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
src/quick/scenegraph/qsgthreadedrenderloop.cpp
src/quick/scenegraph/util/qsgatlastexture.cpp

index 04f2bc8..791e06e 100644 (file)
@@ -836,10 +836,12 @@ static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs)
 
 Renderer::~Renderer()
 {
-    // Clean up batches and buffers
-    for (int i=0; i<m_opaqueBatches.size(); ++i) qsg_wipeBatch(m_opaqueBatches.at(i), this);
-    for (int i=0; i<m_alphaBatches.size(); ++i) qsg_wipeBatch(m_alphaBatches.at(i), this);
-    for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this);
+    if (QOpenGLContext::currentContext()) {
+        // Clean up batches and buffers
+        for (int i=0; i<m_opaqueBatches.size(); ++i) qsg_wipeBatch(m_opaqueBatches.at(i), this);
+        for (int i=0; i<m_alphaBatches.size(); ++i) qsg_wipeBatch(m_alphaBatches.at(i), this);
+        for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this);
+    }
 
     // The shadowtree
     qDeleteAll(m_nodes.values());
index 2135bbe..7b01f64 100644 (file)
@@ -398,6 +398,7 @@ bool QSGRenderThread::event(QEvent *e)
             QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
             invalidateOpenGL(wme->window, wme->inDestructor, wme->fallbackSurface);
             active = gl;
+            Q_ASSERT_X(!wme->inDestructor || !active, "QSGRenderThread::invalidateOpenGL()", "Thread's active state is not set to false when shutting down");
             if (sleeping)
                 stopEventProcessing = true;
         } else {
@@ -462,11 +463,8 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor,
     bool wipeGL = inDestructor || (wipeSG && !window->isPersistentOpenGLContext());
 
     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;
+    if (Q_UNLIKELY(!current)) {
+        QSG_RT_DEBUG(" - cleanup without an OpenGL context");
     }
 
     // The canvas nodes must be cleaned up regardless if we are in the destructor..
@@ -475,14 +473,16 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor,
         dd->cleanupNodesOnShutdown();
     } else {
         QSG_RT_DEBUG(" - persistent SG, avoiding cleanup");
-        gl->doneCurrent();
+        if (current)
+            gl->doneCurrent();
         return;
     }
 
     sgrc->invalidate();
     QCoreApplication::processEvents();
     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
-    gl->doneCurrent();
+    if (current)
+        gl->doneCurrent();
     QSG_RT_DEBUG(" - invalidated scenegraph..");
 
     if (wipeGL) {
index 997d58d..99d1d60 100644 (file)
@@ -185,11 +185,9 @@ Atlas::~Atlas()
 
 void Atlas::invalidate()
 {
-    Q_ASSERT(QOpenGLContext::currentContext());
-    if (m_texture_id) {
+    if (m_texture_id && QOpenGLContext::currentContext())
         glDeleteTextures(1, &m_texture_id);
-        m_texture_id = 0;
-    }
+    m_texture_id = 0;
 }
 
 Texture *Atlas::create(const QImage &image)