diff options
author | Trond Kjernåsen <trond.kjernasen@nokia.com> | 2010-06-17 12:46:27 (GMT) |
---|---|---|
committer | Trond Kjernåsen <trond.kjernasen@nokia.com> | 2010-07-02 10:25:24 (GMT) |
commit | b2de72a51124333b639fdfbda829f54088dff838 (patch) | |
tree | b28b3b601351ae05d413315fe88781cefb7d98c8 /src/opengl | |
parent | 76a14c8254f4f8beb16de897f31bab13dc7609a4 (diff) | |
download | Qt-b2de72a51124333b639fdfbda829f54088dff838.zip Qt-b2de72a51124333b639fdfbda829f54088dff838.tar.gz Qt-b2de72a51124333b639fdfbda829f54088dff838.tar.bz2 |
Rework the internal GL resource system yet again.
Instead of having to sub-class QGLContextResource, we now have two
template classes:
1. 'QGLContextResource' to handle context specific resources that are
*not* shared in a group, even though the context itself is in a sharing
group
2. 'QGLContextGroupResource' to handle resources shared in a context
group.
Classes used as the template class type must have a constructor with
the following signature:
T(const QGLContext *);
The resources that the templates wrap are freed up when the context
or context group it is tied to is destroyed. The resource is also
freed when the QGLContext<Group>Resource object is destroyed, which
might lead to context switches, depending on where and in how many
non-sharing contexts the resource is used.
The templates wrap some boiler plate code that were common for all the
use cases.
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager.cpp | 49 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglgradientcache.cpp | 19 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglgradientcache_p.h | 4 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h | 2 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 34 | ||||
-rw-r--r-- | src/opengl/qgl.h | 1 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 137 | ||||
-rw-r--r-- | src/opengl/qglpixmapfilter.cpp | 23 |
8 files changed, 161 insertions, 108 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 888bac9..c06bb3c 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -48,65 +48,27 @@ QT_BEGIN_NAMESPACE -class QGLSharedShaderResource : public QGLContextResource -{ -public: - ~QGLSharedShaderResource() { - qDebug() << "~QGLSharedShaderResource cleaned up" << hex << this; - } - - void freeResource(void *value) - { - qDebug() << "Context destroyed:"; - qDebug() << " -> deleting shader cache" << hex << value; - delete reinterpret_cast<QGLEngineSharedShaders *>(value); - } -}; - -class QGLThreadLocalShaders -{ -public: - QGLEngineSharedShaders *shadersForContext(const QGLContext *context) { - QGLEngineSharedShaders *shaders = reinterpret_cast<QGLEngineSharedShaders *>(m_resource.value(context)); - if (!shaders) { - QGLShareContextScope scope(context); - shaders = new QGLEngineSharedShaders(context); - qDebug() << " -> new shader cache for context:" << hex << context << "cache:" << shaders; - m_resource.insert(context, shaders); - } - return shaders; - } - - ~QGLThreadLocalShaders() { - qDebug() << "Thread exit:"; - qDebug() << "~QGLThreadLocalShaders() for thread:" << hex << QThread::currentThread(); - } - -private: - QGLSharedShaderResource m_resource; -}; - class QGLShaderStorage { public: QGLEngineSharedShaders *shadersForThread(const QGLContext *context) { - QGLThreadLocalShaders *&shaders = m_storage.localData(); + QGLContextGroupResource<QGLEngineSharedShaders> *&shaders = m_storage.localData(); if (!shaders) { qDebug() << "New thread storage for:" << hex << QThread::currentThread(); - shaders = new QGLThreadLocalShaders; + shaders = new QGLContextGroupResource<QGLEngineSharedShaders>(); } - return shaders->shadersForContext(context); + return shaders->value(context); } private: - QThreadStorage<QGLThreadLocalShaders *> m_storage; + QThreadStorage<QGLContextGroupResource<QGLEngineSharedShaders> *> m_storage; }; Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage); QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context) { - return reinterpret_cast<QGLEngineSharedShaders *>(qt_shader_storage()->shadersForThread(context)); + return qt_shader_storage()->shadersForThread(context); } const char* QGLEngineSharedShaders::qShaderSnippets[] = { @@ -271,6 +233,7 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) QGLEngineSharedShaders::~QGLEngineSharedShaders() { + qDebug() << "####### ~QGLEngineSharedShaders() ##########"; qDeleteAll(shaders); shaders.clear(); diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index a0a3f8f..f1b095d 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache.cpp +++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp @@ -46,26 +46,11 @@ QT_BEGIN_NAMESPACE -class QGLGradientCacheResource : public QGLContextResource -{ -public: - void freeResource(void *value) - { - delete reinterpret_cast<QGL2GradientCache *>(value); - } -}; - -Q_GLOBAL_STATIC(QGLGradientCacheResource, qt_gradient_caches) +Q_GLOBAL_STATIC(QGLContextGroupResource<QGL2GradientCache>, qt_gradient_caches) QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context) { - QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context)); - if (!p) { - QGLShareContextScope scope(context); - p = new QGL2GradientCache; - qt_gradient_caches()->insert(context, p); - } - return p; + return qt_gradient_caches()->value(context); } void QGL2GradientCache::cleanCache() { diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h index 0a5f846..8ecb34e 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache_p.h +++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h @@ -75,8 +75,8 @@ class QGL2GradientCache public: static QGL2GradientCache *cacheForContext(const QGLContext *context); - QGL2GradientCache() { } - ~QGL2GradientCache() {cleanCache();} + QGL2GradientCache(const QGLContext *) {} + ~QGL2GradientCache() { cleanCache(); } GLuint getBuffer(const QGradient &gradient, qreal opacity); inline int paletteSize() const { return 1024; } diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index 710a12d..1a78eed 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QGL2PaintEngineExPrivate; -class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QGLContextResource, public QImageTextureGlyphCache +class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QGLContextGroupResourceBase, public QImageTextureGlyphCache { public: QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 74efb34..6755d93 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2029,6 +2029,9 @@ QGLContext::~QGLContext() QGLTextureCache::instance()->removeContextTextures(this); qDebug() << "~QGLContext(): about to clean up" << hex << this; + // 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); @@ -2037,6 +2040,10 @@ QGLContext::~QGLContext() void QGLContextPrivate::cleanup() { + QHash<QGLContextResourceBase *, void *>::ConstIterator it; + for (it = m_resources.begin(); it != m_resources.end(); ++it) + it.key()->freeResource(it.value()); + m_resources.clear(); } #define ctx q_ptr @@ -5282,15 +5289,17 @@ void QGLContextGroup::removeShare(const QGLContext *context) { group->m_shares.clear(); } -QGLContextResource::QGLContextResource() +QGLContextGroupResourceBase::QGLContextGroupResourceBase() : active(0) { } -QGLContextResource::~QGLContextResource() +QGLContextGroupResourceBase::~QGLContextGroupResourceBase() { + qDebug() << "~QGLContextGroupResourceBase()" << hex << this << "group size:" << m_groups.size(); for (int i = 0; i < m_groups.size(); ++i) { m_groups.at(i)->m_resources.remove(this); + qDebug() << " ->removing from group resource list:" << hex << this; active.deref(); } #ifndef QT_NO_DEBUG @@ -5302,24 +5311,24 @@ QGLContextResource::~QGLContextResource() #endif } -void QGLContextResource::insert(const QGLContext *key, void *value) +void QGLContextGroupResourceBase::insert(const QGLContext *context, void *value) { - QGLContextGroup *group = QGLContextPrivate::contextGroup(key); + 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 *QGLContextResource::value(const QGLContext *key) +void *QGLContextGroupResourceBase::value(const QGLContext *context) { - QGLContextGroup *group = QGLContextPrivate::contextGroup(key); + QGLContextGroup *group = QGLContextPrivate::contextGroup(context); return group->m_resources.value(this, 0); } -void QGLContextResource::cleanup(const QGLContext *ctx, void *value) +void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value) { - qDebug() << "QGLContextResource::cleanup() this:" << hex << this << "ctx:" << ctx << "thread:" << (void *)QThread::currentThread(); + qDebug() << "QGLContextGroupResourceBase::cleanup() this:" << hex << this << "ctx:" << ctx << "thread:" << (void *)QThread::currentThread(); QGLShareContextScope scope(ctx); freeResource(value); active.deref(); @@ -5328,17 +5337,18 @@ void QGLContextResource::cleanup(const QGLContext *ctx, void *value) m_groups.removeOne(group); } -void QGLContextGroup::cleanupResources(const QGLContext *ctx) +void QGLContextGroup::cleanupResources(const QGLContext *context) { - qDebug() << "QGLContextGroup::cleanupResources() for ctx:" << hex << ctx << "shares:" << m_shares.size() << "res:" << m_resources.size(); + qDebug() << "QGLContextGroup::cleanupResources() for ctx:" << hex << context + << "shares:" << m_shares.size() << "res:" << m_resources.size(); // 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<QGLContextResource *, void *>::ConstIterator it; + QHash<QGLContextGroupResourceBase *, void *>::ConstIterator it; for (it = m_resources.begin(); it != m_resources.end(); ++it) - it.key()->cleanup(ctx, it.value()); + it.key()->cleanup(context, it.value()); } QGLSharedResourceGuard::~QGLSharedResourceGuard() diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index f0b36f7..d354f92 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -436,6 +436,7 @@ private: friend class QGLWidgetGLPaintDevice; friend class QX11GLPixmapData; friend class QX11GLSharedContexts; + friend class QGLContextResourceBase; private: Q_DISABLE_COPY(QGLContext) }; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index acd799a..3be30de 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -206,7 +206,7 @@ public: #endif }; -class QGLContextResource; +class QGLContextGroupResourceBase; class QGLSharedResourceGuard; // QGLContextPrivate has the responsibility of creating context groups. @@ -234,7 +234,7 @@ private: QGLExtensionFuncs m_extensionFuncs; const QGLContext *m_context; // context group's representative QList<const QGLContext *> m_shares; - QHash<QGLContextResource *, void *> m_resources; + QHash<QGLContextGroupResourceBase *, void *> m_resources; QGLSharedResourceGuard *m_guards; // double-linked list of active guards. QAtomicInt m_refs; @@ -242,7 +242,7 @@ private: friend class QGLContext; friend class QGLContextPrivate; - friend class QGLContextResource; + friend class QGLContextGroupResourceBase; }; // Get the context that resources for "ctx" will transfer to once @@ -307,6 +307,8 @@ class QGLTexture; // all the GL2 engine uses: #define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3 +class QGLContextResourceBase; + class QGLContextPrivate { Q_DECLARE_PUBLIC(QGLContext) @@ -398,6 +400,7 @@ public: GLuint current_fbo; GLuint default_fbo; QPaintEngine *active_engine; + QHash<QGLContextResourceBase *, void *> m_resources; bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT]; @@ -606,24 +609,130 @@ inline GLenum qt_gl_preferredTextureTarget() #endif } -// One resource per group of shared contexts. -class Q_OPENGL_EXPORT QGLContextResource +/* + Base for resources that are shared in a context group. +*/ +class QGLContextGroupResourceBase { public: - QGLContextResource(); - virtual ~QGLContextResource(); - // Set resource 'value' for 'key' and all its shared contexts. - void insert(const QGLContext *key, void *value); - // Return resource for 'key' or a shared context. - void *value(const QGLContext *key); - // Cleanup 'value' in response to a context group being destroyed. - void cleanup(const QGLContext *ctx, void *value); + QGLContextGroupResourceBase(); + virtual ~QGLContextGroupResourceBase(); + void insert(const QGLContext *context, void *value); + void *value(const QGLContext *context); + void cleanup(const QGLContext *context, void *value); virtual void freeResource(void *value) = 0; -private: + +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); + } +}; + +/* + Base for resources that are context specific. +*/ +class QGLContextResourceBase +{ +public: + virtual ~QGLContextResourceBase() { + for (int i = 0; i < m_contexts.size(); ++i) + m_contexts.at(i)->d_ptr->m_resources.remove(this); + } + + void insert(const QGLContext *context, void *value) { + context->d_ptr->m_resources.insert(this, value); + } + + void *value(const QGLContext *context) { + return context->d_ptr->m_resources.value(this, 0); + } + virtual void freeResource(void *value) = 0; + +protected: + QList<const QGLContext *> m_contexts; +}; + +/* + The QGLContextResource template is used to manage a resource for a + single GL context. Just before the context is destroyed (while it's + still the current context), or when the QGLContextResource 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 QGLContextResource : public QGLContextResourceBase +{ +public: + ~QGLContextResource() { + for (int i = 0; i < m_contexts.size(); ++i) { + const QGLContext *context = m_contexts.at(i); + T *resource = reinterpret_cast<T *>(QGLContextResourceBase::value(context)); + if (resource) { + QGLShareContextScope scope(context); + delete resource; + } + } + } + + T *value(const QGLContext *context) { + T *resource = reinterpret_cast<T *>(QGLContextResourceBase::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 diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 011869e..68586c1 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -315,7 +315,7 @@ class QGLBlurTextureCache : public QObject public: static QGLBlurTextureCache *cacheForContext(const QGLContext *context); - QGLBlurTextureCache(); + QGLBlurTextureCache(const QGLContext *); ~QGLBlurTextureCache(); QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap); @@ -336,19 +336,9 @@ private: }; QList<QGLBlurTextureCache *> QGLBlurTextureCache::blurTextureCaches; +Q_GLOBAL_STATIC(QGLContextGroupResource<QGLBlurTextureCache>, qt_blur_texture_caches) -class QGLBlurCacheResource : public QGLContextResource -{ -public: - void freeResource(void *value) - { - delete reinterpret_cast<QGLBlurTextureCache *>(value); - } -}; - -Q_GLOBAL_STATIC(QGLBlurCacheResource, qt_blur_texture_caches) - -QGLBlurTextureCache::QGLBlurTextureCache() +QGLBlurTextureCache::QGLBlurTextureCache(const QGLContext *) : timerId(0) { cache.setMaxCost(4 * 1024 * 1024); @@ -370,12 +360,7 @@ void QGLBlurTextureCache::timerEvent(QTimerEvent *) QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context) { - QGLBlurTextureCache *p = reinterpret_cast<QGLBlurTextureCache *>(qt_blur_texture_caches()->value(context)); - if (!p) { - p = new QGLBlurTextureCache; - qt_blur_texture_caches()->insert(context, p); - } - return p; + return qt_blur_texture_caches()->value(context); } QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap) |