Move GL resource handling enablers to QtGui.
authorSamuel Rødal <samuel.rodal@nokia.com>
Tue, 16 Aug 2011 07:29:44 +0000 (09:29 +0200)
committerSamuel Rødal <samuel.rodal@nokia.com>
Mon, 29 Aug 2011 08:24:55 +0000 (10:24 +0200)
Made resource handling more robust by attempting to free GL resources in
the correct thread, and not forcing a context to become current to free
resources.

Change-Id: Ie81d4005b608972375755571d9b50ce82080709b
Reviewed-on: http://codereview.qt.nokia.com/3258
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
20 files changed:
src/gui/kernel/kernel.pri
src/gui/kernel/qguiglcontext_qpa.cpp
src/gui/kernel/qguiglcontext_qpa.h
src/gui/kernel/qguiglcontext_qpa_p.h [new file with mode: 0644]
src/gui/kernel/qplatformglcontext_qpa.cpp
src/opengl/gl2paintengineex/qglengineshadermanager.cpp
src/opengl/gl2paintengineex/qglengineshadermanager_p.h
src/opengl/gl2paintengineex/qglgradientcache.cpp
src/opengl/gl2paintengineex/qglgradientcache_p.h
src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
src/opengl/qgl.cpp
src/opengl/qgl.h
src/opengl/qgl_p.h
src/opengl/qglbuffer.cpp
src/opengl/qglframebufferobject.cpp
src/opengl/qglframebufferobject_p.h
src/opengl/qglfunctions.cpp
src/opengl/qglshaderprogram.cpp

index 58291f5..44d0395 100644 (file)
@@ -51,6 +51,7 @@ qpa {
                 kernel/qplatformwindow_qpa.h \
                 kernel/qplatformglcontext_qpa.h \
                 kernel/qguiglcontext_qpa.h \
+                kernel/qguiglcontext_qpa_p.h \
                 kernel/qplatformcursor_qpa.h \
                 kernel/qplatformclipboard_qpa.h \
                 kernel/qplatformnativeinterface_qpa.h \
index 2c43bef..71c8301 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "qplatformglcontext_qpa.h"
 #include "qguiglcontext_qpa.h"
+#include "qguiglcontext_qpa_p.h"
 #include "qwindow.h"
 
 #include <QtCore/QThreadStorage>
@@ -63,35 +64,6 @@ public:
 
 static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage;
 
-class QGuiGLContextPrivate
-{
-public:
-    QGuiGLContextPrivate()
-        : qGLContextHandle(0)
-        , platformGLContext(0)
-        , shareContext(0)
-        , screen(0)
-        , surface(0)
-    {
-    }
-
-    virtual ~QGuiGLContextPrivate()
-    {
-        //do not delete the QGLContext handle here as it is deleted in
-        //QWidgetPrivate::deleteTLSysExtra()
-    }
-    void *qGLContextHandle;
-    void (*qGLContextDeleteFunction)(void *handle);
-
-    QSurfaceFormat requestedFormat;
-    QPlatformGLContext *platformGLContext;
-    QGuiGLContext *shareContext;
-    QScreen *screen;
-    QSurface *surface;
-
-    static void setCurrentContext(QGuiGLContext *context);
-};
-
 void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context)
 {
     QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
@@ -118,6 +90,11 @@ QGuiGLContext* QGuiGLContext::currentContext()
     return 0;
 }
 
+bool QGuiGLContext::areSharing(QGuiGLContext *first, QGuiGLContext *second)
+{
+    return first->shareGroup() == second->shareGroup();
+}
+
 QPlatformGLContext *QGuiGLContext::handle() const
 {
     Q_D(const QGuiGLContext);
@@ -136,7 +113,7 @@ QPlatformGLContext *QGuiGLContext::shareHandle() const
   Creates a new GL context instance, you need to call create() before it can be used.
 */
 QGuiGLContext::QGuiGLContext()
-    : d_ptr(new QGuiGLContextPrivate())
+    : QObject(*new QGuiGLContextPrivate())
 {
     Q_D(QGuiGLContext);
     d->screen = QGuiApplication::primaryScreen();
@@ -174,7 +151,7 @@ void QGuiGLContext::setScreen(QScreen *screen)
 /*!
   Attempts to create the GL context with the desired parameters.
 
-  Returns true if the native context was successfully created and is ready to be used.d
+  Returns true if the native context was successfully created and is ready to be used.
 */
 bool QGuiGLContext::create()
 {
@@ -183,6 +160,8 @@ bool QGuiGLContext::create()
     Q_D(QGuiGLContext);
     d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformGLContext(this);
     d->platformGLContext->setContext(this);
+    d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QGuiGLContextGroup;
+    d->shareGroup->d_func()->addContext(this);
     return d->platformGLContext;
 }
 
@@ -191,6 +170,9 @@ void QGuiGLContext::destroy()
     Q_D(QGuiGLContext);
     if (QGuiGLContext::currentContext() == this)
         doneCurrent();
+    if (d->shareGroup)
+        d->shareGroup->d_func()->removeContext(this);
+    d->shareGroup = 0;
     delete d->platformGLContext;
     d->platformGLContext = 0;
 }
@@ -232,6 +214,9 @@ bool QGuiGLContext::makeCurrent(QSurface *surface)
     if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
         QGuiGLContextPrivate::setCurrentContext(this);
         d->surface = surface;
+
+        d->shareGroup->d_func()->deletePendingResources(this);
+
         return true;
     }
 
@@ -247,6 +232,9 @@ void QGuiGLContext::doneCurrent()
     if (!d->platformGLContext)
         return;
 
+    if (QGuiGLContext::currentContext() == this)
+        d->shareGroup->d_func()->deletePendingResources(this);
+
     d->platformGLContext->doneCurrent();
     QGuiGLContextPrivate::setCurrentContext(0);
 
@@ -293,6 +281,12 @@ QSurfaceFormat QGuiGLContext::format() const
     return d->platformGLContext->format();
 }
 
+QGuiGLContextGroup *QGuiGLContext::shareGroup() const
+{
+    Q_D(const QGuiGLContext);
+    return d->shareGroup;
+}
+
 QGuiGLContext *QGuiGLContext::shareContext() const
 {
     Q_D(const QGuiGLContext);
@@ -331,3 +325,176 @@ void QGuiGLContext::deleteQGLContext()
         d->qGLContextHandle = 0;
     }
 }
