From aaa4a26f82f99fa8724841eba91bad029306e0ce Mon Sep 17 00:00:00 2001 From: =?utf8?q?Samuel=20R=C3=B8dal?= Date: Tue, 16 Aug 2011 09:29:44 +0200 Subject: [PATCH] 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 Reviewed-by: Gunnar Sletta --- src/gui/kernel/kernel.pri | 1 + src/gui/kernel/qguiglcontext_qpa.cpp | 229 ++++++++++++++++++--- src/gui/kernel/qguiglcontext_qpa.h | 33 ++- src/gui/kernel/qguiglcontext_qpa_p.h | 181 ++++++++++++++++ src/gui/kernel/qplatformglcontext_qpa.cpp | 2 + .../gl2paintengineex/qglengineshadermanager.cpp | 55 ++++- .../gl2paintengineex/qglengineshadermanager_p.h | 1 - src/opengl/gl2paintengineex/qglgradientcache.cpp | 25 ++- src/opengl/gl2paintengineex/qglgradientcache_p.h | 9 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 5 +- .../gl2paintengineex/qtextureglyphcache_gl.cpp | 70 +++---- .../gl2paintengineex/qtextureglyphcache_gl_p.h | 48 ++--- src/opengl/qgl.cpp | 132 +----------- src/opengl/qgl.h | 1 - src/opengl/qgl_p.h | 132 ++++-------- src/opengl/qglbuffer.cpp | 59 +++--- src/opengl/qglframebufferobject.cpp | 87 +++++--- src/opengl/qglframebufferobject_p.h | 17 +- src/opengl/qglfunctions.cpp | 28 ++- src/opengl/qglshaderprogram.cpp | 142 +++++++------ 20 files changed, 772 insertions(+), 485 deletions(-) create mode 100644 src/gui/kernel/qguiglcontext_qpa_p.h diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 58291f5..44d0395 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 2c43bef..71c8301 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 @@ -63,35 +64,6 @@ public: static QThreadStorage 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::iterator it = d->m_sharedResources.begin(); + QList::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 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::iterator it = m_pendingDeletion.begin(); + QList::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 11a7e16..a234bd3 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 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 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 0000000..a9c8f5c --- /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 +#include + +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 m_shares; + QMutex m_mutex; + + QHash m_resources; + QAtomicInt m_refs; + + QList m_sharedResources; + QList 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 + T *value(QGuiGLContext *context) { + QGuiGLContextGroup *group = context->shareGroup(); + T *resource = static_cast(group->d_func()->m_resources.value(this, 0)); + if (!resource) { + resource = new T(context); + insert(context, resource); + } + return resource; + } + +private: + QAtomicInt active; + QList 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 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 81030b8..5ce7db0 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 4c50089..05a612c 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 + #if defined(QT_DEBUG) #include #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 *&shaders = m_storage.localData(); + QGLMultiGroupSharedResource *&shaders = m_storage.localData(); if (!shaders) - shaders = new QGLContextGroupResource(); - return shaders->value(context); + shaders = new QGLMultiGroupSharedResource; + QGLEngineSharedShadersResource *resource = + shaders->value(context->contextHandle()); + return resource ? resource->shaders() : 0; } private: - QThreadStorage *> m_storage; + QThreadStorage 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 shaderProgram(new QGLShaderProgram(ctxGuard.context(), 0)); + QScopedPointer 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 fragShader(new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0)); + QScopedPointer 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 vertexShader(new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0)); + QScopedPointer 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 921df36..58c761d 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 cachedPrograms; diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index 9e6b801..bd408ff 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(context->contextHandle()); } private: - QGLContextGroupResource 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 1c2d0a0..1b001c3 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 49d6b29..771d42b 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 4838ab0..214bfa5 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::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 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::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::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::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::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 83ca06d..2fcc551 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(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(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(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 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 8ef1fc3..f518828 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::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 c25ea16..a12cddc 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 d132b97..58efc7f 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 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 m_shares; - QHash 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 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 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(QGLContextGroupResourceBase::value(context)); - if (resource) { - QGLShareContextScope scope(context); - delete resource; - } - } - } - - T *value(const QGLContext *context) { - T *resource = reinterpret_cast(QGLContextGroupResourceBase::value(context)); - if (!resource) { - resource = new T(context); - insert(context, resource); - } - return resource; - } - -protected: - void freeResource(void *resource) { - delete reinterpret_cast(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 +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 +QGLSharedResourceGuardBase *createSharedResourceGuard(QGLContext *context, GLuint id, Func cleanupFunc) +{ + return new QGLSharedResourceGuard(context, id, cleanupFunc); +} class QGLExtensionMatcher { diff --git a/src/opengl/qglbuffer.cpp b/src/opengl/qglbuffer.cpp index 637e48d..53f2739 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::currentContext()); if (ctx) { - if (!qt_resolve_buffer_extensions(const_cast(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 f35f6e5..2916844 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(fbo->d_ptr->fbo_guard.context()); - QGLContext *currentContext = const_cast(QGLContext::currentContext()); - - if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext)) - return currentContext; - else - return fboContext; + return const_cast(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::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 f823612..61d39c6 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 48549fb..534c6c8 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, 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 - (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(context->contextHandle())); return funcs; } diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index de03553..7b3f5d9 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::currentContext()); if (!context) return false; - if (qt_resolve_glsl_extensions(const_cast(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 src; QVarLengthArray 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::currentContext()); if (!context) return false; - if (qt_resolve_glsl_extensions(const_cast(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(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"; -- 2.7.4