diff options
author | Trond Kjernåsen <trond.kjernasen@nokia.com> | 2010-06-22 11:02:54 (GMT) |
---|---|---|
committer | Trond Kjernåsen <trond.kjernasen@nokia.com> | 2010-07-02 10:25:02 (GMT) |
commit | 80a2ebd93346f885d904e4e1020e112cc635dbaf (patch) | |
tree | d84a7d29f51a140a047bacff7139ffa340c2cd8d /src/opengl/gl2paintengineex | |
parent | 4c3ac765b26e56fbf08c9f70cf43aa00a6565cae (diff) | |
download | Qt-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')
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: |