summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@nokia.com>2011-08-16 09:29:44 +0200
committerSamuel Rødal <samuel.rodal@nokia.com>2011-08-29 10:24:55 +0200
commitaaa4a26f82f99fa8724841eba91bad029306e0ce (patch)
tree3d24e874bff00efc0e73af610bc80e645d14f789
parent00fd783a39d55d2365ddead4fab2cc06091c119f (diff)
Move GL resource handling enablers to QtGui.
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>
-rw-r--r--src/gui/kernel/kernel.pri1
-rw-r--r--src/gui/kernel/qguiglcontext_qpa.cpp229
-rw-r--r--src/gui/kernel/qguiglcontext_qpa.h33
-rw-r--r--src/gui/kernel/qguiglcontext_qpa_p.h181
-rw-r--r--src/gui/kernel/qplatformglcontext_qpa.cpp2
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp55
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h1
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp25
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache_p.h9
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp5
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp70
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h48
-rw-r--r--src/opengl/qgl.cpp132
-rw-r--r--src/opengl/qgl.h1
-rw-r--r--src/opengl/qgl_p.h132
-rw-r--r--src/opengl/qglbuffer.cpp59
-rw-r--r--src/opengl/qglframebufferobject.cpp87
-rw-r--r--src/opengl/qglframebufferobject_p.h17
-rw-r--r--src/opengl/qglfunctions.cpp28
-rw-r--r--src/opengl/qglshaderprogram.cpp142
20 files changed, 772 insertions, 485 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 58291f5237..44d039512f 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -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 \
diff --git a/src/gui/kernel/qguiglcontext_qpa.cpp b/src/gui/kernel/qguiglcontext_qpa.cpp
index 2c43befbc9..71c830174e 100644
--- a/src/gui/kernel/qguiglcontext_qpa.cpp
+++ b/src/gui/kernel/qguiglcontext_qpa.cpp
@@ -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);
+}
+
diff --git a/src/gui/kernel/qguiglcontext_qpa.h b/src/gui/kernel/qguiglcontext_qpa.h
index 11a7e16a82..a234bd3cb6 100644
--- a/src/gui/kernel/qguiglcontext_qpa.h
+++ b/src/gui/kernel/qguiglcontext_qpa.h
@@ -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
index 0000000000..a9c8f5c75e
--- /dev/null
+++ b/src/gui/kernel/qguiglcontext_qpa_p.h
@@ -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
diff --git a/src/gui/kernel/qplatformglcontext_qpa.cpp b/src/gui/kernel/qplatformglcontext_qpa.cpp
index 81030b8cfe..5ce7db09e2 100644
--- a/src/gui/kernel/qplatformglcontext_qpa.cpp
+++ b/src/gui/kernel/qplatformglcontext_qpa.cpp
@@ -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)
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 4c50089f6d..05a612c311 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -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
@@ -52,18 +54,50 @@
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");
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 921df369f4..58c761df43 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -365,7 +365,6 @@ public:
void cleanupCustomStage(QGLCustomShaderStage* stage);
private:
- QGLSharedResourceGuard ctxGuard;
QGLShaderProgram *blitShaderProg;
QGLShaderProgram *simpleShaderProg;
QList<QGLEngineShaderProg*> cachedPrograms;
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index 9e6b801c40..bd408ffdc4 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -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);
diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h
index 1c2d0a029a..1b001c3405 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache_p.h
+++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h
@@ -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,
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 49d6b297e4..771d42be3f 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -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;
}
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
index 4838ab09e7..214bfa5b47 100644
--- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
@@ -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
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
index 83ca06d040..2fcc551667 100644
--- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
@@ -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;
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 8ef1fc38e5..f51882841b 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -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)
{
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index c25ea16e43..a12cddcca4 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -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;
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index d132b97260..58efc7f7fd 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -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
{
diff --git a/src/opengl/qglbuffer.cpp b/src/opengl/qglbuffer.cpp
index 637e48d27d..53f27392b0 100644
--- a/src/opengl/qglbuffer.cpp
+++ b/src/opengl/qglbuffer.cpp
@@ -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;
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index f35f6e513d..29168441b3 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -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;
}
/*!
diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h
index f82361279d..61d39c6a07 100644
--- a/src/opengl/qglframebufferobject_p.h
+++ b/src/opengl/qglframebufferobject_p.h
@@ -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; }
};
diff --git a/src/opengl/qglfunctions.cpp b/src/opengl/qglfunctions.cpp
index 48549fb8d2..534c6c8bbf 100644
--- a/src/opengl/qglfunctions.cpp
+++ b/src/opengl/qglfunctions.cpp
@@ -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;
}
diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp
index de03553d8f..7b3f5d998d 100644
--- a/src/opengl/qglshaderprogram.cpp
+++ b/src/opengl/qglshaderprogram.cpp
@@ -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";