summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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";