Make opengl context current in context2d's toImage if necessary
authorUlf Hermann <ulf.hermann@theqtcompany.com>
Mon, 17 Nov 2014 13:43:27 +0000 (14:43 +0100)
committerUlf Hermann <ulf.hermann@theqtcompany.com>
Mon, 12 Jan 2015 10:37:53 +0000 (11:37 +0100)
With the basic render loop the scene graph thread is the render thread
and thus we don't get a different opengl context for context2d in
immediate/fbo mode. We have to make sure the opengl context is current
when we call flush() from functions exposed to JS.

Change-Id: Idd91cf1ce9c299a7645cf3b78d4498652376b17e
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
src/quick/items/context2d/qquickcontext2d.cpp

index 0101e0e..2d1bb4d 100644 (file)
@@ -4171,13 +4171,35 @@ QQuickContext2DTexture *QQuickContext2D::texture() const
 
 QImage QQuickContext2D::toImage(const QRectF& bounds)
 {
-    flush();
-    if (m_texture->thread() == QThread::currentThread())
-        m_texture->grabImage(bounds);
-    else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
+    if (m_texture->thread() == QThread::currentThread()) {
+        // if we're either not rendering to an fbo or we have a separate opengl context we can just
+        // flush. Otherwise we have to make sure the shared opengl context is current before we do
+        // so. It may or may not be current already, depending on how this method is called.
+        if (m_renderTarget != QQuickCanvasItem::FramebufferObject || m_glContext) {
+            flush();
+            m_texture->grabImage(bounds);
+        } else {
+            QQuickWindow *window = m_canvas->window();
+            QOpenGLContext *ctx =  window ? window->openglContext() : 0;
+            if (ctx && ctx->isValid()) {
+                if (ctx == QOpenGLContext::currentContext()) {
+                    flush();
+                } else {
+                    ctx->makeCurrent(window);
+                    flush();
+                    ctx->doneCurrent();
+                }
+                m_texture->grabImage(bounds);
+            } else {
+                qWarning() << "Cannot read pixels from canvas before opengl context is valid";
+                return QImage();
+            }
+        }
+    } else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
         qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";
         return QImage();
     } else {
+        flush();
         QCoreApplication::postEvent(m_texture, new QEvent(QEvent::Type(QEvent::User + 10)));
         QMetaObject::invokeMethod(m_texture,
                                   "grabImage",