summaryrefslogtreecommitdiffstats
path: root/src/opengl/gl2paintengineex
diff options
context:
space:
mode:
authorTrond Kjernåsen <trond.kjernasen@nokia.com>2010-06-22 11:02:54 (GMT)
committerTrond Kjernåsen <trond.kjernasen@nokia.com>2010-07-02 10:25:02 (GMT)
commit80a2ebd93346f885d904e4e1020e112cc635dbaf (patch)
treed84a7d29f51a140a047bacff7139ffa340c2cd8d /src/opengl/gl2paintengineex
parent4c3ac765b26e56fbf08c9f70cf43aa00a6565cae (diff)
downloadQt-80a2ebd93346f885d904e4e1020e112cc635dbaf.zip
Qt-80a2ebd93346f885d904e4e1020e112cc635dbaf.tar.gz
Qt-80a2ebd93346f885d904e4e1020e112cc635dbaf.tar.bz2
Redesigned how GL resource management works.
The usage of QGLContextResource has changed: You're now have to subclass QGLContextResource and reimplement the freeResource() function and add your cleanup code there instead of using a plain callback function. It's now also possible to delete a QGLContextResource *before* the QGLContextGroup it refers to is destroyed, as the resource will remove itself from the context groups it's a member of. The QGLTextureGlyphCache is no longer a QObject, and it no longer depends on the aboutToDestroyContext() signal. That concept doesn't work in a threaded environment, as it relies on an eventloop to dispatch the signal to the thread. It's common to *not* have an eventloop running in a thread, which means the signal might never be delivered. QGLTextureGlyphCache now inherits from QGLContextResource, and gets cleaned up correctly when the group context is destroyed. Note that up until now the glyph cache has never been shared among sharing contexts for the GL 2 engine. Made the gradient and pixmap blur caches use the new QGLContextResource scheme. Added a template that wraps the common init code for paintEngine() function implementations for QGLWidget, QGLPixelBuffer and QGLFramebufferObject. Fixed a bug in QFontCache where the font caches weren't cleared when a thread other than the main thread exited (backported to 4.6.3), which caused resource leaks.
Diffstat (limited to 'src/opengl/gl2paintengineex')
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp80
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h4
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp12
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp1
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp47
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h31
6 files changed, 56 insertions, 119 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 0ba324d..888bac9 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -48,65 +48,54 @@
QT_BEGIN_NAMESPACE
+class QGLSharedShaderResource : public QGLContextResource
+{
+public:
+ ~QGLSharedShaderResource() {
+ qDebug() << "~QGLSharedShaderResource cleaned up" << hex << this;
+ }
-// Handling the cleanup and creation of the thread-local shader cache
-// differes from other QGLContextResources. The cache needs to be
-// cleaned up when the thread exits, or when its group context is
-// destroyed.
-
-static void qt_gl_free_shared_shaders(void *value);
+ void freeResource(void *value)
+ {
+ qDebug() << "Context destroyed:";
+ qDebug() << " -> deleting shader cache" << hex << value;
+ delete reinterpret_cast<QGLEngineSharedShaders *>(value);
+ }
+};
class QGLThreadLocalShaders
{
public:
- QGLThreadLocalShaders(const QGLContext *context, QGLEngineSharedShaders *shaders)
- : m_context(context), m_shaders(shaders)
- {
- m_resource = new QGLContextResource(qt_gl_free_shared_shaders);
- m_resource->insert(context, this);
+ 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();
- qDebug() << " -> deleting shader cache:" << hex << m_shaders;
- delete m_shaders;
- // remove the resource from the group's resource list, so that
- // the cleanup function is not called when the context is destroyed
- m_resource->remove(m_context);
- delete m_resource;
}
- const QGLContext *m_context;
- QGLEngineSharedShaders *m_shaders;
- QGLContextResource *m_resource;
-};
-static void qt_gl_free_shared_shaders(void *value)
-{
- QGLThreadLocalShaders *local = reinterpret_cast<QGLThreadLocalShaders *>(value);
- qDebug() << "Context destroyed:";
- qDebug() << " -> deleting shader cache" << hex << local->m_shaders;
- delete local->m_shaders;
- local->m_shaders = 0;
-
- // this function is called when the context group for the context
- // we have ref'ed is deleted - that means our context ptr is no
- // longer valid
- local->m_context = 0;
-}
+private:
+ QGLSharedShaderResource m_resource;
+};
class QGLShaderStorage
{
public:
QGLEngineSharedShaders *shadersForThread(const QGLContext *context) {
- QGLThreadLocalShaders *shaders = m_storage.localData();
+ QGLThreadLocalShaders *&shaders = m_storage.localData();
if (!shaders) {
- qDebug() << "New shader cache for thread:" << hex << QThread::currentThread();
- QGLShareContextScope scope(context);
- shaders = new QGLThreadLocalShaders(context, new QGLEngineSharedShaders(context));
- qDebug() << " -> context:" << context;
- m_storage.setLocalData(shaders);
+ qDebug() << "New thread storage for:" << hex << QThread::currentThread();
+ shaders = new QGLThreadLocalShaders;
}
- return shaders->m_shaders;
+ return shaders->shadersForContext(context);
}
private:
@@ -282,15 +271,6 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
QGLEngineSharedShaders::~QGLEngineSharedShaders()
{
- cleanupBeforeDestruction();
-}
-
-
-// This might be called both when a thread exits, or when the a
-// context is destroyed
-
-void QGLEngineSharedShaders::cleanupBeforeDestruction()
-{
qDeleteAll(shaders);
shaders.clear();
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 8d3697b..e5ababf 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -364,10 +364,6 @@ public:
// full.
void cleanupCustomStage(QGLCustomShaderStage* stage);
- // this is needed so that threads can get a foot in and have a chance to
- // clean up the shaders they've created before the thread exits
- void cleanupBeforeDestruction();
-
private:
QGLSharedResourceGuard ctxGuard;
QGLShaderProgram *blitShaderProg;
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index a1495dd..a0a3f8f 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -46,12 +46,16 @@
QT_BEGIN_NAMESPACE
-static void QGL2GradientCache_free(void *ptr)
+class QGLGradientCacheResource : public QGLContextResource
{
- delete reinterpret_cast<QGL2GradientCache *>(ptr);
-}
+public:
+ void freeResource(void *value)
+ {
+ delete reinterpret_cast<QGL2GradientCache *>(value);
+ }
+};
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free))
+Q_GLOBAL_STATIC(QGLGradientCacheResource, qt_gradient_caches)
QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
{
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 634b315..260e797 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1457,6 +1457,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
(QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform());
if (!cache || cache->cacheType() != glyphType) {
cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
+ cache->insert(ctx, cache);
staticTextItem->fontEngine->setGlyphCache(ctx, cache);
}
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
index faf4563..001a09e 100644
--- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
@@ -54,45 +54,10 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled;
QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
: QImageTextureGlyphCache(type, matrix)
- , ctx(0)
- , pex(0)
+ , ctx(context)
, m_width(0)
, m_height(0)
{
- if (context != 0)
- setContext(context);
-}
-
-QGLTextureGlyphCache::~QGLTextureGlyphCache()
-{
- cleanUpContext();
-}
-
-void QGLTextureGlyphCache::cleanUpContext()
-{
- if (ctx) {
- QGLShareContextScope scope(ctx);
-
- if (!ctx->d_ptr->workaround_brokenFBOReadBack && pex != 0)
- glDeleteFramebuffers(1, &m_fbo);
-
- if (m_width || m_height) {
- glDeleteTextures(1, &m_texture);
- m_width = 0;
- m_height = 0;
- m_h = 0;
- }
-
- ctx = 0;
- }
-}
-
-void QGLTextureGlyphCache::setContext(const QGLContext *context)
-{
- cleanUpContext();
-
- ctx = context;
-
// broken FBO readback is a bug in the SGX 1.3 and 1.4 drivers for the N900 where
// copying between FBO's is broken if the texture is either GL_ALPHA or POT. The
// workaround is to use a system-memory copy of the glyph cache for this device.
@@ -101,8 +66,12 @@ void QGLTextureGlyphCache::setContext(const QGLContext *context)
if (!ctx->d_ptr->workaround_brokenFBOReadBack && pex != 0)
glGenFramebuffers(1, &m_fbo);
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
- SLOT(contextDestroyed(const QGLContext*)));
+ fprintf(stderr, "## QGLTextureGlyphCache(): ctx: %p - this: %p\n", ctx, this);
+}
+
+QGLTextureGlyphCache::~QGLTextureGlyphCache()
+{
+ fprintf(stderr, "## ~QGLTextureGlyphCache(): context: %p - this: %p\n", ctx, this);
}
void QGLTextureGlyphCache::createTextureData(int width, int height)
@@ -161,7 +130,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
GLuint oldTexture = m_texture;
createTextureData(width, height);
-
+
if (pex == 0 || ctx->d_ptr->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::resizeTextureData(width, height);
Q_ASSERT(image().depth() == 8);
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
index d291ac3..710a12d 100644
--- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
@@ -62,9 +62,8 @@ QT_BEGIN_NAMESPACE
class QGL2PaintEngineExPrivate;
-class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QObject, public QImageTextureGlyphCache
+class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QGLContextResource, public QImageTextureGlyphCache
{
- Q_OBJECT
public:
QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
~QGLTextureGlyphCache();
@@ -82,33 +81,21 @@ public:
inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
- void setContext(const QGLContext *context);
inline const QGLContext *context() const
{
return ctx;
}
+ void freeResource(void *) {
+ qDebug() << "QGLTextureGlyphCache::freeResource():" << this << "ctx:" << ctx;
+ // At this point, the context group is made current, so it's safe to
+ // release resources without a makeCurrent() call
+ if (!ctx->d_ptr->workaround_brokenFBOReadBack)
+ glDeleteFramebuffers(1, &m_fbo);
-public Q_SLOTS:
- void contextDestroyed(const QGLContext *context) {
- if (context == ctx) {
- const QGLContext *nextCtx = qt_gl_transfer_context(ctx);
- if (!nextCtx) {
- // the context may not be current, so we cannot directly
- // destroy the fbo and texture here, but since the context
- // is about to be destroyed, the GL server will do the
- // clean up for us anyway
- m_fbo = 0;
- m_texture = 0;
- ctx = 0;
- } else {
- // since the context holding the texture is shared, and
- // about to be destroyed, we have to transfer ownership
- // of the texture to one of the share contexts
- ctx = const_cast<QGLContext *>(nextCtx);
- }
- }
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
}
private: