summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
authorTrond Kjernåsen <trond.kjernasen@nokia.com>2010-06-17 12:46:27 (GMT)
committerTrond Kjernåsen <trond.kjernasen@nokia.com>2010-07-02 10:25:24 (GMT)
commitb2de72a51124333b639fdfbda829f54088dff838 (patch)
treeb28b3b601351ae05d413315fe88781cefb7d98c8 /src/opengl
parent76a14c8254f4f8beb16de897f31bab13dc7609a4 (diff)
downloadQt-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.cpp49
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp19
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache_p.h4
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h2
-rw-r--r--src/opengl/qgl.cpp34
-rw-r--r--src/opengl/qgl.h1
-rw-r--r--src/opengl/qgl_p.h137
-rw-r--r--src/opengl/qglpixmapfilter.cpp23
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)