src/opengl/qgl.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 5 d3bac044e0f0
--- a/src/opengl/qgl.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/opengl/qgl.cpp	Fri Feb 19 23:40:16 2010 +0200
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -124,9 +124,6 @@
 };
 Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance)
 
-QGLExtensions::Extensions QGLExtensions::glExtensions = 0;
-bool QGLExtensions::nvidiaFboNeedsFinish = false;
-
 Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy)
 QGLSignalProxy *QGLSignalProxy::instance()
 {
@@ -154,11 +151,9 @@
         // falling back to the GL 1 engine..
         static bool mac_x1600_check_done = false;
         if (!mac_x1600_check_done) {
-            QGLWidget *tmp = 0;
-            if (!QGLContext::currentContext()) {
-                tmp = new QGLWidget();
-                tmp->makeCurrent();
-            }
+            QGLTemporaryContext *tmp = 0;
+            if (!QGLContext::currentContext())
+                tmp = new QGLTemporaryContext();
             if (strstr((char *) glGetString(GL_RENDERER), "X1600"))
                 engineType = QPaintEngine::OpenGL;
             if (tmp)
@@ -178,7 +173,7 @@
             // from an old GL 1.1 server to a GL 2.x client. In that case we can't
             // use GL 2.0.
             if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
-                && (QGLExtensions::glExtensions & QGLExtensions::FragmentShader)
+                && (QGLExtensions::glExtensions() & QGLExtensions::FragmentShader)
                 && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty())
                 engineType = QPaintEngine::OpenGL2;
             else
@@ -1250,7 +1245,7 @@
     static bool cachedDefault = false;
     static OpenGLVersionFlags defaultVersionFlags = OpenGL_Version_None;
     QGLContext *currentCtx = const_cast<QGLContext *>(QGLContext::currentContext());
-    QGLWidget *dummy = 0;
+    QGLTemporaryContext *tmpContext = 0;
 
     if (currentCtx && currentCtx->d_func()->version_flags_cached)
         return currentCtx->d_func()->version_flags;
@@ -1261,8 +1256,7 @@
         } else {
             if (!hasOpenGL())
                 return defaultVersionFlags;
-            dummy = new QGLWidget;
-            dummy->makeCurrent(); // glGetString() needs a current context
+            tmpContext = new QGLTemporaryContext;
             cachedDefault = true;
         }
     }
@@ -1273,9 +1267,9 @@
         currentCtx->d_func()->version_flags_cached = true;
         currentCtx->d_func()->version_flags = versionFlags;
     }
-    if (dummy) {
+    if (tmpContext) {
         defaultVersionFlags = versionFlags;
-        delete dummy;
+        delete tmpContext;
     }
 
     return versionFlags;
@@ -1436,6 +1430,18 @@
         m_guards = guard->m_next;
 }
 