+
+QGuiGLContextGroup::QGuiGLContextGroup()
+    : QObject(*new QGuiGLContextGroupPrivate())
+{
+}
+
+QGuiGLContextGroup::~QGuiGLContextGroup()
+{
+    Q_D(QGuiGLContextGroup);
+
+    QList<QGLSharedResource *>::iterator it = d->m_sharedResources.begin();
+    QList<QGLSharedResource *>::iterator end = d->m_sharedResources.end();
+
+    while (it != end) {
+        (*it)->invalidateResource();
+        (*it)->m_group = 0;
+        ++it;
+    }
+
+    qDeleteAll(d->m_pendingDeletion.begin(), d->m_pendingDeletion.end());
+}
+
+QList<QGuiGLContext *> QGuiGLContextGroup::shares() const
+{
+    Q_D(const QGuiGLContextGroup);
+    return d->m_shares;
+}
+
+QGuiGLContextGroup *QGuiGLContextGroup::currentContextGroup()
+{
+    QGuiGLContext *current = QGuiGLContext::currentContext();
+    return current ? current->shareGroup() : 0;
+}
+
+void QGuiGLContextGroupPrivate::addContext(QGuiGLContext *ctx)
+{
+    QMutexLocker locker(&m_mutex);
+    m_refs.ref();
+    m_shares << ctx;
+}
+
+void QGuiGLContextGroupPrivate::removeContext(QGuiGLContext *ctx)
+{
+    Q_Q(QGuiGLContextGroup);
+
+    QMutexLocker locker(&m_mutex);
+    m_shares.removeOne(ctx);
+
+    if (ctx == m_context && !m_shares.isEmpty())
+        m_context = m_shares.first();
+
+    if (!m_refs.deref())
+        q->deleteLater();
+}
+
+void QGuiGLContextGroupPrivate::deletePendingResources(QGuiGLContext *ctx)
+{
+    QMutexLocker locker(&m_mutex);
+
+    QList<QGLSharedResource *>::iterator it = m_pendingDeletion.begin();
+    QList<QGLSharedResource *>::iterator end = m_pendingDeletion.end();
+    while (it != end) {
+        (*it)->freeResource(ctx);
+        delete *it;
+        ++it;
+    }
+    m_pendingDeletion.clear();
+}
+
+QGLSharedResource::QGLSharedResource(QGuiGLContextGroup *group)
+    : m_group(group)
+{
+    QMutexLocker locker(&m_group->d_func()->m_mutex);
+    m_group->d_func()->m_sharedResources << this;
+}
+
+QGLSharedResource::~QGLSharedResource()
+{
+}
+
+// schedule the resource for deletion at an appropriate time
+void QGLSharedResource::free()
+{
+    if (!m_group) {
+        delete this;
+        return;
+    }
+
+    QMutexLocker locker(&m_group->d_func()->m_mutex);
+    m_group->d_func()->m_sharedResources.removeOne(this);
+    m_group->d_func()->m_pendingDeletion << this;
+
+    // can we delete right away?
+    QGuiGLContext *current = QGuiGLContext::currentContext();
+    if (current && current->shareGroup() == m_group) {
+        m_group->d_func()->deletePendingResources(current);
+    }
+}
+
+QGLMultiGroupSharedResource::QGLMultiGroupSharedResource()
+    : active(0)
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+    qDebug("Creating context group resource object %p.", this);
+#endif
+}
+
+QGLMultiGroupSharedResource::~QGLMultiGroupSharedResource()
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+    qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
+#endif
+    for (int i = 0; i < m_groups.size(); ++i) {
+        QGuiGLContext *context = m_groups.at(i)->shares().first();
+        QGLSharedResource *resource = value(context);
+        if (resource)
+            resource->free();
+        m_groups.at(i)->d_func()->m_resources.remove(this);
+        active.deref();
+    }
+#ifndef QT_NO_DEBUG
+    if (active != 0) {
+        qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
+                 "          This is possibly caused by a leaked QGLWidget, \n"
+                 "          QGLFramebufferObject or QGLPixelBuffer.");
+    }
+#endif
+}
+
+void QGLMultiGroupSharedResource::insert(QGuiGLContext *context, QGLSharedResource *value)
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+    qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
+#endif
+    QGuiGLContextGroup *group = context->shareGroup();
+    Q_ASSERT(!group->d_func()->m_resources.contains(this));
+    group->d_func()->m_resources.insert(this, value);
+    m_groups.append(group);
+    active.ref();
+}
+
+QGLSharedResource *QGLMultiGroupSharedResource::value(QGuiGLContext *context)
+{
+    QGuiGLContextGroup *group = context->shareGroup();
+    return group->d_func()->m_resources.value(this, 0);
+}
+
+void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx)
+{
+    QGLSharedResource *resource = value(ctx);
+
+    if (resource != 0) {
+        resource->free();
+
+        QGuiGLContextGroup *group = ctx->shareGroup();
+        group->d_func()->m_resources.remove(this);
+        m_groups.removeOne(group);
+        active.deref();
+    }
+}
+
+void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx, QGLSharedResource *value)
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+    qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread());
+#endif
+    value->free();
+    active.deref();
+
+    QGuiGLContextGroup *group = ctx->shareGroup();
+    m_groups.removeOne(group);
+}
+
index 11a7e16..a234bd3 100644 (file)
@@ -54,12 +54,34 @@ QT_BEGIN_NAMESPACE
 QT_MODULE(Gui)
 
 class QGuiGLContextPrivate;
+class QGuiGLContextGroupPrivate;
 class QPlatformGLContext;
 class QSurface;
 
-class Q_GUI_EXPORT QGuiGLContext
+class Q_GUI_EXPORT QGuiGLContextGroup : public QObject
 {
-Q_DECLARE_PRIVATE(QGuiGLContext);
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QGuiGLContextGroup)
+public:
+    ~QGuiGLContextGroup();
+
+    QList<QGuiGLContext *> shares() const;
+
+    static QGuiGLContextGroup *currentContextGroup();
+
+private:
+    QGuiGLContextGroup();
+
+    friend class QGuiGLContext;
+    friend class QGLContextGroupResourceBase;
+    friend class QGLSharedResource;
+    friend class QGLMultiGroupSharedResource;
+};
+
+class Q_GUI_EXPORT QGuiGLContext : public QObject
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QGuiGLContext);
 public:
     QGuiGLContext();
     ~QGuiGLContext();
@@ -73,6 +95,7 @@ public:
 
     QSurfaceFormat format() const;
     QGuiGLContext *shareContext() const;
+    QGuiGLContextGroup *shareGroup() const;
     QScreen *screen() const;
 
     bool makeCurrent(QSurface *surface);
@@ -84,15 +107,15 @@ public:
     QSurface *surface() const;
 
     static QGuiGLContext *currentContext();
+    static bool areSharing(QGuiGLContext *first, QGuiGLContext *second);
 
     QPlatformGLContext *handle() const;
     QPlatformGLContext *shareHandle() const;
 
 private:
-    QScopedPointer<QGuiGLContextPrivate> d_ptr;
-
     //hack to make it work with QGLContext::CurrentContext
     friend class QGLContext;
+    friend class QGLContextResourceBase;
     friend class QWidgetPrivate;
 
     void *qGLContextHandle() const;
@@ -100,8 +123,6 @@ private:
     void deleteQGLContext();
 
     void destroy();
-
-    Q_DISABLE_COPY(QGuiGLContext);
 };
 
 QT_END_NAMESPACE
