[PATCH] QOpenGlContext: Always unset current context in doneCurrent()
authorDavid Redondo <qt@david-redondo.de>
Wed, 15 Jan 2025 12:52:13 +0000 (13:52 +0100)
committerPatrick Franz <deltaone@debian.org>
Wed, 16 Apr 2025 19:33:04 +0000 (21:33 +0200)
Otherwise when no other context is made current until thread exit, the
QGuiGLThreadContext destructor will try to call doneCurrent() on an
already deleted context.

Change-Id: If55dd69a72b8ab4012780a449f6a02729dd0ed43
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
(cherry picked from commit cd1686e55f706048286cbc962bbe02032c2396cd)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 10c195b86432eaa430c6991c0fcb74c411407cdf)

Gbp-Pq: Name upstream_unset_current_openglcontext.diff

src/gui/kernel/qopenglcontext.cpp
tests/auto/gui/qopengl/tst_qopengl.cpp

index dd41318f72a9942a3d2820af5c1c0615577b3581..c25132dc734a97d594dc84502a3897e92b43d76e 100644 (file)
@@ -743,13 +743,13 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
 void QOpenGLContext::doneCurrent()
 {
     Q_D(QOpenGLContext);
-    if (!isValid())
-        return;
 
-    if (QOpenGLContext::currentContext() == this)
-        d->shareGroup->d_func()->deletePendingResources(this);
+    if (isValid()) {
+        if (QOpenGLContext::currentContext() == this)
+            d->shareGroup->d_func()->deletePendingResources(this);
+        d->platformGLContext->doneCurrent();
+    }
 
-    d->platformGLContext->doneCurrent();
     QOpenGLContextPrivate::setCurrentContext(nullptr);
 
     d->surface = nullptr;
index af59f3e31a386ff9696124e1c89bd1214fa07d9d..3f4aa8cd8f946b6164e836a8f8d46f5ee064d4a9 100644 (file)
@@ -84,6 +84,9 @@ private slots:
     void bufferCreate();
     void bufferMapRange();
     void defaultQGLCurrentBuffer();
+#if QT_CONFIG(egl)
+    void dontCrashOnInvalidContextThreadTeardown();
+#endif
 };
 
 struct SharedResourceTracker
@@ -1751,6 +1754,31 @@ void tst_QOpenGL::clipRect()
     //QCOMPARE(fb.pixelColor(clipRect.right(), clipRect.top() + 1), QColor(Qt::red));
 }
 
+#if QT_CONFIG(egl)
+void tst_QOpenGL::dontCrashOnInvalidContextThreadTeardown()
+{
+    class Thread : public QThread
+    {
+        void run() override
+        {
+            auto context = std::make_unique<QOpenGLContext>();
+            QVERIFY(context->create());
+            QScopedPointer<QSurface> surface(createSurface(int(QSurface::Window)));
+            QVERIFY(context->makeCurrent(surface.data()));
+            auto eglContext = context->nativeInterface<QNativeInterface::QEGLContext>();
+            if (!eglContext) {
+                QSKIP("Need an egl context for this test");
+            }
+            eglContext->invalidateContext();
+            context->doneCurrent();
+        }
+    };
+    Thread thread;
+    thread.start();
+    thread.wait();
+}
+#endif
+
 QTEST_MAIN(tst_QOpenGL)
 
 #include "tst_qopengl.moc"