Redirect the default FBO correctly with QQuickWidget
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>
Mon, 1 Jun 2015 15:04:07 +0000 (17:04 +0200)
committerAntti Kokko <antti.kokko@theqtcompany.com>
Wed, 3 Jun 2015 16:20:59 +0000 (16:20 +0000)
Similarly to QOpenGLWidget, functions like QOpenGLFramebufferObject::bindDefault()
should bind the QQuickWidget's FBO, not 0, while rendering the scene graph.

This becomes particularly important on platforms with surfaceless context support.
Here offscreen surfaces are not backed by any surface. Therefore any OpenGL operation
accessing the current draw framebuffer with FBO 0 bound may potentially crash, as there
is no draw framebuffer at all.

The distance field glyph cache exhibits this issue when running with EGL on Mesa:
glViewport crashes when we render via QQuickWidget and the current framebuffer is reset
to 0. The problem goes away when the code changed is to use bindDefault() - as it should have
anyhow - and QQuickWidget is enhanced to communicate the "default" framebuffer to QOpenGLContext,
just like QOpenGLWidget does.

Task-number: QTBUG-46415
Task-number: QTBUG-43269
Change-Id: I35fe375a0870dadecc4a074dfdec122c6a4c92ab
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com>
src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
src/quickwidgets/qquickwidget.cpp

index 136f23f..dcc485c 100644 (file)
@@ -38,6 +38,7 @@
 #include <QtQml/private/qqmlglobal_p.h>
 #include <QtQuick/private/qsgdistancefieldutil_p.h>
 #include <qopenglfunctions.h>
+#include <qopenglframebufferobject.h>
 #include <qmath.h>
 
 #if !defined(QT_OPENGL_ES_2)
@@ -324,7 +325,7 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
                                    GL_COLOR_BUFFER_BIT, GL_NEAREST);
 
         // Reset the default framebuffer
-        m_coreFuncs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        QOpenGLFramebufferObject::bindDefault();
 
         return;
     } else if (useTextureResizeWorkaround()) {
@@ -449,7 +450,7 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
     m_funcs->glDeleteTextures(1, &tmp_texture);
     m_funcs->glDeleteTextures(1, &oldTexture);
 
-    m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    QOpenGLFramebufferObject::bindDefault();
 
     // restore render states
     if (stencilTestEnabled)
index 608c5f9..a848774 100644 (file)
@@ -202,7 +202,12 @@ void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRec
 
 void QQuickWidgetPrivate::render(bool needsSync)
 {
-    context->makeCurrent(offscreenSurface);
+    if (!context->makeCurrent(offscreenSurface)) {
+        qWarning("QQuickWidget: Cannot render due to failing makeCurrent()");
+        return;
+    }
+
+    QOpenGLContextPrivate::get(context)->defaultFboRedirect = fbo->handle();
 
     if (needsSync) {
         renderControl->polishItems();
@@ -217,6 +222,8 @@ void QQuickWidgetPrivate::render(bool needsSync)
     }
 
     static_cast<QOpenGLExtensions *>(context->functions())->flushShared();
+
+    QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0;
 }
 
 void QQuickWidgetPrivate::renderSceneGraph()