diff --git a/src/gui/kernel/qguiglcontext_qpa_p.h b/src/gui/kernel/qguiglcontext_qpa_p.h
new file mode 100644 (file)
index 0000000..a9c8f5c
--- /dev/null
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGUIGLCONTEXT_P_H
+#define QGUIGLCONTEXT_P_H
+
+#include "qguiglcontext_qpa.h"
+#include <private/qobject_p.h>
+#include <qmutex.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGuiGLContext;
+class QGLMultiGroupSharedResource;
+
+class Q_GUI_EXPORT QGLSharedResource
+{
+public:
+    QGLSharedResource(QGuiGLContextGroup *group);
+    virtual ~QGLSharedResource() = 0;
+
+    QGuiGLContextGroup *group() const { return m_group; }
+
+    // schedule the resource for deletion at an appropriate time
+    void free();
+
+protected:
+    // the resource's share group no longer exists, invalidate the resource
+    virtual void invalidateResource() = 0;
+
+    // a valid context in the group is current, free the resource
+    virtual void freeResource(QGuiGLContext *context) = 0;
+
+private:
+    QGuiGLContextGroup *m_group;
+
+    friend class QGuiGLContextGroup;
+    friend class QGuiGLContextGroupPrivate;
+
+    Q_DISABLE_COPY(QGLSharedResource);
+};
+
+class Q_GUI_EXPORT QGuiGLContextGroupPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QGuiGLContextGroup);
+public:
+    QGuiGLContextGroupPrivate()
+        : m_context(0)
+        , m_mutex(QMutex::Recursive)
+        , m_refs(0)
+    {
+    }
+
+    void addContext(QGuiGLContext *ctx);
+    void removeContext(QGuiGLContext *ctx);
+
+    void deletePendingResources(QGuiGLContext *ctx);
+
+    QGuiGLContext *m_context;
+
+    QList<QGuiGLContext *> m_shares;
+    QMutex m_mutex;
+
+    QHash<QGLMultiGroupSharedResource *, QGLSharedResource *> m_resources;
+    QAtomicInt m_refs;
+
+    QList<QGLSharedResource *> m_sharedResources;
+    QList<QGLSharedResource *> m_pendingDeletion;
+
+    void cleanupResources(QGuiGLContext *ctx);
+};
+
+class Q_GUI_EXPORT QGLMultiGroupSharedResource
+{
+public:
+    QGLMultiGroupSharedResource();
+    ~QGLMultiGroupSharedResource();
+
+    void insert(QGuiGLContext *context, QGLSharedResource *value);
+    void cleanup(QGuiGLContext *context);
+    void cleanup(QGuiGLContext *context, QGLSharedResource *value);
+
+    QGLSharedResource *value(QGuiGLContext *context);
+
+    template <typename T>
+    T *value(QGuiGLContext *context) {
+        QGuiGLContextGroup *group = context->shareGroup();
+        T *resource = static_cast<T *>(group->d_func()->m_resources.value(this, 0));
+        if (!resource) {
+            resource = new T(context);
+            insert(context, resource);
+        }
+        return resource;
+    }
+
+private:
+    QAtomicInt active;
+    QList<QGuiGLContextGroup *> m_groups;
+};
+
+class Q_GUI_EXPORT QGuiGLContextPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QGuiGLContext);
+public:
+    QGuiGLContextPrivate()
+        : qGLContextHandle(0)
+        , platformGLContext(0)
+        , shareContext(0)
+        , shareGroup(0)
+        , screen(0)
+        , surface(0)
+    {
+    }
+
+    virtual ~QGuiGLContextPrivate()
+    {
+        //do not delete the QGLContext handle here as it is deleted in
+        //QWidgetPrivate::deleteTLSysExtra()
+    }
+    void *qGLContextHandle;
+    void (*qGLContextDeleteFunction)(void *handle);
+
+    QSurfaceFormat requestedFormat;
+    QPlatformGLContext *platformGLContext;
+    QGuiGLContext *shareContext;
+    QGuiGLContextGroup *shareGroup;
+    QScreen *screen;
+    QSurface *surface;
+
+    QHash<QGLMultiGroupSharedResource *, void *> m_resources;
+
+    static void setCurrentContext(QGuiGLContext *context);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGUIGLCONTEXT_P_H
index 81030b8..5ce7db0 100644 (file)
@@ -65,6 +65,8 @@
 
 /*! \fn void QPlatformGLContext::swapBuffers()
     Reimplement in subclass to native swap buffers calls
+
+    The implementation must support being called in a thread different than the gui-thread.
 */
 
 /*! \fn void *QPlatformGLContext::getProcAddress(const QString &procName)
index 4c50089..05a612c 100644 (file)
@@ -44,6 +44,8 @@
 #include "qpaintengineex_opengl2_p.h"
 #include "qglshadercache_p.h"
 
+#include <QtGui/private/qguiglcontext_qpa_p.h>
+
 #if defined(QT_DEBUG)
 #include <QMetaEnum>
 #endif
 
 QT_BEGIN_NAMESPACE
 
+class QGLEngineSharedShadersResource : public QGLSharedResource
+{
+public:
+    QGLEngineSharedShadersResource(QGuiGLContext *ctx)
+        : QGLSharedResource(ctx->shareGroup())
+        , m_shaders(new QGLEngineSharedShaders(QGLContext::fromGuiGLContext(ctx)))
+    {
+    }
+
+    ~QGLEngineSharedShadersResource()
+    {
+        delete m_shaders;
+    }
+
+    void invalidateResource()
+    {
+        delete m_shaders;
+        m_shaders = 0;
+    }
+
+    void freeResource(QGuiGLContext *)
+    {
+    }
+
+    QGLEngineSharedShaders *shaders() const { return m_shaders; }
+
+private:
+    QGLEngineSharedShaders *m_shaders;
+};
+
 class QGLShaderStorage
 {
 public:
     QGLEngineSharedShaders *shadersForThread(const QGLContext *context) {
-        QGLContextGroupResource<QGLEngineSharedShaders> *&shaders = m_storage.localData();
+        QGLMultiGroupSharedResource *&shaders = m_storage.localData();
         if (!shaders)
-            shaders = new QGLContextGroupResource<QGLEngineSharedShaders>();
-        return shaders->value(context);
+            shaders = new QGLMultiGroupSharedResource;
+        QGLEngineSharedShadersResource *resource =
+            shaders->value<QGLEngineSharedShadersResource>(context->contextHandle());
+        return resource ? resource->shaders() : 0;
     }
 
 private:
-    QThreadStorage<QGLContextGroupResource<QGLEngineSharedShaders> *> m_storage;
+    QThreadStorage<QGLMultiGroupSharedResource *> m_storage;
 };
 
 Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage);
@@ -81,8 +115,7 @@ const char* QGLEngineSharedShaders::qShaderSnippets[] = {
 };
 
 QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
-    : ctxGuard(context)
-    , blitShaderProg(0)
+    : blitShaderProg(0)
     , simpleShaderProg(0)
 {
 
@@ -327,14 +360,14 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
         vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
         vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
 
-        QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram(ctxGuard.context(), 0));
+        QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram);
 
         CachedShader shaderCache(fragSource, vertexSource);
-        bool inCache = shaderCache.load(shaderProgram.data(), ctxGuard.context());
+        bool inCache = shaderCache.load(shaderProgram.data(), QGLContext::currentContext());
 
         if (!inCache) {
 
-            QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0));
+            QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment));
             QByteArray description;
 #if defined(QT_DEBUG)
             // Name the shader for easier debugging
@@ -357,7 +390,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
                 break;
             }
 
-            QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0));
+            QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex));
 #if defined(QT_DEBUG)
             // Name the shader for easier debugging
             description.clear();
@@ -396,7 +429,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
         newProg->program->link();
         if (newProg->program->isLinked()) {
             if (!inCache)
-                shaderCache.store(newProg->program, ctxGuard.context());
+                shaderCache.store(newProg->program, QGLContext::currentContext());
         } else {
             QLatin1String none("none");
             QLatin1String br("\n");
index 921df36..58c761d 100644 (file)
@@ -365,7 +365,6 @@ public:
     void cleanupCustomStage(QGLCustomShaderStage* stage);
 
 private:
-    QGLSharedResourceGuard ctxGuard;
     QGLShaderProgram *blitShaderProg;
     QGLShaderProgram *simpleShaderProg;
     QList<QGLEngineShaderProg*> cachedPrograms;
index 9e6b801..bd408ff 100644 (file)
@@ -51,21 +51,42 @@ class QGL2GradientCacheWrapper
 public:
     QGL2GradientCache *cacheForContext(const QGLContext *context) {
         QMutexLocker lock(&m_mutex);
-        return m_resource.value(context);
+        return m_resource.value<QGL2GradientCache>(context->contextHandle());
     }
 
 private:
-    QGLContextGroupResource<QGL2GradientCache> m_resource;
+    QGLMultiGroupSharedResource m_resource;
     QMutex m_mutex;
 };
 
 Q_GLOBAL_STATIC(QGL2GradientCacheWrapper, qt_gradient_caches)
 
+QGL2GradientCache::QGL2GradientCache(QGuiGLContext *ctx)
+    : QGLSharedResource(ctx->shareGroup())
+{
+}
+
+QGL2GradientCache::~QGL2GradientCache()
+{
+    cache.clear();
+}
+
 QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
 {
     return qt_gradient_caches()->cacheForContext(context);
 }
 
+void QGL2GradientCache::invalidateResource()
+{
+    QMutexLocker lock(&m_mutex);
+    cache.clear();
+}
+
+void QGL2GradientCache::freeResource(QGuiGLContext *)
+{
+    cleanCache();
+}
+
 void QGL2GradientCache::cleanCache()
 {
     QMutexLocker lock(&m_mutex);
index 1c2d0a0..1b001c3 100644 (file)
@@ -58,7 +58,7 @@
 
 QT_BEGIN_NAMESPACE
 
-class QGL2GradientCache
+class QGL2GradientCache : public QGLSharedResource
 {
     struct CacheInfo
     {
@@ -76,12 +76,15 @@ class QGL2GradientCache
 public:
     static QGL2GradientCache *cacheForContext(const QGLContext *context);
 
-    QGL2GradientCache(const QGLContext *) {}
-    ~QGL2GradientCache() { cleanCache(); }
+    QGL2GradientCache(QGuiGLContext *);
+    ~QGL2GradientCache();
 
     GLuint getBuffer(const QGradient &gradient, qreal opacity);
     inline int paletteSize() const { return 1024; }
 
+    void invalidateResource();
+    void freeResource(QGuiGLContext *ctx);
+
 private:
     inline int maxCacheSize() const { return 60; }
     inline void generateGradientColorTable(const QGradient& gradient,
index 49d6b29..771d42b 100644 (file)
@@ -1580,10 +1580,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
 
     QGLTextureGlyphCache *cache =
             (QGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(cacheKey, glyphType, QTransform());
-    if (!cache || cache->cacheType() != glyphType || cache->context() == 0) {
-        cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
+    if (!cache || cache->cacheType() != glyphType || cache->contextGroup() == 0) {
+        cache = new QGLTextureGlyphCache(glyphType, QTransform());
         staticTextItem->fontEngine()->setGlyphCache(cacheKey, cache);
-        cache->insert(ctx, cache);
         recreateVertexArrays = true;
     }
 
index 4838ab0..214bfa5 100644 (file)
@@ -51,19 +51,16 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled;
 
 QBasicAtomicInt qgltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
 
-QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
-    : QImageTextureGlyphCache(type, matrix), QGLContextGroupResourceBase()
-    , ctx(0)
+QGLTextureGlyphCache::QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix)
+    : QImageTextureGlyphCache(type, matrix)
     , pex(0)
     , m_blitProgram(0)
     , m_filterMode(Nearest)
     , m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
 {
 #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
-    qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, ctx);
+    qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, QGuiGLContext::currentContext());
 #endif
-    setContext(context);
-
     m_vertexCoordinateArray[0] = -1.0f;
     m_vertexCoordinateArray[1] = -1.0f;
     m_vertexCoordinateArray[2] =  1.0f;
@@ -91,14 +88,9 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache()
     delete m_blitProgram;
 }
 
-void QGLTextureGlyphCache::setContext(const QGLContext *context)
-{
-    ctx = context;
-    m_h = 0;
-}
-
 void QGLTextureGlyphCache::createTextureData(int width, int height)
 {
+    QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     if (ctx == 0) {
         qWarning("QGLTextureGlyphCache::createTextureData: Called with no context");
         return;
@@ -116,12 +108,17 @@ void QGLTextureGlyphCache::createTextureData(int width, int height)
     if (height < 16)
         height = 16;
 
-    QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
-    glGenTextures(1, &glyphTexture->m_texture);
-    glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
+    if (m_textureResource && !m_textureResource->m_texture)
+        delete m_textureResource;
 
-    glyphTexture->m_width = width;
-    glyphTexture->m_height = height;
+    if (!m_textureResource)
+        m_textureResource = new QGLGlyphTexture(ctx);
+
+    glGenTextures(1, &m_textureResource->m_texture);
+    glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
+
+    m_textureResource->m_width = width;
+    m_textureResource->m_height = height;
 
     if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
         QVarLengthArray<uchar> data(width * height * 4);
@@ -144,14 +141,14 @@ void QGLTextureGlyphCache::createTextureData(int width, int height)
 
 void QGLTextureGlyphCache::resizeTextureData(int width, int height)
 {
+    QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     if (ctx == 0) {
         qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context");
         return;
     }
-    QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
 
-    int oldWidth = glyphTexture->m_width;
-    int oldHeight = glyphTexture->m_height;
+    int oldWidth = m_textureResource->m_width;
+    int oldHeight = m_textureResource->m_height;
 
     // Make the lower glyph texture size 16 x 16.
     if (width < 16)
@@ -159,7 +156,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
     if (height < 16)
         height = 16;
 
-    GLuint oldTexture = glyphTexture->m_texture;
+    GLuint oldTexture = m_textureResource->m_texture;
     createTextureData(width, height);
 
     if (ctx->d_ptr->workaround_brokenFBOReadBack) {
@@ -173,7 +170,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
     // ### the QTextureGlyphCache API needs to be reworked to allow
     // ### resizeTextureData to fail
 
-    glBindFramebuffer(GL_FRAMEBUFFER_EXT, glyphTexture->m_fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_textureResource->m_fbo);
 
     GLuint tmp_texture;
     glGenTextures(1, &tmp_texture);
@@ -257,7 +254,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
 
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
-    glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
+    glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
 
     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
 
@@ -276,16 +273,16 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
 
 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
 {
+    QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     if (ctx == 0) {
         qWarning("QGLTextureGlyphCache::fillTexture: Called with no context");
         return;
     }
 
-    QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
     if (ctx->d_ptr->workaround_brokenFBOReadBack) {
         QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition);
 
-        glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
+        glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
         const QImage &texture = image();
         const uchar *bits = texture.constBits();
         bits += c.y * texture.bytesPerLine() + c.x;
@@ -322,7 +319,7 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed sub
         }
     }
 
-    glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
+    glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
     if (mask.format() == QImage::Format_RGB32) {
         glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
     } else {
@@ -358,6 +355,7 @@ int QGLTextureGlyphCache::glyphPadding() const
 
 int QGLTextureGlyphCache::maxTextureWidth() const
 {
+    QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     if (ctx == 0)
         return QImageTextureGlyphCache::maxTextureWidth();
     else
@@ -366,6 +364,7 @@ int QGLTextureGlyphCache::maxTextureWidth() const
 
 int QGLTextureGlyphCache::maxTextureHeight() const
 {
+    QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     if (ctx == 0)
         return QImageTextureGlyphCache::maxTextureHeight();
 
@@ -377,16 +376,15 @@ int QGLTextureGlyphCache::maxTextureHeight() const
 
 void QGLTextureGlyphCache::clear()
 {
-    if (ctx != 0) {
-        m_textureResource.cleanup(ctx);
-
-        m_w = 0;
-        m_h = 0;
-        m_cx = 0;
-        m_cy = 0;
-        m_currentRowHeight = 0;
-        coords.clear();
-    }
+    m_textureResource->free();
+    m_textureResource = 0;
+
+    m_w = 0;
+    m_h = 0;
+    m_cx = 0;
+    m_cy = 0;
+    m_currentRowHeight = 0;
+    coords.clear();
 }
 
 QT_END_NAMESPACE
index 83ca06d..2fcc551 100644 (file)
@@ -63,10 +63,11 @@ QT_BEGIN_NAMESPACE
 
 class QGL2PaintEngineExPrivate;
 
-struct QGLGlyphTexture
+struct QGLGlyphTexture : public QGLSharedResource
 {
     QGLGlyphTexture(const QGLContext *ctx)
-        : m_width(0)
+        : QGLSharedResource(ctx->contextHandle()->shareGroup())
+        , m_width(0)
         , m_height(0)
     {
         if (ctx && !ctx->d_ptr->workaround_brokenFBOReadBack)
@@ -77,19 +78,24 @@ struct QGLGlyphTexture
 #endif
     }
 
-    ~QGLGlyphTexture() {
-        const QGLContext *ctx = QGLContext::currentContext();
+    void freeResource(QGuiGLContext *context)
+    {
+        const QGLContext *ctx = QGLContext::fromGuiGLContext(context);
 #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
         qDebug("~QGLGlyphTexture() %p for context %p.", this, ctx);
 #endif
-        // At this point, the context group is made current, so it's safe to
-        // release resources without a makeCurrent() call
-        if (ctx) {
-            if (!ctx->d_ptr->workaround_brokenFBOReadBack)
-                glDeleteFramebuffers(1, &m_fbo);
-            if (m_width || m_height)
-                glDeleteTextures(1, &m_texture);
-        }
+        if (!ctx->d_ptr->workaround_brokenFBOReadBack)
+            glDeleteFramebuffers(1, &m_fbo);
+        if (m_width || m_height)
+            glDeleteTextures(1, &m_texture);
+    }
+
+    void invalidateResource()
+    {
+        m_texture = 0;
+        m_fbo = 0;
+        m_width = 0;
+        m_height = 0;
     }
 
     GLuint m_texture;
@@ -98,10 +104,10 @@ struct QGLGlyphTexture
     int m_height;
 };
 
-class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache, public QGLContextGroupResourceBase
+class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache
 {
 public:
-    QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
+    QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix);
     ~QGLTextureGlyphCache();
 
     virtual void createTextureData(int width, int height);
@@ -113,25 +119,24 @@ public:
 
     inline GLuint texture() const {
         QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
-        QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
+        QGLGlyphTexture *glyphTexture = that->m_textureResource;
         return glyphTexture ? glyphTexture->m_texture : 0;
     }
 
     inline int width() const {
         QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
-        QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
+        QGLGlyphTexture *glyphTexture = that->m_textureResource;
         return glyphTexture ? glyphTexture->m_width : 0;
     }
     inline int height() const {
         QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
-        QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
+        QGLGlyphTexture *glyphTexture = that->m_textureResource;
         return glyphTexture ? glyphTexture->m_height : 0;
     }
 
     inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
 
-    void setContext(const QGLContext *context);
-    inline const QGLContext *context() const { return ctx; }
+    inline const QGuiGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; }
 
     inline int serialNumber() const { return m_serialNumber; }
 
@@ -144,12 +149,9 @@ public:
 
     void clear();
 
-    void freeResource(void *) { ctx = 0; }
-
 private:
-    QGLContextGroupResource<QGLGlyphTexture> m_textureResource;
+    QGLGlyphTexture *m_textureResource;
 
-    const QGLContext *ctx;
     QGL2PaintEngineExPrivate *pex;
     QGLShaderProgram *m_blitProgram;
     FilterMode m_filterMode;
index 8ef1fc3..f518828 100644 (file)
@@ -1476,42 +1476,16 @@ Q_GLOBAL_STATIC(QGLContextGroupList, qt_context_groups)
  *****************************************************************************/
 
 QGLContextGroup::QGLContextGroup(const QGLContext *context)
