From aaa4a26f82f99fa8724841eba91bad029306e0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 16 Aug 2011 09:29:44 +0200 Subject: 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 --- .../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 ++++++++------- 7 files changed, 134 insertions(+), 79 deletions(-) (limited to 'src/opengl/gl2paintengineex') diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 4c50089f6d..05a612c311 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 921df369f4..58c761df43 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 9e6b801c40..bd408ffdc4 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 1c2d0a029a..1b001c3405 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 49d6b297e4..771d42be3f 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 4838ab09e7..214bfa5b47 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 83ca06d040..2fcc551667 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; -- cgit v1.2.3