src/opengl/qgl.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
--- a/src/opengl/qgl.cpp	Fri Sep 17 08:34:18 2010 +0300
+++ b/src/opengl/qgl.cpp	Mon Oct 04 01:19:32 2010 +0300
@@ -96,7 +96,7 @@
 
 QT_BEGIN_NAMESPACE
 
-#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
+#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
 QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs;
 #endif
 
@@ -1688,6 +1688,10 @@
     workaround_needsFullClearOnEveryFrame = false;
     workaround_brokenFBOReadBack = false;
     workaroundsCached = false;
+
+    workaround_brokenTextureFromPixmap = false;
+    workaround_brokenTextureFromPixmap_init = false;
+
     for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
         vertexAttributeArraysEnabledState[i] = false;
 }
@@ -1991,7 +1995,7 @@
     option helps preserve this default behavior.
 
     \omitvalue CanFlipNativePixmapBindOption Used by x11 from pixmap to choose
-    wether or not it can bind the pixmap upside down or not.
+    whether or not it can bind the pixmap upside down or not.
 
     \omitvalue MemoryManagedBindOption Used by paint engines to
     indicate that the pixmap should be memory managed along side with
@@ -2099,11 +2103,8 @@
 #ifdef QT_NO_EGL
 void QGLContextPrivate::swapRegion(const QRegion *)
 {
-    static bool firstWarning = true;
-    if (firstWarning) {
-        qWarning() << "::swapRegion called but not supported!";
-        firstWarning = false;
-    }
+    Q_Q(QGLContext);
+    q->swapBuffers();
 }
 #endif
 
@@ -2260,7 +2261,7 @@
     }
 }
 
-#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
+#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
 QGLExtensionFuncs& QGLContextPrivate::extensionFuncs(const QGLContext *)
 {
     return qt_extensionFuncs;
@@ -2283,11 +2284,19 @@
 QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
                                            QGLContext::BindOptions options)
 {
+    Q_Q(QGLContext);
+
     const qint64 key = image.cacheKey();
     QGLTexture *texture = textureCacheLookup(key, target);
     if (texture) {
-        glBindTexture(target, texture->id);
-        return texture;
+        if (image.paintingActive()) {
+            // A QPainter is active on the image - take the safe route and replace the texture.
+            q->deleteTexture(texture->id);
+            texture = 0;
+        } else {
+            glBindTexture(target, texture->id);
+            return texture;
+        }
     }
 
     if (!texture)
@@ -2553,14 +2562,19 @@
     }
 #else
     Q_UNUSED(pd);
-    Q_UNUSED(q);
 #endif
 
     const qint64 key = pixmap.cacheKey();
     QGLTexture *texture = textureCacheLookup(key, target);
     if (texture) {
-        glBindTexture(target, texture->id);
-        return texture;
+        if (pixmap.paintingActive()) {
+            // A QPainter is active on the pixmap - take the safe route and replace the texture.
+            q->deleteTexture(texture->id);
+            texture = 0;
+        } else {
+            glBindTexture(target, texture->id);
+            return texture;
+        }
     }
 
 #if defined(Q_WS_X11)
@@ -2570,11 +2584,27 @@
         && xinfo && xinfo->screen() == pixmap.x11Info().screen()
         && target == GL_TEXTURE_2D)
     {
-        texture = bindTextureFromNativePixmap(const_cast<QPixmap*>(&pixmap), key, options);
-        if (texture) {
-            texture->options |= QGLContext::MemoryManagedBindOption;
-            texture->boundPixmap = pd;
-            boundPixmaps.insert(pd, QPixmap(pixmap));
+        if (!workaround_brokenTextureFromPixmap_init) {
+            workaround_brokenTextureFromPixmap_init = true;
+
+            const QByteArray versionString(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
+            const int pos = versionString.indexOf("NVIDIA ");
+
+            if (pos >= 0) {
+                const QByteArray nvidiaVersionString = versionString.mid(pos + strlen("NVIDIA "));
+
+                if (nvidiaVersionString.startsWith("195") || nvidiaVersionString.startsWith("256"))
+                    workaround_brokenTextureFromPixmap = true;
+            }
+        }
+
+        if (!workaround_brokenTextureFromPixmap) {
+            texture = bindTextureFromNativePixmap(const_cast<QPixmap*>(&pixmap), key, options);
+            if (texture) {
+                texture->options |= QGLContext::MemoryManagedBindOption;
+                texture->boundPixmap = pd;
+                boundPixmaps.insert(pd, QPixmap(pixmap));
+            }
         }
     }
 #endif
@@ -4177,6 +4207,34 @@
         d->glcx->d_ptr->clearDrawable();
 #  endif
     }
+#elif defined(Q_OS_SYMBIAN)
+    // prevents errors on some systems, where we get a flush to a
+    // hidden widget
+    if (e->type() == QEvent::Hide) {
+        makeCurrent();
+        glFinish();
+        doneCurrent();
+    } else if (e->type() == QEvent::ParentChange) {
+        // if we've reparented a window that has the current context
+        // bound, we need to rebind that context to the new window id
+        if (d->glcx == QGLContext::currentContext())
+            makeCurrent();
+
+        if (testAttribute(Qt::WA_TranslucentBackground))
+            setContext(new QGLContext(d->glcx->requestedFormat(), this));
+    }
+
+    // A re-parent is likely to destroy the Symbian window and re-create it. It is important
+    // that we free the EGL surface _before_ the winID changes - otherwise we can leak.
+    if (e->type() == QEvent::ParentAboutToChange)
+        d->glcx->d_func()->destroyEglSurfaceForDevice();
+
+    if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) {
+        // The window may have been re-created during re-parent or state change - if so, the EGL
+        // surface will need to be re-created.
+        d->recreateEglSurface();
+    }
+
 #endif
 
     return QWidget::event(e);
@@ -4384,6 +4442,11 @@
     Q_D(QGLWidget);
     if (!isValid())
         return;
+#ifdef Q_OS_SYMBIAN
+    // Crashes on Symbian if trying to render to invisible surfaces
+    if (!isVisible() && d->glcx->device()->devType() == QInternal::Widget)
+        return;
+#endif
     makeCurrent();
 #ifndef QT_OPENGL_ES
     if (d->glcx->deviceIsPixmap())
@@ -5196,6 +5259,8 @@
         glExtensions |= FragmentProgram;
     if (extensions.match("GL_ARB_fragment_shader"))
         glExtensions |= FragmentShader;
+    if (extensions.match("GL_ARB_ES2_compatibility"))
+        glExtensions |= ES2Compatibility;
     if (extensions.match("GL_ARB_texture_mirrored_repeat"))
         glExtensions |= MirroredRepeat;
     if (extensions.match("GL_EXT_framebuffer_object"))
@@ -5216,6 +5281,7 @@
     glExtensions |= FramebufferObject;
     glExtensions |= GenerateMipmap;
     glExtensions |= FragmentShader;
+    glExtensions |= ES2Compatibility;
 #endif
 #if defined(QT_OPENGL_ES_1)
     if (extensions.match("GL_OES_framebuffer_object"))