-    : m_context(context), m_guards(0), m_refs(1)
+    : m_context(context), m_refs(1)
 {
     qt_context_groups()->append(this);
 }
 
 QGLContextGroup::~QGLContextGroup()
 {
-    // Clear any remaining QGLSharedResourceGuard objects on the group.
-    QGLSharedResourceGuard *guard = m_guards;
-    while (guard != 0) {
-        guard->m_group = 0;
-        guard->m_id = 0;
-        guard = guard->m_next;
-    }
     qt_context_groups()->remove(this);
 }
 
-void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard)
-{
-    if (m_guards)
-        m_guards->m_prev = guard;
-    guard->m_next = m_guards;
-    guard->m_prev = 0;
-    m_guards = guard;
-}
-
-void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard)
-{
-    if (guard->m_next)
-        guard->m_next->m_prev = guard->m_prev;
-    if (guard->m_prev)
-        guard->m_prev->m_next = guard->m_next;
-    else
-        m_guards = guard->m_next;
-}
-
 const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
 {
     if (!ctx)
@@ -1934,8 +1908,6 @@ QGLContext::~QGLContext()
 
     // clean up resources specific to this context
     d_ptr->cleanup();
-    // clean up resources belonging to this context's group
-    d_ptr->group->cleanupResources(this);
 
     QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
     reset();
@@ -5017,108 +4989,6 @@ void QGLContextGroup::removeShare(const QGLContext *context) {
         group->m_shares.clear();
 }
 
-QGLContextGroupResourceBase::QGLContextGroupResourceBase()
-    : active(0)
-{
-#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
-    qDebug("Creating context group resource object %p.", this);
-#endif
-}
-
-QGLContextGroupResourceBase::~QGLContextGroupResourceBase()
-{
-#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
-    qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
-#endif
-    for (int i = 0; i < m_groups.size(); ++i) {
-        m_groups.at(i)->m_resources.remove(this);
-        active.deref();
-    }
-#ifndef QT_NO_DEBUG
-    if (active != 0) {
-        qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
-                 "          This is possibly caused by a leaked QGLWidget, \n"
-                 "          QGLFramebufferObject or QGLPixelBuffer.");
-    }
-#endif
-}
-
-void QGLContextGroupResourceBase::insert(const QGLContext *context, void *value)
-{
-#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
-    qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
-#endif
-    QGLContextGroup *group = QGLContextPrivate::contextGroup(context);
-    Q_ASSERT(!group->m_resources.contains(this));
-    group->m_resources.insert(this, value);
-    m_groups.append(group);
-    active.ref();
-}
-
-void *QGLContextGroupResourceBase::value(const QGLContext *context)
-{
-    QGLContextGroup *group = QGLContextPrivate::contextGroup(context);
-    return group->m_resources.value(this, 0);
-}
-
-void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx)
-{
-    void *resource = value(ctx);
-
-    if (resource != 0) {
-        QGLShareContextScope scope(ctx);
-        freeResource(resource);
-
-        QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx);
-        group->m_resources.remove(this);
-        m_groups.removeOne(group);
-        active.deref();
-    }
-}
-
-void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value)
-{
-#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
-    qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread());
-#endif
-    QGLShareContextScope scope(ctx);
-    freeResource(value);
-    active.deref();
-
-    QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx);
-    m_groups.removeOne(group);
-}
-
-void QGLContextGroup::cleanupResources(const QGLContext *context)
-{
-    // If there are still shares, then no cleanup to be done yet.
-    if (m_shares.size() > 1)
-        return;
-
-    // Iterate over all resources and free each in turn.
-    QHash<QGLContextGroupResourceBase *, void *>::ConstIterator it;
-    for (it = m_resources.begin(); it != m_resources.end(); ++it)
-        it.key()->cleanup(context, it.value());
-}
-
-QGLSharedResourceGuard::~QGLSharedResourceGuard()
-{
-    if (m_group)
-        m_group->removeGuard(this);
-}
-
-void QGLSharedResourceGuard::setContext(const QGLContext *context)
-{
-    if (m_group)
-        m_group->removeGuard(this);
-    if (context) {
-        m_group = QGLContextPrivate::contextGroup(context);
-        m_group->addGuard(this);
-    } else {
-        m_group = 0;
-    }
-}
-
 QSize QGLTexture::bindCompressedTexture
     (const QString& fileName, const char *format)
 {
index c25ea16..a12cddc 100644 (file)
@@ -374,7 +374,6 @@ private:
     friend class QGLTextureGlyphCache;
     friend struct QGLGlyphTexture;
     friend class QGLContextGroup;
-    friend class QGLSharedResourceGuard;
     friend class QGLPixmapBlurFilter;
     friend class QGLExtensions;
     friend class QGLTexture;
index d132b97..58efc7f 100644 (file)
@@ -61,6 +61,7 @@
 #include "QtCore/qhash.h"
 #include "QtCore/qatomic.h"
 #include "QtWidgets/private/qwidget_p.h"
+#include "QtGui/private/qguiglcontext_qpa_p.h"
 #include "qcache.h"
 #include "qglpaintdevice_p.h"
 
@@ -177,9 +178,6 @@ public:
     bool disable_clear_on_painter_begin;
 };
 
