From f79d96b486c1dd50876001b9c3f65d103e07a18c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20R=C3=B8dal?= <srodal@gmail.com>
Date: Tue, 4 Nov 2014 20:24:38 +0100
Subject: [PATCH] Fixed QtGui's GL paint engine getting out of sync when using
 QtOpenGL
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We need to reset the active_engine belonging to QOpenGLContext whenever
we make the QtOpenGL paint engine active, to give the OpenGL paint
engine in QtGui a chance to sync its state if we've used the QtOpenGL
paint engine inbetween.

Change-Id: I445ce2f99bfbacf55650c881c4fdf07f2ff85069
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
---
 .../qpaintengineex_opengl2.cpp                | 21 ++++++++++++++-
 .../qpaintengineex_opengl2_p.h                |  1 +
 tests/auto/opengl/qgl/tst_qgl.cpp             | 27 +++++++++++++++++++
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 43df3116364..1fa5723d85a 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -612,6 +612,21 @@ void QGL2PaintEngineExPrivate::resetGLState()
 #endif
 }
 
+bool QGL2PaintEngineExPrivate::resetOpenGLContextActiveEngine()
+{
+    QOpenGLContext *guiGlContext = ctx->contextHandle();
+    QOpenGLContextPrivate *guiGlContextPrivate =
+        guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0;
+
+    if (guiGlContextPrivate && guiGlContextPrivate->active_engine) {
+        ctx->d_func()->refreshCurrentFbo();
+        guiGlContextPrivate->active_engine = 0;
+        return true;
+    }
+
+    return false;
+}
+
 void QGL2PaintEngineEx::endNativePainting()
 {
     Q_D(QGL2PaintEngineEx);
@@ -2015,6 +2030,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
     d->ctx = d->device->context();
     d->ctx->d_ptr->active_engine = this;
 
+    d->resetOpenGLContextActiveEngine();
+
     const QSize sz = d->device->size();
     d->width = sz.width();
     d->height = sz.height();
@@ -2080,6 +2097,8 @@ bool QGL2PaintEngineEx::end()
 
     ctx->d_ptr->active_engine = 0;
 
+    d->resetOpenGLContextActiveEngine();
+
     d->resetGLState();
 
     delete d->shaderManager;
@@ -2105,7 +2124,7 @@ void QGL2PaintEngineEx::ensureActive()
     Q_D(QGL2PaintEngineEx);
     QGLContext *ctx = d->ctx;
 
-    if (isActive() && ctx->d_ptr->active_engine != this) {
+    if (isActive() && (ctx->d_ptr->active_engine != this || d->resetOpenGLContextActiveEngine())) {
         ctx->d_ptr->active_engine = this;
         d->needsSync = true;
     }
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 528bfdeeb98..ac1d63df17d 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -191,6 +191,7 @@ public:
     void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = GLuint(-1));
 
     void resetGLState();
+    bool resetOpenGLContextActiveEngine();
 
     // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points,
     // however writeClip can also be thought of as en entry point as it does similar things.
diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp
index d8ad3e1470c..56198ceb650 100644
--- a/tests/auto/opengl/qgl/tst_qgl.cpp
+++ b/tests/auto/opengl/qgl/tst_qgl.cpp
@@ -1200,6 +1200,33 @@ void tst_QGL::currentFboSync()
 
         QCOMPARE(fbo1.toImage(), fbo2Image);
     }
+
+    {
+        QGLFramebufferObject fbo1(512, 512, QGLFramebufferObject::CombinedDepthStencil);
+
+        QOpenGLFramebufferObjectPaintDevice fbo2(256, 256);
+
+        QImage sourceImage(256, 256, QImage::Format_ARGB32_Premultiplied);
+        QPainter sourcePainter(&sourceImage);
+        qt_opengl_draw_test_pattern(&sourcePainter, 256, 256);
+
+        QPainter fbo2Painter(&fbo2);
+        fbo2Painter.drawImage(0, 0, sourceImage);
+        QImage fbo2Image1 = fbo2.toImage();
+        fbo2Painter.fillRect(0, 0, 256, 256, Qt::white);
+
+        QPainter fbo1Painter(&fbo1);
+        fbo1Painter.drawImage(0, 0, sourceImage);
+        fbo1Painter.end();
+
+        // check that the OpenGL paint engine now knows it needs to sync
+        fbo2Painter.drawImage(0, 0, sourceImage);
+        QImage fbo2Image2 = fbo2.toImage();
+
+        fbo2Painter.end();
+
+        QCOMPARE(fbo2Image1, fbo2Image2);
+    }
 }
 
 // Tests multiple QPainters active on different FBOs at the same time, with
-- 
GitLab