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 +++---- src/opengl/qgl.cpp | 132 +------------------ src/opengl/qgl.h | 1 - src/opengl/qgl_p.h | 132 ++++++------------- src/opengl/qglbuffer.cpp | 59 +++++---- src/opengl/qglframebufferobject.cpp | 87 ++++++++----- src/opengl/qglframebufferobject_p.h | 17 +-- src/opengl/qglfunctions.cpp | 28 ++-- src/opengl/qglshaderprogram.cpp | 142 +++++++++++---------- 15 files changed, 363 insertions(+), 448 deletions(-) (limited to 'src/opengl') 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; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 8ef1fc38e5..f51882841b 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1476,42 +1476,16 @@ Q_GLOBAL_STATIC(QGLContextGroupList, qt_context_groups) *****************************************************************************/ QGLContextGroup::QGLContextGroup(const QGLContext *context) - : m_context(context), m_guards(0), m_refs(1) + : m_context(context), m_refs(1) { qt_context_groups()->append(this); } QGLContextGroup::~QGLContextGroup() { - // Clear any remaining QGLSharedResourceGuard objects on the group. - QGLSharedResourceGuard *guard = m_guards; - while (guard != 0) { - guard->m_group = 0; - guard->m_id = 0; - guard = guard->m_next; - } qt_context_groups()->remove(this); } -void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard) -{ - if (m_guards) - m_guards->m_prev = guard; - guard->m_next = m_guards; - guard->m_prev = 0; - m_guards = guard; -} - -void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard) -{ - if (guard->m_next) - guard->m_next->m_prev = guard->m_prev; - if (guard->m_prev) - guard->m_prev->m_next = guard->m_next; - else - m_guards = guard->m_next; -} - const QGLContext *qt_gl_transfer_context(const QGLContext *ctx) { if (!ctx) @@ -1934,8 +1908,6 @@ QGLContext::~QGLContext() // 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); reset(); @@ -5017,108 +4989,6 @@ void QGLContextGroup::removeShare(const QGLContext *context) { group->m_shares.clear(); } -QGLContextGroupResourceBase::QGLContextGroupResourceBase() - : active(0) -{ -#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG - qDebug("Creating context group resource object %p.", this); -#endif -} - -QGLContextGroupResourceBase::~QGLContextGroupResourceBase() -{ -#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG - qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size()); -#endif - for (int i = 0; i < m_groups.size(); ++i) { - m_groups.at(i)->m_resources.remove(this); - active.deref(); - } -#ifndef QT_NO_DEBUG - if (active != 0) { - qWarning("QtOpenGL: Resources are still available at program shutdown.\n" - " This is possibly caused by a leaked QGLWidget, \n" - " QGLFramebufferObject or QGLPixelBuffer."); - } -#endif -} - -void QGLContextGroupResourceBase::insert(const QGLContext *context, void *value) -{ -#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG - qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this); -#endif - 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 *QGLContextGroupResourceBase::value(const QGLContext *context) -{ - QGLContextGroup *group = QGLContextPrivate::contextGroup(context); - return group->m_resources.value(this, 0); -} - -void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx) -{ - void *resource = value(ctx); - - if (resource != 0) { - QGLShareContextScope scope(ctx); - freeResource(resource); - - QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx); - group->m_resources.remove(this); - m_groups.removeOne(group); - active.deref(); - } -} - -void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value) -{ -#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG - qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread()); -#endif - QGLShareContextScope scope(ctx); - freeResource(value); - active.deref(); - - QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx); - m_groups.removeOne(group); -} - -void QGLContextGroup::cleanupResources(const QGLContext *context) -{ - // 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::ConstIterator it; - for (it = m_resources.begin(); it != m_resources.end(); ++it) - it.key()->cleanup(context, it.value()); -} - -QGLSharedResourceGuard::~QGLSharedResourceGuard() -{ - if (m_group) - m_group->removeGuard(this); -} - -void QGLSharedResourceGuard::setContext(const QGLContext *context) -{ - if (m_group) - m_group->removeGuard(this); - if (context) { - m_group = QGLContextPrivate::contextGroup(context); - m_group->addGuard(this); - } else { - m_group = 0; - } -} - QSize QGLTexture::bindCompressedTexture (const QString& fileName, const char *format) { diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index c25ea16e43..a12cddcca4 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -374,7 +374,6 @@ private: friend class QGLTextureGlyphCache; friend struct QGLGlyphTexture; friend class QGLContextGroup; - friend class QGLSharedResourceGuard; friend class QGLPixmapBlurFilter; friend class QGLExtensions; friend class QGLTexture; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index d132b97260..58efc7f7fd 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -61,6 +61,7 @@ #include "QtCore/qhash.h" #include "QtCore/qatomic.h" #include "QtWidgets/private/qwidget_p.h" +#include "QtGui/private/qguiglcontext_qpa_p.h" #include "qcache.h" #include "qglpaintdevice_p.h" @@ -177,9 +178,6 @@ public: bool disable_clear_on_painter_begin; }; -class QGLContextGroupResourceBase; -class QGLSharedResourceGuard; - // QGLContextPrivate has the responsibility of creating context groups. // QGLContextPrivate maintains the reference counter and destroys // context groups when needed. @@ -193,9 +191,6 @@ public: bool isSharing() const { return m_shares.size() >= 2; } QList shares() const { return m_shares; } - void addGuard(QGLSharedResourceGuard *guard); - void removeGuard(QGLSharedResourceGuard *guard); - static void addShare(const QGLContext *context, const QGLContext *share); static void removeShare(const QGLContext *context); @@ -205,12 +200,8 @@ private: QGLExtensionFuncs m_extensionFuncs; const QGLContext *m_context; // context group's representative QList m_shares; - QHash m_resources; - QGLSharedResourceGuard *m_guards; // double-linked list of active guards. QAtomicInt m_refs; - void cleanupResources(const QGLContext *ctx); - friend class QGLContext; friend class QGLContextPrivate; friend class QGLContextGroupResourceBase; @@ -539,114 +530,69 @@ QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key) extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine(); -/* - Base for resources that are shared in a context group. -*/ -class Q_OPENGL_EXPORT QGLContextGroupResourceBase -{ -public: - QGLContextGroupResourceBase(); - virtual ~QGLContextGroupResourceBase(); - void insert(const QGLContext *context, void *value); - void *value(const QGLContext *context); - void cleanup(const QGLContext *context); - void cleanup(const QGLContext *context, void *value); - virtual void freeResource(void *value) = 0; - -protected: - QList 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 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(QGLContextGroupResourceBase::value(context)); - if (resource) { - QGLShareContextScope scope(context); - delete resource; - } - } - } - - T *value(const QGLContext *context) { - T *resource = reinterpret_cast(QGLContextGroupResourceBase::value(context)); - if (!resource) { - resource = new T(context); - insert(context, resource); - } - return resource; - } - -protected: - void freeResource(void *resource) { - delete reinterpret_cast(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 // the identifier is returned as zero - it is assumed that the // context destruction cleaned up the identifier in this case. -class Q_OPENGL_EXPORT QGLSharedResourceGuard +class Q_OPENGL_EXPORT QGLSharedResourceGuardBase : public QGLSharedResource { public: - QGLSharedResourceGuard(const QGLContext *context) - : m_group(0), m_id(0), m_next(0), m_prev(0) + QGLSharedResourceGuardBase(QGLContext *context, GLuint id) + : QGLSharedResource(context->contextHandle()->shareGroup()) + , m_id(id) + { + } + + GLuint id() const { - setContext(context); + return m_id; } - QGLSharedResourceGuard(const QGLContext *context, GLuint id) - : m_group(0), m_id(id), m_next(0), m_prev(0) + +protected: + void invalidateResource() { - setContext(context); + m_id = 0; } - ~QGLSharedResourceGuard(); - const QGLContext *context() const + void freeResource(QGuiGLContext *context) { - return m_group ? m_group->context() : 0; + if (m_id) { + freeResource(QGLContext::fromGuiGLContext(context), m_id); + } } - void setContext(const QGLContext *context); + virtual void freeResource(QGLContext *ctx, GLuint id) = 0; - GLuint id() const +private: + GLuint m_id; +}; + +template +class QGLSharedResourceGuard : public QGLSharedResourceGuardBase +{ +public: + QGLSharedResourceGuard(QGLContext *context, GLuint id, Func func) + : QGLSharedResourceGuardBase(context, id) + , m_func(func) { - return m_id; } - void setId(GLuint id) +protected: + void freeResource(QGLContext *ctx, GLuint id) { - m_id = id; + m_func(ctx, id); } private: - QGLContextGroup *m_group; - GLuint m_id; - QGLSharedResourceGuard *m_next; - QGLSharedResourceGuard *m_prev; - - friend class QGLContextGroup; + Func m_func; }; +template +QGLSharedResourceGuardBase *createSharedResourceGuard(QGLContext *context, GLuint id, Func cleanupFunc) +{ + return new QGLSharedResourceGuard(context, id, cleanupFunc); +} class QGLExtensionMatcher { diff --git a/src/opengl/qglbuffer.cpp b/src/opengl/qglbuffer.cpp index 637e48d27d..53f27392b0 100644 --- a/src/opengl/qglbuffer.cpp +++ b/src/opengl/qglbuffer.cpp @@ -141,7 +141,7 @@ public: QAtomicInt ref; QGLBuffer::Type type; - QGLSharedResourceGuard guard; + QGLSharedResourceGuardBase *guard; QGLBuffer::UsagePattern usagePattern; QGLBuffer::UsagePattern actualUsagePattern; }; @@ -184,7 +184,7 @@ QGLBuffer::QGLBuffer(const QGLBuffer &other) d_ptr->ref.ref(); } -#define ctx d->guard.context() +#define ctx QGLContext::currentContext(); /*! Destroys this buffer object, including the storage being @@ -250,6 +250,14 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value) #undef ctx +namespace { + void freeBufferFunc(QGLContext *ctx, GLuint id) + { + Q_UNUSED(ctx); + glDeleteBuffers(1, &id); + } +} + /*! Creates the buffer object in the GL server. Returns true if the object was created; false otherwise. @@ -266,24 +274,26 @@ void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value) bool QGLBuffer::create() { Q_D(QGLBuffer); - if (d->guard.id()) + if (d->guard && d->guard->id()) return true; - const QGLContext *ctx = QGLContext::currentContext(); + QGLContext *ctx = const_cast(QGLContext::currentContext()); if (ctx) { - if (!qt_resolve_buffer_extensions(const_cast(ctx))) + if (!qt_resolve_buffer_extensions(ctx)) return false; GLuint bufferId = 0; glGenBuffers(1, &bufferId); if (bufferId) { - d->guard.setContext(ctx); - d->guard.setId(bufferId); + if (d->guard) + d->guard->free(); + + d->guard = createSharedResourceGuard(ctx, bufferId, freeBufferFunc); return true; } } return false; } -#define ctx d->guard.context() +#define ctx QGLContext::currentContext() /*! Returns true if this buffer has been created; false otherwise. @@ -293,7 +303,7 @@ bool QGLBuffer::create() bool QGLBuffer::isCreated() const { Q_D(const QGLBuffer); - return d->guard.id() != 0; + return d->guard && d->guard->id(); } /*! @@ -304,14 +314,10 @@ bool QGLBuffer::isCreated() const void QGLBuffer::destroy() { Q_D(QGLBuffer); - GLuint bufferId = d->guard.id(); - if (bufferId) { - // Switch to the original creating context to destroy it. - QGLShareContextScope scope(d->guard.context()); - glDeleteBuffers(1, &bufferId); + if (d->guard) { + d->guard->free(); + d->guard = 0; } - d->guard.setId(0); - d->guard.setContext(0); } /*! @@ -358,7 +364,7 @@ void QGLBuffer::write(int offset, const void *data, int count) qWarning("QGLBuffer::allocate(): buffer not created"); #endif Q_D(QGLBuffer); - if (d->guard.id()) + if (d->guard && d->guard->id()) glBufferSubData(d->type, offset, count, data); } @@ -378,7 +384,7 @@ void QGLBuffer::allocate(const void *data, int count) qWarning("QGLBuffer::allocate(): buffer not created"); #endif Q_D(QGLBuffer); - if (d->guard.id()) + if (d->guard && d->guard->id()) glBufferData(d->type, count, data, d->actualUsagePattern); } @@ -413,10 +419,9 @@ bool QGLBuffer::bind() qWarning("QGLBuffer::bind(): buffer not created"); #endif Q_D(const QGLBuffer); - GLuint bufferId = d->guard.id(); + GLuint bufferId = d->guard ? d->guard->id() : 0; if (bufferId) { - if (!QGLContext::areSharing(QGLContext::currentContext(), - d->guard.context())) { + if (d->guard->group() != QGuiGLContextGroup::currentContextGroup()) { #ifndef QT_NO_DEBUG qWarning("QGLBuffer::bind: buffer is not valid in the current context"); #endif @@ -445,7 +450,7 @@ void QGLBuffer::release() qWarning("QGLBuffer::release(): buffer not created"); #endif Q_D(const QGLBuffer); - if (d->guard.id()) + if (d->guard && d->guard->id()) glBindBuffer(d->type, 0); } @@ -471,7 +476,7 @@ void QGLBuffer::release(QGLBuffer::Type type) glBindBuffer(GLenum(type), 0); } -#define ctx d->guard.context() +#define ctx QGLContext::currentContext() /*! Returns the GL identifier associated with this buffer; zero if @@ -482,7 +487,7 @@ void QGLBuffer::release(QGLBuffer::Type type) GLuint QGLBuffer::bufferId() const { Q_D(const QGLBuffer); - return d->guard.id(); + return d->guard ? d->guard->id() : 0; } #ifndef GL_BUFFER_SIZE @@ -501,7 +506,7 @@ GLuint QGLBuffer::bufferId() const int QGLBuffer::size() const { Q_D(const QGLBuffer); - if (!d->guard.id()) + if (!d->guard || !d->guard->id()) return -1; GLint value = -1; glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value); @@ -529,7 +534,7 @@ void *QGLBuffer::map(QGLBuffer::Access access) if (!isCreated()) qWarning("QGLBuffer::map(): buffer not created"); #endif - if (!d->guard.id()) + if (!d->guard || !d->guard->id()) return 0; if (!glMapBufferARB) return 0; @@ -556,7 +561,7 @@ bool QGLBuffer::unmap() if (!isCreated()) qWarning("QGLBuffer::unmap(): buffer not created"); #endif - if (!d->guard.id()) + if (!d->guard || !d->guard->id()) return false; if (!glUnmapBufferARB) return false; diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index f35f6e513d..29168441b3 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool); -#define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context(); -#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context(); +#define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext(); +#define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext(); #ifndef QT_NO_DEBUG #define QT_RESET_GLERROR() \ @@ -351,13 +351,7 @@ void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f, QGLContext *QGLFBOGLPaintDevice::context() const { - QGLContext *fboContext = const_cast(fbo->d_ptr->fbo_guard.context()); - QGLContext *currentContext = const_cast(QGLContext::currentContext()); - - if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext)) - return currentContext; - else - return fboContext; + return const_cast(QGLContext::currentContext()); } bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const @@ -407,13 +401,33 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const return false; } +namespace +{ + void freeFramebufferFunc(QGLContext *ctx, GLuint id) + { + Q_UNUSED(ctx); + glDeleteFramebuffers(1, &id); + } + + void freeRenderbufferFunc(QGLContext *ctx, GLuint id) + { + Q_UNUSED(ctx); + glDeleteRenderbuffers(1, &id); + } + + void freeTextureFunc(QGLContext *ctx, GLuint id) + { + Q_UNUSED(ctx); + glDeleteTextures(1, &id); + } +} + void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, QGLFramebufferObject::Attachment attachment, GLenum texture_target, GLenum internal_format, GLint samples, bool mipmap) { QGLContext *ctx = const_cast(QGLContext::currentContext()); - fbo_guard.setContext(ctx); bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject); if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx))) @@ -427,9 +441,11 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, GLuint fbo = 0; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo); - fbo_guard.setId(fbo); - glDevice.setFBO(q, attachment); + GLuint texture = 0; + GLuint color_buffer = 0; + GLuint depth_buffer = 0; + GLuint stencil_buffer = 0; QT_CHECK_GLERROR(); // init texture @@ -603,7 +619,21 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, } glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - if (!valid) { + if (valid) { + fbo_guard = createSharedResourceGuard(ctx, fbo, freeFramebufferFunc); + if (color_buffer) + color_buffer_guard = createSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc); + else + texture_guard = createSharedResourceGuard(ctx, texture, freeTextureFunc); + if (depth_buffer) + depth_buffer_guard = createSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc); + if (stencil_buffer) { + if (stencil_buffer == depth_buffer) + stencil_buffer_guard = depth_buffer_guard; + else + stencil_buffer_guard = createSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc); + } + } else { if (color_buffer) glDeleteRenderbuffers(1, &color_buffer); else @@ -613,7 +643,6 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, if (stencil_buffer && depth_buffer != stencil_buffer) glDeleteRenderbuffers(1, &stencil_buffer); glDeleteFramebuffers(1, &fbo); - fbo_guard.setId(0); } QT_CHECK_GLERROR(); @@ -622,6 +651,8 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, format.setAttachment(fbo_attachment); format.setInternalTextureFormat(internal_format); format.setMipmap(mipmap); + + glDevice.setFBO(q, attachment); } /*! @@ -849,23 +880,19 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm QGLFramebufferObject::~QGLFramebufferObject() { Q_D(QGLFramebufferObject); - QGL_FUNC_CONTEXT; delete d->engine; - if (isValid() && ctx) { - QGLShareContextScope scope(ctx); - if (d->texture) - glDeleteTextures(1, &d->texture); - if (d->color_buffer) - glDeleteRenderbuffers(1, &d->color_buffer); - if (d->depth_buffer) - glDeleteRenderbuffers(1, &d->depth_buffer); - if (d->stencil_buffer && d->stencil_buffer != d->depth_buffer) - glDeleteRenderbuffers(1, &d->stencil_buffer); - GLuint fbo = d->fbo(); - glDeleteFramebuffers(1, &fbo); - } + if (d->texture_guard) + d->texture_guard->free(); + if (d->color_buffer_guard) + d->color_buffer_guard->free(); + if (d->depth_buffer_guard) + d->depth_buffer_guard->free(); + if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard) + d->stencil_buffer_guard->free(); + if (d->fbo_guard) + d->fbo_guard->free(); } /*! @@ -889,7 +916,7 @@ QGLFramebufferObject::~QGLFramebufferObject() bool QGLFramebufferObject::isValid() const { Q_D(const QGLFramebufferObject); - return d->valid && d->fbo_guard.context(); + return d->valid && d->fbo_guard && d->fbo_guard->id(); } /*! @@ -972,7 +999,7 @@ bool QGLFramebufferObject::release() GLuint QGLFramebufferObject::texture() const { Q_D(const QGLFramebufferObject); - return d->texture; + return d->texture_guard ? d->texture_guard->id() : 0; } /*! diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h index f82361279d..61d39c6a07 100644 --- a/src/opengl/qglframebufferobject_p.h +++ b/src/opengl/qglframebufferobject_p.h @@ -130,8 +130,9 @@ private: class QGLFramebufferObjectPrivate { public: - QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_buffer(0), stencil_buffer(0) - , color_buffer(0), valid(false), engine(0) {} + QGLFramebufferObjectPrivate() : fbo_guard(0), texture_guard(0), depth_buffer_guard(0) + , stencil_buffer_guard(0), color_buffer_guard(0) + , valid(false), engine(0) {} ~QGLFramebufferObjectPrivate() {} void init(QGLFramebufferObject *q, const QSize& sz, @@ -139,11 +140,11 @@ public: GLenum internal_format, GLenum texture_target, GLint samples = 0, bool mipmap = false); bool checkFramebufferStatus() const; - QGLSharedResourceGuard fbo_guard; - GLuint texture; - GLuint depth_buffer; - GLuint stencil_buffer; - GLuint color_buffer; + QGLSharedResourceGuardBase *fbo_guard; + QGLSharedResourceGuardBase *texture_guard; + QGLSharedResourceGuardBase *depth_buffer_guard; + QGLSharedResourceGuardBase *stencil_buffer_guard; + QGLSharedResourceGuardBase *color_buffer_guard; GLenum target; QSize size; QGLFramebufferObjectFormat format; @@ -152,7 +153,7 @@ public: mutable QPaintEngine *engine; QGLFBOGLPaintDevice glDevice; - inline GLuint fbo() const { return fbo_guard.id(); } + inline GLuint fbo() const { return fbo_guard ? fbo_guard->id() : 0; } }; diff --git a/src/opengl/qglfunctions.cpp b/src/opengl/qglfunctions.cpp index 48549fb8d2..534c6c8bbf 100644 --- a/src/opengl/qglfunctions.cpp +++ b/src/opengl/qglfunctions.cpp @@ -41,6 +41,7 @@ #include "qglfunctions.h" #include "qgl_p.h" +#include "QtGui/private/qguiglcontext_qpa_p.h" QT_BEGIN_NAMESPACE @@ -139,16 +140,27 @@ QT_BEGIN_NAMESPACE */ // Hidden private fields for additional extension data. -struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate +struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResource { - QGLFunctionsPrivateEx(const QGLContext *context = 0) - : QGLFunctionsPrivate(context) + QGLFunctionsPrivateEx(QGuiGLContext *context) + : QGLFunctionsPrivate(QGLContext::fromGuiGLContext(context)) + , QGLSharedResource(context->shareGroup()) , m_features(-1) {} + void invalidateResource() + { + m_features = -1; + } + + void freeResource(QGuiGLContext *) + { + // no gl resources to free + } + int m_features; }; -Q_GLOBAL_STATIC(QGLContextGroupResource, qt_gl_functions_resource) +Q_GLOBAL_STATIC(QGLMultiGroupSharedResource, qt_gl_functions_resource) static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0) { @@ -157,13 +169,7 @@ static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0) Q_ASSERT(context); QGLFunctionsPrivateEx *funcs = reinterpret_cast - (qt_gl_functions_resource()->value(context)); -#if QT_VERSION < 0x040800 - if (!funcs) { - funcs = new QGLFunctionsPrivateEx(); - qt_gl_functions_resource()->insert(context, funcs); - } -#endif + (qt_gl_functions_resource()->value(context->contextHandle())); return funcs; } diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index de03553d8f..7b3f5d998d 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -189,15 +189,15 @@ class QGLShaderPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QGLShader) public: - QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type) - : shaderGuard(context) + QGLShaderPrivate(const QGLContext *, QGLShader::ShaderType type) + : shaderGuard(0) , shaderType(type) , compiled(false) { } ~QGLShaderPrivate(); - QGLSharedResourceGuard shaderGuard; + QGLSharedResourceGuardBase *shaderGuard; QGLShader::ShaderType shaderType; bool compiled; QString log; @@ -207,22 +207,28 @@ public: void deleteShader(); }; -#define ctx shaderGuard.context() +namespace { + void freeShaderFunc(QGLContext *ctx, GLuint id) + { + Q_UNUSED(ctx); + glDeleteShader(id); + } +} + +#define ctx QGLContext::currentContext() QGLShaderPrivate::~QGLShaderPrivate() { - if (shaderGuard.id()) { - QGLShareContextScope scope(shaderGuard.context()); - glDeleteShader(shaderGuard.id()); - } + if (shaderGuard) + shaderGuard->free(); } bool QGLShaderPrivate::create() { - const QGLContext *context = shaderGuard.context(); + QGLContext *context = const_cast(QGLContext::currentContext()); if (!context) return false; - if (qt_resolve_glsl_extensions(const_cast(context))) { + if (qt_resolve_glsl_extensions(context)) { GLuint shader; if (shaderType == QGLShader::Vertex) shader = glCreateShader(GL_VERTEX_SHADER); @@ -234,7 +240,7 @@ bool QGLShaderPrivate::create() qWarning() << "QGLShader: could not create shader"; return false; } - shaderGuard.setId(shader); + shaderGuard = createSharedResourceGuard(context, shader, freeShaderFunc); return true; } else { return false; @@ -243,7 +249,7 @@ bool QGLShaderPrivate::create() bool QGLShaderPrivate::compile(QGLShader *q) { - GLuint shader = shaderGuard.id(); + GLuint shader = shaderGuard ? shaderGuard->id() : 0; if (!shader) return false; glCompileShader(shader); @@ -286,15 +292,12 @@ bool QGLShaderPrivate::compile(QGLShader *q) void QGLShaderPrivate::deleteShader() { - if (shaderGuard.id()) { - glDeleteShader(shaderGuard.id()); - shaderGuard.setId(0); + if (shaderGuard) { + shaderGuard->free(); + shaderGuard = 0; } } -#undef ctx -#define ctx d->shaderGuard.context() - /*! Constructs a new QGLShader object of the specified \a type and attaches it to \a parent. If shader programs are not supported, @@ -387,7 +390,7 @@ static const char redefineHighp[] = bool QGLShader::compileSourceCode(const char *source) { Q_D(QGLShader); - if (d->shaderGuard.id()) { + if (d->shaderGuard && d->shaderGuard->id()) { QVarLengthArray src; QVarLengthArray srclen; int headerLen = 0; @@ -420,7 +423,7 @@ bool QGLShader::compileSourceCode(const char *source) #endif src.append(source + headerLen); srclen.append(GLint(qstrlen(source + headerLen))); - glShaderSource(d->shaderGuard.id(), src.size(), src.data(), srclen.data()); + glShaderSource(d->shaderGuard->id(), src.size(), src.data(), srclen.data()); return d->compile(this); } else { return false; @@ -480,7 +483,7 @@ bool QGLShader::compileSourceFile(const QString& fileName) QByteArray QGLShader::sourceCode() const { Q_D(const QGLShader); - GLuint shader = d->shaderGuard.id(); + GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0; if (!shader) return QByteArray(); GLint size = 0; @@ -525,22 +528,17 @@ QString QGLShader::log() const GLuint QGLShader::shaderId() const { Q_D(const QGLShader); - return d->shaderGuard.id(); + return d->shaderGuard ? d->shaderGuard->id() : 0; } - - - - #undef ctx -#define ctx programGuard.context() class QGLShaderProgramPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QGLShaderProgram) public: - QGLShaderProgramPrivate(const QGLContext *context) - : programGuard(context) + QGLShaderProgramPrivate(const QGLContext *) + : programGuard(0) , linked(false) , inited(false) , removingShaders(false) @@ -551,7 +549,7 @@ public: } ~QGLShaderProgramPrivate(); - QGLSharedResourceGuard programGuard; + QGLSharedResourceGuardBase *programGuard; bool linked; bool inited; bool removingShaders; @@ -567,12 +565,19 @@ public: bool hasShader(QGLShader::ShaderType type) const; }; +namespace { + void freeProgramFunc(QGLContext *ctx, GLuint id) + { + Q_UNUSED(ctx); + glDeleteProgram(id); + } +} + + QGLShaderProgramPrivate::~QGLShaderProgramPrivate() { - if (programGuard.id()) { - QGLShareContextScope scope(programGuard.context()); - glDeleteProgram(programGuard.id()); - } + if (programGuard) + programGuard->free(); } bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const @@ -584,8 +589,7 @@ bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const return false; } -#undef ctx -#define ctx d->programGuard.context() +#define ctx QGLContext::currentContext() /*! Constructs a new shader program and attaches it to \a parent. @@ -623,24 +627,21 @@ QGLShaderProgram::~QGLShaderProgram() bool QGLShaderProgram::init() { Q_D(QGLShaderProgram); - if (d->programGuard.id() || d->inited) + if ((d->programGuard && d->programGuard->id()) || d->inited) return true; d->inited = true; - const QGLContext *context = d->programGuard.context(); - if (!context) { - context = QGLContext::currentContext(); - d->programGuard.setContext(context); - } - + QGLContext *context = const_cast(QGLContext::currentContext()); if (!context) return false; - if (qt_resolve_glsl_extensions(const_cast(context))) { + if (qt_resolve_glsl_extensions(context)) { GLuint program = glCreateProgram(); if (!program) { qWarning() << "QGLShaderProgram: could not create shader program"; return false; } - d->programGuard.setId(program); + if (d->programGuard) + delete d->programGuard; + d->programGuard = createSharedResourceGuard(context, program, freeProgramFunc); return true; } else { qWarning() << "QGLShaderProgram: shader programs are not supported"; @@ -667,15 +668,14 @@ bool QGLShaderProgram::addShader(QGLShader *shader) return false; if (d->shaders.contains(shader)) return true; // Already added to this shader program. - if (d->programGuard.id() && shader) { - if (!QGLContext::areSharing(shader->d_func()->shaderGuard.context(), - d->programGuard.context())) { + if (d->programGuard && d->programGuard->id() && shader) { + if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id()) + return false; + if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) { qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context."); return false; } - if (!shader->d_func()->shaderGuard.id()) - return false; - glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id()); + glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); d->linked = false; // Program needs to be relinked. d->shaders.append(shader); connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed())); @@ -784,14 +784,17 @@ bool QGLShaderProgram::addShaderFromSourceFile /*! Removes \a shader from this shader program. The object is not deleted. + The shader program must be valid in the current QGLContext. + \sa addShader(), link(), removeAllShaders() */ void QGLShaderProgram::removeShader(QGLShader *shader) { Q_D(QGLShaderProgram); - if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) { - QGLShareContextScope scope(d->programGuard.context()); - glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id()); + if (d->programGuard && d->programGuard->id() + && shader && shader->d_func()->shaderGuard) + { + glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); } d->linked = false; // Program needs to be relinked. if (shader) { @@ -826,8 +829,11 @@ void QGLShaderProgram::removeAllShaders() Q_D(QGLShaderProgram); d->removingShaders = true; foreach (QGLShader *shader, d->shaders) { - if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) - glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id()); + if (d->programGuard && d->programGuard->id() + && shader && shader->d_func()->shaderGuard) + { + glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); + } } foreach (QGLShader *shader, d->anonShaders) { // Delete shader objects that were created anonymously. @@ -856,7 +862,7 @@ void QGLShaderProgram::removeAllShaders() bool QGLShaderProgram::link() { Q_D(QGLShaderProgram); - GLuint program = d->programGuard.id(); + GLuint program = d->programGuard ? d->programGuard->id() : 0; if (!program) return false; @@ -946,13 +952,13 @@ QString QGLShaderProgram::log() const bool QGLShaderProgram::bind() { Q_D(QGLShaderProgram); - GLuint program = d->programGuard.id(); + GLuint program = d->programGuard ? d->programGuard->id() : 0; if (!program) return false; if (!d->linked && !link()) return false; #ifndef QT_NO_DEBUG - if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) { + if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup()) { qWarning("QGLShaderProgram::bind: program is not valid in the current context."); return false; } @@ -974,7 +980,7 @@ void QGLShaderProgram::release() { #ifndef QT_NO_DEBUG Q_D(QGLShaderProgram); - if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) + if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup()) qWarning("QGLShaderProgram::release: program is not valid in the current context."); #endif #if defined(QT_OPENGL_ES_2) @@ -996,7 +1002,7 @@ void QGLShaderProgram::release() GLuint QGLShaderProgram::programId() const { Q_D(const QGLShaderProgram); - GLuint id = d->programGuard.id(); + GLuint id = d->programGuard ? d->programGuard->id() : 0; if (id) return id; @@ -1005,7 +1011,7 @@ GLuint QGLShaderProgram::programId() const // themselves, particularly those using program binaries. if (!const_cast(this)->init()) return 0; - return d->programGuard.id(); + return d->programGuard ? d->programGuard->id() : 0; } /*! @@ -1022,9 +1028,9 @@ GLuint QGLShaderProgram::programId() const void QGLShaderProgram::bindAttributeLocation(const char *name, int location) { Q_D(QGLShaderProgram); - if (!init()) + if (!init() || !d->programGuard || !d->programGuard->id()) return; - glBindAttribLocation(d->programGuard.id(), location, name); + glBindAttribLocation(d->programGuard->id(), location, name); d->linked = false; // Program needs to be relinked. } @@ -1074,8 +1080,8 @@ void QGLShaderProgram::bindAttributeLocation(const QString& name, int location) int QGLShaderProgram::attributeLocation(const char *name) const { Q_D(const QGLShaderProgram); - if (d->linked) { - return glGetAttribLocation(d->programGuard.id(), name); + if (d->linked && d->programGuard && d->programGuard->id()) { + return glGetAttribLocation(d->programGuard->id(), name); } else { qWarning() << "QGLShaderProgram::attributeLocation(" << name << "): shader program is not linked"; @@ -1752,8 +1758,8 @@ int QGLShaderProgram::uniformLocation(const char *name) const { Q_D(const QGLShaderProgram); Q_UNUSED(d); - if (d->linked) { - return glGetUniformLocation(d->programGuard.id(), name); + if (d->linked && d->programGuard && d->programGuard->id()) { + return glGetUniformLocation(d->programGuard->id(), name); } else { qWarning() << "QGLShaderProgram::uniformLocation(" << name << "): shader program is not linked"; -- cgit v1.2.3