-class QGLContextGroupResourceBase;
-class QGLSharedResourceGuard;
-
 // QGLContextPrivate has the responsibility of creating context groups.
 // QGLContextPrivate maintains the reference counter and destroys
 // context groups when needed.
@@ -193,9 +191,6 @@ public:
     bool isSharing() const { return m_shares.size() >= 2; }
     QList<const QGLContext *> shares() const { return m_shares; }
 
-    void addGuard(QGLSharedResourceGuard *guard);
-    void removeGuard(QGLSharedResourceGuard *guard);
-
     static void addShare(const QGLContext *context, const QGLContext *share);
     static void removeShare(const QGLContext *context);
 
@@ -205,12 +200,8 @@ private:
     QGLExtensionFuncs m_extensionFuncs;
     const QGLContext *m_context; // context group's representative
     QList<const QGLContext *> m_shares;
-    QHash<QGLContextGroupResourceBase *, void *> m_resources;
-    QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
     QAtomicInt m_refs;
 
-    void cleanupResources(const QGLContext *ctx);
-
     friend class QGLContext;
     friend class QGLContextPrivate;
     friend class QGLContextGroupResourceBase;
@@ -539,114 +530,69 @@ QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key)
 
 extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
 
-/*
-   Base for resources that are shared in a context group.
-*/
-class Q_OPENGL_EXPORT QGLContextGroupResourceBase
-{
-public:
-    QGLContextGroupResourceBase();
-    virtual ~QGLContextGroupResourceBase();
-    void insert(const QGLContext *context, void *value);
-    void *value(const QGLContext *context);
-    void cleanup(const QGLContext *context);
-    void cleanup(const QGLContext *context, void *value);
-    virtual void freeResource(void *value) = 0;
-
-protected:
-    QList<QGLContextGroup *> m_groups;
-
-private:
-    QAtomicInt active;
-};
-
-/*
-   The QGLContextGroupResource template is used to manage a resource
-   for a group of sharing GL contexts. When the last context in the
-   group is destroyed, or when the QGLContextGroupResource object
-   itself is destroyed (implies potential context switches), the
-   resource will be freed.
-
-   The class used as the template class type needs to have a
-   constructor with the following signature:
-     T(const QGLContext *);
-*/
-template <class T>
-class QGLContextGroupResource : public QGLContextGroupResourceBase
-{
-public:
-    ~QGLContextGroupResource() {
-        for (int i = 0; i < m_groups.size(); ++i) {
-            const QGLContext *context = m_groups.at(i)->context();
-            T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
-            if (resource) {
-                QGLShareContextScope scope(context);
-                delete resource;
-            }
-        }
-    }
-
-    T *value(const QGLContext *context) {
-        T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
-        if (!resource) {
-            resource = new T(context);
-            insert(context, resource);
-        }
-        return resource;
-    }
-
-protected:
-    void freeResource(void *resource) {
-        delete reinterpret_cast<T *>(resource);
-    }
-};
-
 // Put a guard around a GL object identifier and its context.
 // When the context goes away, a shared context will be used
 // in its place.  If there are no more shared contexts, then
 // the identifier is returned as zero - it is assumed that the
 // context destruction cleaned up the identifier in this case.
-class Q_OPENGL_EXPORT QGLSharedResourceGuard
+class Q_OPENGL_EXPORT QGLSharedResourceGuardBase : public QGLSharedResource
 {
 public:
-    QGLSharedResourceGuard(const QGLContext *context)
-        : m_group(0), m_id(0), m_next(0), m_prev(0)
+    QGLSharedResourceGuardBase(QGLContext *context, GLuint id)
+        : QGLSharedResource(context->contextHandle()->shareGroup())
+        , m_id(id)
+    {
+    }
+
+    GLuint id() const
     {
-        setContext(context);
+        return m_id;
     }
-    QGLSharedResourceGuard(const QGLContext *context, GLuint id)
-        : m_group(0), m_id(id), m_next(0), m_prev(0)
+
+protected:
+    void invalidateResource()
     {
-        setContext(context);
+        m_id = 0;
     }
-    ~QGLSharedResourceGuard();
 
-    const QGLContext *context() const
+    void freeResource(QGuiGLContext *context)
     {
-        return m_group ? m_group->context() : 0;
+        if (m_id) {
+            freeResource(QGLContext::fromGuiGLContext(context), m_id);
+        }
     }
 
-    void setContext(const QGLContext *context);
+    virtual void freeResource(QGLContext *ctx, GLuint id) = 0;
 
-    GLuint id() const
+private:
+    GLuint m_id;
+};
+
+template <typename Func>
+class QGLSharedResourceGuard : public QGLSharedResourceGuardBase
+{
+public:
+    QGLSharedResourceGuard(QGLContext *context, GLuint id, Func func)
+        : QGLSharedResourceGuardBase(context, id)
+        , m_func(func)
     {
-        return m_id;
     }
 
-    void setId(GLuint id)
+protected:
+    void freeResource(QGLContext *ctx, GLuint id)
     {
-        m_id = id;
+        m_func(ctx, id);
     }
 
 private:
-    QGLContextGroup *m_group;
-    GLuint m_id;
-    QGLSharedResourceGuard *m_next;
-    QGLSharedResourceGuard *m_prev;
-
-    friend class QGLContextGroup;
+    Func m_func;
 };
 
+template <typename Func>
+QGLSharedResourceGuardBase *createSharedResourceGuard(QGLContext *context, GLuint id, Func cleanupFunc)
+{
+    return new QGLSharedResourceGuard<Func>(context, id, cleanupFunc);
+}
 
 class QGLExtensionMatcher
 {
index 637e48d..53f2739 100644 (file)
@@ -141,7 +141,7 @@ public:
 
     QAtomicInt ref;
     QGLBuffer::Type type;
-    QGLSharedResourceGuard guard;
+    QGLSharedResourceGuardBase *guard;
     QGLBuffer::UsagePattern usagePattern;
     QGLBuffer::UsagePattern actualUsagePattern;
 };