+const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
+{
+    if (!ctx)
+        return 0;
+    QList<const QGLContext *> shares
+        (QGLContextPrivate::contextGroup(ctx)->shares());
+    if (shares.size() >= 2)
+        return (ctx == shares.at(0)) ? shares.at(1) : shares.at(0);
+    else
+        return 0;
+}
+
 QGLContextPrivate::~QGLContextPrivate()
 {
     if (!group->m_refs.deref()) {
@@ -1481,9 +1487,13 @@
     max_texture_size = -1;
     version_flags_cached = false;
     version_flags = QGLFormat::OpenGL_Version_None;
+    extension_flags_cached = false;
+    extension_flags = 0;
     current_fbo = 0;
     default_fbo = 0;
     active_engine = 0;
+    for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
+        vertexAttributeArraysEnabledState[i] = false;
 }
 
 QGLContext* QGLContext::currentCtx = 0;
@@ -1541,7 +1551,7 @@
 
 QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha)
 {
-    QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
+    QImage img(size, alpha_format ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
     int w = size.width();
     int h = size.height();
 #if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
@@ -1729,12 +1739,6 @@
 #define GL_GENERATE_MIPMAP_HINT_SGIS  0x8192
 #endif
 
-Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg)
-Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
-{
-    return _qgl_share_reg();
-}
-
 /*!
     \class QGLContext
     \brief The QGLContext class encapsulates an OpenGL rendering context.
@@ -1874,6 +1878,35 @@
 {
 }
 
+#define ctx q_ptr
+void QGLContextPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled)
+{
+    Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT);
+    Q_ASSERT(glEnableVertexAttribArray);
+
+    if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled)
+        glDisableVertexAttribArray(arrayIndex);
+
+    if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled)
+        glEnableVertexAttribArray(arrayIndex);
+
+    vertexAttributeArraysEnabledState[arrayIndex] = enabled;
+}
+
+void QGLContextPrivate::syncGlState()
+{
+    Q_ASSERT(glEnableVertexAttribArray);
+    for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) {
+        if (vertexAttributeArraysEnabledState[i])
+            glEnableVertexAttribArray(i);
+        else
+            glDisableVertexAttribArray(i);
+    }
+
+}
+#undef ctx
+
+
 /*!
     \overload
 
@@ -2110,7 +2143,7 @@
     int tx_h = qt_next_power_of_two(image.height());
 
     QImage img = image;
-    if (!(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures)
+    if (!(QGLExtensions::glExtensions() & QGLExtensions::NPOTTextures)
         && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0)
         && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
     {
@@ -2132,7 +2165,7 @@
     bool genMipmap = false;
 #endif
     if (glFormat.directRendering()
-        && (QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap)
+        && (QGLExtensions::glExtensions() & QGLExtensions::GenerateMipmap)
         && target == GL_TEXTURE_2D
         && (options & QGLContext::MipmapBindOption))
     {
@@ -2160,9 +2193,12 @@
     bool premul = options & QGLContext::PremultipliedAlphaBindOption;
     GLenum externalFormat;
     GLuint pixel_type;
-    if (QGLExtensions::glExtensions & QGLExtensions::BGRATextureFormat) {
+    if (QGLExtensions::glExtensions() & QGLExtensions::BGRATextureFormat) {
         externalFormat = GL_BGRA;
-        pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+        if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
+            pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+        else
+            pixel_type = GL_UNSIGNED_BYTE;
     } else {
         externalFormat = GL_RGBA;
         pixel_type = GL_UNSIGNED_BYTE;
@@ -2241,12 +2277,9 @@
         qgl_byteSwapImage(img, pixel_type);
     }
 #ifdef QT_OPENGL_ES
-    // OpenGL/ES requires that the internal and external formats be identical.
-    // This is typically used to convert GL_RGBA into GL_BGRA.
-    // Also, we need to use GL_UNSIGNED_BYTE when the format is GL_BGRA.
+    // OpenGL/ES requires that the internal and external formats be
+    // identical.
     internalFormat = externalFormat;
-    if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV)
-        pixel_type = GL_UNSIGNED_BYTE;
 #endif
 #ifdef QGL_BIND_TEXTURE_DEBUG
     printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n",
@@ -2954,7 +2987,7 @@
         wd->usesDoubleBufferedGLContext = d->glFormat.doubleBuffer();
     }
     if (d->sharing)  // ok, we managed to share
-        qgl_share_reg()->addShare(this, shareContext);
+        QGLContextGroup::addShare(this, shareContext);
     return d->valid;
 }
 
@@ -4378,9 +4411,9 @@
     int height = d->glcx->device()->height();
     bool auto_swap = autoBufferSwap();
 
+    QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
+    qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
     QPaintEngine *engine = paintEngine();
-    if (engine->type() == QPaintEngine::OpenGL2)
-        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
     QPainter *p;
     bool reuse_painter = false;
     if (engine->isActive()) {
@@ -4400,11 +4433,6 @@
         setAutoBufferSwap(false);
         // disable glClear() as a result of QPainter::begin()
         d->disable_clear_on_painter_begin = true;
-        if (engine->type() == QPaintEngine::OpenGL2) {
-            qt_save_gl_state();
-            glMatrixMode(GL_MODELVIEW);
-            glLoadIdentity();
-        }
         p = new QPainter(this);
     }
 
@@ -4428,11 +4456,8 @@
         delete p;
         setAutoBufferSwap(auto_swap);
         d->disable_clear_on_painter_begin = false;
-        if (engine->type() == QPaintEngine::OpenGL2)
-            qt_restore_gl_state();
     }
-    if (engine->type() == QPaintEngine::OpenGL2)
-        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+    qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
 #else // QT_OPENGL_ES
     Q_UNUSED(x);
     Q_UNUSED(y);
@@ -4480,9 +4505,9 @@
                 &win_x, &win_y, &win_z);
     win_y = height - win_y; // y is inverted
 
+    QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
+    qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
     QPaintEngine *engine = paintEngine();
-    if (engine->type() == QPaintEngine::OpenGL2)
-        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
     QPainter *p;
     bool reuse_painter = false;
     bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
@@ -4496,8 +4521,6 @@
         setAutoBufferSwap(false);
         // disable glClear() as a result of QPainter::begin()
         d->disable_clear_on_painter_begin = true;
-        if (engine->type() == QPaintEngine::OpenGL2)
-            qt_save_gl_state();
         p = new QPainter(this);
     }
 
@@ -4526,13 +4549,10 @@
     } else {
         p->end();
         delete p;
-        if (engine->type() == QPaintEngine::OpenGL2)
-            qt_restore_gl_state();
         setAutoBufferSwap(auto_swap);
         d->disable_clear_on_painter_begin = false;
     }
-    if (engine->type() == QPaintEngine::OpenGL2)
-        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+    qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
 #else // QT_OPENGL_ES
     Q_UNUSED(x);
     Q_UNUSED(y);
@@ -4844,9 +4864,13 @@
 
 #endif // QT3_SUPPORT
 
-void QGLExtensions::init_extensions()
+/*
+    Returns the GL extensions for the current context.
+*/
+QGLExtensions::Extensions QGLExtensions::currentContextExtensions()
 {
     QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
+    Extensions glExtensions;
 
     if (extensions.match("GL_ARB_texture_rectangle"))
         glExtensions |= TextureRectangle;
@@ -4907,6 +4931,46 @@
 
     if (extensions.match("GL_EXT_bgra"))
         glExtensions |= BGRATextureFormat;
+
+    return glExtensions;
+}
+
+/*
+    Returns the GL extensions for the current QGLContext. If there is no
+    current QGLContext, a default context will be created and the extensions
+    for that context will be returned instead.
+*/
+QGLExtensions::Extensions QGLExtensions::glExtensions()
+{
+    QGLTemporaryContext *tmpContext = 0;
+    static bool cachedDefault = false;
+    static Extensions defaultExtensions = 0;
+    QGLContext *currentCtx = const_cast<QGLContext *>(QGLContext::currentContext());
+
+    if (currentCtx && currentCtx->d_func()->extension_flags_cached)
+        return currentCtx->d_func()->extension_flags;
+
+    if (!currentCtx) {
+        if (cachedDefault) {
+            return defaultExtensions;
+        } else {
+            tmpContext = new QGLTemporaryContext;
+            cachedDefault = true;
+        }
+    }
+
+    Extensions extensionFlags = currentContextExtensions();
+    if (currentCtx) {
+        currentCtx->d_func()->extension_flags_cached = true;
+        currentCtx->d_func()->extension_flags = extensionFlags;
+    } else {
+        defaultExtensions = extensionFlags;
+    }
+
+    if (tmpContext)
+        delete tmpContext;
+
+    return extensionFlags;
 }
 
 /*
@@ -4918,7 +4982,6 @@
 
     glDevice.setWidget(q);
 
-    QGLExtensions::init();
     glcx = 0;
     autoSwap = true;
 
@@ -4928,8 +4991,6 @@
 
     if (!glcx)
         glcx = new QGLContext(QGLFormat::defaultFormat(), q);
-
-    q->setAttribute(Qt::WA_NoSystemBackground);
 }
 
 #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
@@ -4953,7 +5014,7 @@
 }
 #endif
 
-void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) {
+void QGLContextGroup::addShare(const QGLContext *context, const QGLContext *share) {
     Q_ASSERT(context && share);
     if (context->d_ptr->group == share->d_ptr->group)
         return;
@@ -4974,11 +5035,7 @@
     group->m_shares.append(context);
 }
 
-QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
-    return context->d_ptr->group->m_shares;
-}
-
-void QGLShareRegister::removeShare(const QGLContext *context) {
+void QGLContextGroup::removeShare(const QGLContext *context) {
     // Remove the context from the group.
     QGLContextGroup *group = context->d_ptr->group;
     if (group->m_shares.isEmpty())
@@ -5173,7 +5230,7 @@
     }
 #if !defined(QT_OPENGL_ES)
     if (!glCompressedTexImage2D) {
-        if (!(QGLExtensions::glExtensions & QGLExtensions::TextureCompression)) {
+        if (!(QGLExtensions::glExtensions() & QGLExtensions::TextureCompression)) {
             qWarning("QGLContext::bindTexture(): The GL implementation does "
                      "not support texture compression extensions.");
             return QSize();
@@ -5212,7 +5269,7 @@
         return QSize();
 
     // Bail out if the necessary extension is not present.
-    if (!(QGLExtensions::glExtensions & QGLExtensions::DDSTextureCompression)) {
+    if (!(QGLExtensions::glExtensions() & QGLExtensions::DDSTextureCompression)) {
         qWarning("QGLContext::bindTexture(): DDS texture compression is not supported.");
         return QSize();
     }
@@ -5322,13 +5379,13 @@
 
     // Bail out if the necessary extension is not present.
     if (textureFormat == GL_ETC1_RGB8_OES) {
-        if (!(QGLExtensions::glExtensions &
+        if (!(QGLExtensions::glExtensions() &
                     QGLExtensions::ETC1TextureCompression)) {
             qWarning("QGLContext::bindTexture(): ETC1 texture compression is not supported.");
             return QSize();
         }
     } else {
-        if (!(QGLExtensions::glExtensions &
+        if (!(QGLExtensions::glExtensions() &
                     QGLExtensions::PVRTCTextureCompression)) {
             qWarning("QGLContext::bindTexture(): PVRTC texture compression is not supported.");
             return QSize();