@@ -184,7 +184,7 @@ QGLBuffer::QGLBuffer(const QGLBuffer &other)
     d_ptr->ref.ref();
 }
 
-#define ctx d->guard.context()
+#define ctx QGLContext::currentContext();
 
 /*!
     Destroys this buffer object, including the storage being
@@ -250,6 +250,14 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
 
 #undef ctx
 
+namespace {
+    void freeBufferFunc(QGLContext *ctx, GLuint id)
+    {
+        Q_UNUSED(ctx);
+        glDeleteBuffers(1, &id);
+    }
+}
+
 /*!
     Creates the buffer object in the GL server.  Returns true if
     the object was created; false otherwise.
@@ -266,24 +274,26 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
 bool QGLBuffer::create()
 {
     Q_D(QGLBuffer);
-    if (d->guard.id())
+    if (d->guard && d->guard->id())
         return true;
-    const QGLContext *ctx = QGLContext::currentContext();
+    QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     if (ctx) {
-        if (!qt_resolve_buffer_extensions(const_cast<QGLContext *>(ctx)))
+        if (!qt_resolve_buffer_extensions(ctx))
             return false;
         GLuint bufferId = 0;
         glGenBuffers(1, &bufferId);
         if (bufferId) {
-            d->guard.setContext(ctx);
-            d->guard.setId(bufferId);
+            if (d->guard)
+                d->guard->free();
+
+            d->guard = createSharedResourceGuard(ctx, bufferId, freeBufferFunc);
             return true;
         }
     }
     return false;
 }
 
-#define ctx d->guard.context()
+#define ctx QGLContext::currentContext()
 
 /*!
     Returns true if this buffer has been created; false otherwise.
@@ -293,7 +303,7 @@ bool QGLBuffer::create()
 bool QGLBuffer::isCreated() const
 {
     Q_D(const QGLBuffer);
-    return d->guard.id() != 0;
+    return d->guard && d->guard->id();
 }
 
 /*!
@@ -304,14 +314,10 @@ bool QGLBuffer::isCreated() const
 void QGLBuffer::destroy()
 {
     Q_D(QGLBuffer);
-    GLuint bufferId = d->guard.id();
-    if (bufferId) {
-        // Switch to the original creating context to destroy it.
-        QGLShareContextScope scope(d->guard.context());
-        glDeleteBuffers(1, &bufferId);
+    if (d->guard) {
+        d->guard->free();
+        d->guard = 0;
     }
-    d->guard.setId(0);
-    d->guard.setContext(0);
 }
 
 /*!
@@ -358,7 +364,7 @@ void QGLBuffer::write(int offset, const void *data, int count)
         qWarning("QGLBuffer::allocate(): buffer not created");
 #endif
     Q_D(QGLBuffer);
-    if (d->guard.id())
+    if (d->guard && d->guard->id())
         glBufferSubData(d->type, offset, count, data);
 }
 
@@ -378,7 +384,7 @@ void QGLBuffer::allocate(const void *data, int count)
         qWarning("QGLBuffer::allocate(): buffer not created");
 #endif
     Q_D(QGLBuffer);
-    if (d->guard.id())
+    if (d->guard && d->guard->id())
         glBufferData(d->type, count, data, d->actualUsagePattern);
 }
 
@@ -413,10 +419,9 @@ bool QGLBuffer::bind()
         qWarning("QGLBuffer::bind(): buffer not created");
 #endif
     Q_D(const QGLBuffer);
-    GLuint bufferId = d->guard.id();
+    GLuint bufferId = d->guard ? d->guard->id() : 0;
     if (bufferId) {
-        if (!QGLContext::areSharing(QGLContext::currentContext(),
-                                    d->guard.context())) {
+        if (d->guard->group() != QGuiGLContextGroup::currentContextGroup()) {
 #ifndef QT_NO_DEBUG
             qWarning("QGLBuffer::bind: buffer is not valid in the current context");
 #endif
@@ -445,7 +450,7 @@ void QGLBuffer::release()
         qWarning("QGLBuffer::release(): buffer not created");
 #endif
     Q_D(const QGLBuffer);
-    if (d->guard.id())
+    if (d->guard && d->guard->id())
         glBindBuffer(d->type, 0);
 }
 
@@ -471,7 +476,7 @@ void QGLBuffer::release(QGLBuffer::Type type)
         glBindBuffer(GLenum(type), 0);
 }
 
-#define ctx d->guard.context()
+#define ctx QGLContext::currentContext()
 
 /*!
     Returns the GL identifier associated with this buffer; zero if
@@ -482,7 +487,7 @@ void QGLBuffer::release(QGLBuffer::Type type)
 GLuint QGLBuffer::bufferId() const
 {
     Q_D(const QGLBuffer);
-    return d->guard.id();
+    return d->guard ? d->guard->id() : 0;
 }
 
 #ifndef GL_BUFFER_SIZE
@@ -501,7 +506,7 @@ GLuint QGLBuffer::bufferId() const
 int QGLBuffer::size() const
 {
     Q_D(const QGLBuffer);
-    if (!d->guard.id())
+    if (!d->guard || !d->guard->id())
         return -1;
     GLint value = -1;
     glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value);
@@ -529,7 +534,7 @@ void *QGLBuffer::map(QGLBuffer::Access access)
     if (!isCreated())
         qWarning("QGLBuffer::map(): buffer not created");
 #endif
-    if (!d->guard.id())
+    if (!d->guard || !d->guard->id())
         return 0;
     if (!glMapBufferARB)
         return 0;
@@ -556,7 +561,7 @@ bool QGLBuffer::unmap()
     if (!isCreated())
         qWarning("QGLBuffer::unmap(): buffer not created");
 #endif
-    if (!d->guard.id())
+    if (!d->guard || !d->guard->id())
         return false;
     if (!glUnmapBufferARB)
         return false;
index f35f6e5..2916844 100644 (file)
@@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE
 
 extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
 
-#define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context();
-#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
+#define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
+#define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
 
 #ifndef QT_NO_DEBUG
 #define QT_RESET_GLERROR()                                \
@@ -351,13 +351,7 @@ void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
 
 QGLContext *QGLFBOGLPaintDevice::context() const
 {
-    QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
-    QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
-
-    if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
-        return currentContext;
-    else
-        return fboContext;
+    return const_cast<QGLContext *>(QGLContext::currentContext());
 }
 
 bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
@@ -407,13 +401,33 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
     return false;
 }
 
+namespace
+{
+    void freeFramebufferFunc(QGLContext *ctx, GLuint id)
+    {
+        Q_UNUSED(ctx);
+        glDeleteFramebuffers(1, &id);
+    }
+
+    void freeRenderbufferFunc(QGLContext *ctx, GLuint id)
+    {
+        Q_UNUSED(ctx);
+        glDeleteRenderbuffers(1, &id);
+    }
+
+    void freeTextureFunc(QGLContext *ctx, GLuint id)
+    {
+        Q_UNUSED(ctx);
+        glDeleteTextures(1, &id);
+    }
+}
+
 void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
                                        QGLFramebufferObject::Attachment attachment,
                                        GLenum texture_target, GLenum internal_format,
                                        GLint samples, bool mipmap)
 {
     QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
-    fbo_guard.setContext(ctx);
 
     bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
     if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
@@ -427,9 +441,11 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
     GLuint fbo = 0;
     glGenFramebuffers(1, &fbo);
     glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
-    fbo_guard.setId(fbo);
 
-    glDevice.setFBO(q, attachment);
+    GLuint texture = 0;
+    GLuint color_buffer = 0;
+    GLuint depth_buffer = 0;
+    GLuint stencil_buffer = 0;
 
     QT_CHECK_GLERROR();
     // init texture
@@ -603,7 +619,21 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
     }
 
     glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
-    if (!valid) {
+    if (valid) {
+        fbo_guard = createSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
+        if (color_buffer)
+            color_buffer_guard = createSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
+        else
+            texture_guard = createSharedResourceGuard(ctx, texture, freeTextureFunc);
+        if (depth_buffer)
+            depth_buffer_guard = createSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
+        if (stencil_buffer) {
+            if (stencil_buffer == depth_buffer)
+                stencil_buffer_guard = depth_buffer_guard;
+            else
+                stencil_buffer_guard = createSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
+        }
+    } else {
         if (color_buffer)
             glDeleteRenderbuffers(1, &color_buffer);
         else
@@ -613,7 +643,6 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
         if (stencil_buffer && depth_buffer != stencil_buffer)
             glDeleteRenderbuffers(1, &stencil_buffer);
         glDeleteFramebuffers(1, &fbo);
-        fbo_guard.setId(0);
     }
     QT_CHECK_GLERROR();
 
@@ -622,6 +651,8 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
     format.setAttachment(fbo_attachment);
     format.setInternalTextureFormat(internal_format);
     format.setMipmap(mipmap);
+
+    glDevice.setFBO(q, attachment);
 }
 
 /*!
@@ -849,23 +880,19 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
 QGLFramebufferObject::~QGLFramebufferObject()
 {
     Q_D(QGLFramebufferObject);
-    QGL_FUNC_CONTEXT;
 
     delete d->engine;
 
-    if (isValid() && ctx) {
-        QGLShareContextScope scope(ctx);
-        if (d->texture)
-            glDeleteTextures(1, &d->texture);
-        if (d->color_buffer)
-            glDeleteRenderbuffers(1, &d->color_buffer);
-        if (d->depth_buffer)
-            glDeleteRenderbuffers(1, &d->depth_buffer);
-        if (d->stencil_buffer && d->stencil_buffer != d->depth_buffer)
-            glDeleteRenderbuffers(1, &d->stencil_buffer);
-        GLuint fbo = d->fbo();
-        glDeleteFramebuffers(1, &fbo);
-    }
+    if (d->texture_guard)
+        d->texture_guard->free();
+    if (d->color_buffer_guard)
+        d->color_buffer_guard->free();
+    if (d->depth_buffer_guard)
+        d->depth_buffer_guard->free();
+    if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
+        d->stencil_buffer_guard->free();
+    if (d->fbo_guard)
+        d->fbo_guard->free();
 }
 
 /*!
@@ -889,7 +916,7 @@ QGLFramebufferObject::~QGLFramebufferObject()
 bool QGLFramebufferObject::isValid() const
 {
     Q_D(const QGLFramebufferObject);
-    return d->valid && d->fbo_guard.context();
+    return d->valid && d->fbo_guard && d->fbo_guard->id();
 }
 
 /*!
@@ -972,7 +999,7 @@ bool QGLFramebufferObject::release()
 GLuint QGLFramebufferObject::texture() const
 {
     Q_D(const QGLFramebufferObject);
-    return d->texture;
+    return d->texture_guard ? d->texture_guard->id() : 0;
 }
 
 /*!
index f823612..61d39c6 100644 (file)
@@ -130,8 +130,9 @@ private:
 class QGLFramebufferObjectPrivate
 {
 public:
-    QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_buffer(0), stencil_buffer(0)
-                                  , color_buffer(0), valid(false), engine(0) {}
+    QGLFramebufferObjectPrivate() : fbo_guard(0), texture_guard(0), depth_buffer_guard(0)
+                                  , stencil_buffer_guard(0), color_buffer_guard(0)
+                                  , valid(false), engine(0) {}
     ~QGLFramebufferObjectPrivate() {}
 
     void init(QGLFramebufferObject *q, const QSize& sz,
@@ -139,11 +140,11 @@ public:
               GLenum internal_format, GLenum texture_target,
               GLint samples = 0, bool mipmap = false);
     bool checkFramebufferStatus() const;
-    QGLSharedResourceGuard fbo_guard;
-    GLuint texture;
-    GLuint depth_buffer;
-    GLuint stencil_buffer;
-    GLuint color_buffer;
+    QGLSharedResourceGuardBase *fbo_guard;
+    QGLSharedResourceGuardBase *texture_guard;
+    QGLSharedResourceGuardBase *depth_buffer_guard;
+    QGLSharedResourceGuardBase *stencil_buffer_guard;
+    QGLSharedResourceGuardBase *color_buffer_guard;
     GLenum target;
     QSize size;
     QGLFramebufferObjectFormat format;
@@ -152,7 +153,7 @@ public:
     mutable QPaintEngine *engine;
     QGLFBOGLPaintDevice glDevice;
 
-    inline GLuint fbo() const { return fbo_guard.id(); }
+    inline GLuint fbo() const { return fbo_guard ? fbo_guard->id() : 0; }
 };
 
 
index 48549fb..534c6c8 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "qglfunctions.h"
 #include "qgl_p.h"
+#include "QtGui/private/qguiglcontext_qpa_p.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -139,16 +140,27 @@ QT_BEGIN_NAMESPACE
 */
 
 // Hidden private fields for additional extension data.
-struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate
+struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResource
 {
-    QGLFunctionsPrivateEx(const QGLContext *context = 0)
-        : QGLFunctionsPrivate(context)
+    QGLFunctionsPrivateEx(QGuiGLContext *context)
+        : QGLFunctionsPrivate(QGLContext::fromGuiGLContext(context))
+        , QGLSharedResource(context->shareGroup())
         , m_features(-1) {}
 
+    void invalidateResource()
+    {
+        m_features = -1;
+    }
+
+    void freeResource(QGuiGLContext *)
+    {
+        // no gl resources to free
+    }
+
     int m_features;
 };
 
-Q_GLOBAL_STATIC(QGLContextGroupResource<QGLFunctionsPrivateEx>, qt_gl_functions_resource)
+Q_GLOBAL_STATIC(QGLMultiGroupSharedResource, qt_gl_functions_resource)
 
 static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0)
 {
@@ -157,13 +169,7 @@ static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0)
     Q_ASSERT(context);
     QGLFunctionsPrivateEx *funcs =
         reinterpret_cast<QGLFunctionsPrivateEx *>
-            (qt_gl_functions_resource()->value(context));
-#if QT_VERSION < 0x040800
-    if (!funcs) {
-        funcs = new QGLFunctionsPrivateEx();
-        qt_gl_functions_resource()->insert(context, funcs);
-    }
-#endif
+            (qt_gl_functions_resource()->value<QGLFunctionsPrivateEx>(context->contextHandle()));
     return funcs;
 }
 
index de03553..7b3f5d9 100644 (file)
@@ -189,15 +189,15 @@ class QGLShaderPrivate : public QObjectPrivate
 {
     Q_DECLARE_PUBLIC(QGLShader)
 public:
-    QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type)
-        : shaderGuard(context)
+    QGLShaderPrivate(const QGLContext *, QGLShader::ShaderType type)
+        : shaderGuard(0)
         , shaderType(type)
         , compiled(false)
     {
     }
     ~QGLShaderPrivate();
 
-    QGLSharedResourceGuard shaderGuard;
+    QGLSharedResourceGuardBase *shaderGuard;
     QGLShader::ShaderType shaderType;
     bool compiled;
     QString log;
@@ -207,22 +207,28 @@ public:
     void deleteShader();
 };
 
-#define ctx shaderGuard.context()
+namespace {
+    void freeShaderFunc(QGLContext *ctx, GLuint id)
+    {
+        Q_UNUSED(ctx);
+        glDeleteShader(id);
+    }
+}
+
+#define ctx QGLContext::currentContext()
 
 QGLShaderPrivate::~QGLShaderPrivate()
 {
-    if (shaderGuard.id()) {
-        QGLShareContextScope scope(shaderGuard.context());
-        glDeleteShader(shaderGuard.id());
-    }
+    if (shaderGuard)
+        shaderGuard->free();
 }
 
 bool QGLShaderPrivate::create()
 {
-    const QGLContext *context = shaderGuard.context();
+    QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
     if (!context)
         return false;
-    if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
+    if (qt_resolve_glsl_extensions(context)) {
         GLuint shader;
         if (shaderType == QGLShader::Vertex)
             shader = glCreateShader(GL_VERTEX_SHADER);
@@ -234,7 +240,7 @@ bool QGLShaderPrivate::create()
             qWarning() << "QGLShader: could not create shader";
             return false;
         }
-        shaderGuard.setId(shader);
+        shaderGuard = createSharedResourceGuard(context, shader, freeShaderFunc);
         return true;
     } else {
         return false;
@@ -243,7 +249,7 @@ bool QGLShaderPrivate::create()
 
 bool QGLShaderPrivate::compile(QGLShader *q)
 {
-    GLuint shader = shaderGuard.id();
+    GLuint shader = shaderGuard ? shaderGuard->id() : 0;
     if (!shader)
         return false;
     glCompileShader(shader);
@@ -286,15 +292,12 @@ bool QGLShaderPrivate::compile(QGLShader *q)
 
 void QGLShaderPrivate::deleteShader()
 {
-    if (shaderGuard.id()) {
-        glDeleteShader(shaderGuard.id());
-        shaderGuard.setId(0);
+    if (shaderGuard) {
+        shaderGuard->free();
+        shaderGuard = 0;
     }
 }
 
-#undef ctx
-#define ctx d->shaderGuard.context()
-
 /*!
     Constructs a new QGLShader object of the specified \a type
     and attaches it to \a parent.  If shader programs are not supported,
@@ -387,7 +390,7 @@ static const char redefineHighp[] =
 bool QGLShader::compileSourceCode(const char *source)
 {
     Q_D(QGLShader);
-    if (d->shaderGuard.id()) {
+    if (d->shaderGuard && d->shaderGuard->id()) {
         QVarLengthArray<const char *, 4> src;
         QVarLengthArray<GLint, 4> srclen;
         int headerLen = 0;
@@ -420,7 +423,7 @@ bool QGLShader::compileSourceCode(const char *source)
 #endif
         src.append(source + headerLen);
         srclen.append(GLint(qstrlen(source + headerLen)));
-        glShaderSource(d->shaderGuard.id(), src.size(), src.data(), srclen.data());
+        glShaderSource(d->shaderGuard->id(), src.size(), src.data(), srclen.data());
         return d->compile(this);
     } else {
         return false;
@@ -480,7 +483,7 @@ bool QGLShader::compileSourceFile(const QString& fileName)
 QByteArray QGLShader::sourceCode() const
 {
     Q_D(const QGLShader);
-    GLuint shader = d->shaderGuard.id();
+    GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0;
     if (!shader)
         return QByteArray();
     GLint size = 0;
@@ -525,22 +528,17 @@ QString QGLShader::log() const
 GLuint QGLShader::shaderId() const
 {
     Q_D(const QGLShader);
-    return d->shaderGuard.id();
+    return d->shaderGuard ? d->shaderGuard->id() : 0;
 }
 
-
-
-
-
 #undef ctx
-#define ctx programGuard.context()
 
 class QGLShaderProgramPrivate : public QObjectPrivate
 {
     Q_DECLARE_PUBLIC(QGLShaderProgram)
 public:
-    QGLShaderProgramPrivate(const QGLContext *context)
-        : programGuard(context)
+    QGLShaderProgramPrivate(const QGLContext *)
+        : programGuard(0)
         , linked(false)
         , inited(false)
         , removingShaders(false)
@@ -551,7 +549,7 @@ public:
     }
     ~QGLShaderProgramPrivate();
 
-    QGLSharedResourceGuard programGuard;
+    QGLSharedResourceGuardBase *programGuard;
     bool linked;
     bool inited;
     bool removingShaders;
@@ -567,12 +565,19 @@ public:
     bool hasShader(QGLShader::ShaderType type) const;
 };
 
+namespace {
+    void freeProgramFunc(QGLContext *ctx, GLuint id)
+    {
+        Q_UNUSED(ctx);
+        glDeleteProgram(id);
+    }
+}
+
+
 QGLShaderProgramPrivate::~QGLShaderProgramPrivate()
 {
-    if (programGuard.id()) {
-        QGLShareContextScope scope(programGuard.context());
-        glDeleteProgram(programGuard.id());
-    }
+    if (programGuard)
+        programGuard->free();
 }
 
 bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
@@ -584,8 +589,7 @@ bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
     return false;
 }
 
-#undef ctx
-#define ctx d->programGuard.context()
+#define ctx QGLContext::currentContext()
 
 /*!
     Constructs a new shader program and attaches it to \a parent.
@@ -623,24 +627,21 @@ QGLShaderProgram::~QGLShaderProgram()
 bool QGLShaderProgram::init()
 {
     Q_D(QGLShaderProgram);
-    if (d->programGuard.id() || d->inited)
+    if ((d->programGuard && d->programGuard->id()) || d->inited)
         return true;
     d->inited = true;
-    const QGLContext *context = d->programGuard.context();
-    if (!context) {
-        context = QGLContext::currentContext();
-        d->programGuard.setContext(context);
-    }
-
+    QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
     if (!context)
         return false;
-    if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
+    if (qt_resolve_glsl_extensions(context)) {
         GLuint program = glCreateProgram();
         if (!program) {
             qWarning() << "QGLShaderProgram: could not create shader program";
             return false;
         }
-        d->programGuard.setId(program);
+        if (d->programGuard)
+            delete d->programGuard;
+        d->programGuard = createSharedResourceGuard(context, program, freeProgramFunc);
         return true;
     } else {
         qWarning() << "QGLShaderProgram: shader programs are not supported";
@@ -667,15 +668,14 @@ bool QGLShaderProgram::addShader(QGLShader *shader)
         return false;
     if (d->shaders.contains(shader))
         return true;    // Already added to this shader program.
-    if (d->programGuard.id() && shader) {
-        if (!QGLContext::areSharing(shader->d_func()->shaderGuard.context(),
-                                    d->programGuard.context())) {
+    if (d->programGuard && d->programGuard->id() && shader) {
+        if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id())
+            return false;
+        if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) {
             qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context.");
             return false;
         }
-        if (!shader->d_func()->shaderGuard.id())
-            return false;
-        glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
+        glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
         d->linked = false;  // Program needs to be relinked.
         d->shaders.append(shader);
         connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
@@ -784,14 +784,17 @@ bool QGLShaderProgram::addShaderFromSourceFile
 /*!
     Removes \a shader from this shader program.  The object is not deleted.
 
+    The shader program must be valid in the current QGLContext.
+
     \sa addShader(), link(), removeAllShaders()
 */
 void QGLShaderProgram::removeShader(QGLShader *shader)
 {
     Q_D(QGLShaderProgram);
-    if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) {
-        QGLShareContextScope scope(d->programGuard.context());
-        glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
+    if (d->programGuard && d->programGuard->id()
+        && shader && shader->d_func()->shaderGuard)
+    {
+        glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
     }
     d->linked = false;  // Program needs to be relinked.
     if (shader) {
@@ -826,8 +829,11 @@ void QGLShaderProgram::removeAllShaders()
     Q_D(QGLShaderProgram);
     d->removingShaders = true;
     foreach (QGLShader *shader, d->shaders) {
-        if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id())
-            glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
+        if (d->programGuard && d->programGuard->id()
+            && shader && shader->d_func()->shaderGuard)
+        {
+            glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
+        }
     }
     foreach (QGLShader *shader, d->anonShaders) {
         // Delete shader objects that were created anonymously.
@@ -856,7 +862,7 @@ void QGLShaderProgram::removeAllShaders()
 bool QGLShaderProgram::link()
 {
     Q_D(QGLShaderProgram);
-    GLuint program = d->programGuard.id();
+    GLuint program = d->programGuard ? d->programGuard->id() : 0;
     if (!program)
         return false;
 
@@ -946,13 +952,13 @@ QString QGLShaderProgram::log() const
 bool QGLShaderProgram::bind()
 {
     Q_D(QGLShaderProgram);
-    GLuint program = d->programGuard.id();
+    GLuint program = d->programGuard ? d->programGuard->id() : 0;
     if (!program)
         return false;
     if (!d->linked && !link())
         return false;
 #ifndef QT_NO_DEBUG
-    if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) {
+    if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup()) {
         qWarning("QGLShaderProgram::bind: program is not valid in the current context.");
         return false;
     }
@@ -974,7 +980,7 @@ void QGLShaderProgram::release()
 {
 #ifndef QT_NO_DEBUG
     Q_D(QGLShaderProgram);
-    if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext()))
+    if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup())
         qWarning("QGLShaderProgram::release: program is not valid in the current context.");
 #endif
 #if defined(QT_OPENGL_ES_2)
@@ -996,7 +1002,7 @@ void QGLShaderProgram::release()
 GLuint QGLShaderProgram::programId() const
 {
     Q_D(const QGLShaderProgram);
-    GLuint id = d->programGuard.id();
+    GLuint id = d->programGuard ? d->programGuard->id() : 0;
     if (id)
         return id;
 
@@ -1005,7 +1011,7 @@ GLuint QGLShaderProgram::programId() const
     // themselves, particularly those using program binaries.
     if (!const_cast<QGLShaderProgram *>(this)->init())
         return 0;
-    return d->programGuard.id();
+    return d->programGuard ? d->programGuard->id() : 0;
 }
 
 /*!
@@ -1022,9 +1028,9 @@ GLuint QGLShaderProgram::programId() const
 void QGLShaderProgram::bindAttributeLocation(const char *name, int location)
 {
     Q_D(QGLShaderProgram);
-    if (!init())
+    if (!init() || !d->programGuard || !d->programGuard->id())
         return;
-    glBindAttribLocation(d->programGuard.id(), location, name);
+    glBindAttribLocation(d->programGuard->id(), location, name);
     d->linked = false;  // Program needs to be relinked.
 }
 
@@ -1074,8 +1080,8 @@ void QGLShaderProgram::bindAttributeLocation(const QString& name, int location)
 int QGLShaderProgram::attributeLocation(const char *name) const
 {
     Q_D(const QGLShaderProgram);
-    if (d->linked) {
-        return glGetAttribLocation(d->programGuard.id(), name);
+    if (d->linked && d->programGuard && d->programGuard->id()) {
+        return glGetAttribLocation(d->programGuard->id(), name);
     } else {
         qWarning() << "QGLShaderProgram::attributeLocation(" << name
                    << "): shader program is not linked";
@@ -1752,8 +1758,8 @@ int QGLShaderProgram::uniformLocation(const char *name) const
 {
     Q_D(const QGLShaderProgram);
     Q_UNUSED(d);
-    if (d->linked) {
-        return glGetUniformLocation(d->programGuard.id(), name);
+    if (d->linked && d->programGuard && d->programGuard->id()) {
+        return glGetUniformLocation(d->programGuard->id(), name);
     } else {
         qWarning() << "QGLShaderProgram::uniformLocation(" << name
                    << "): shader program is not linked";