From 9f72c297843459ab22eeb3af048baa9037aa9634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Wed, 17 Mar 2010 12:16:57 +0100 Subject: Make qt_gl_paint_engine() thread-safe. --- src/opengl/qgl.cpp | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 5c5d3d1..b875fd1 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -5031,25 +5031,54 @@ void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QM } #endif -#ifndef QT_OPENGL_ES_1 -Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine) +#if !defined(QT_OPENGL_ES_1) +class QtGL2EngineStorage +{ +public: + QPaintEngine *engine() { + QPaintEngine *localEngine = storage.localData(); + if (!localEngine) { + localEngine = new QGL2PaintEngineEx; + storage.setLocalData(localEngine); + } + return localEngine; + } + +private: + QThreadStorage storage; +}; +Q_GLOBAL_STATIC(QtGL2EngineStorage, qt_gl_2_engine) #endif #ifndef QT_OPENGL_ES_2 -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine) +class QtGL1EngineStorage +{ +public: + QPaintEngine *engine() { + QPaintEngine *localEngine = storage.localData(); + if (!localEngine) { + localEngine = new QOpenGLPaintEngine; + storage.setLocalData(localEngine); + } + return localEngine; + } +private: + QThreadStorage storage; +}; +Q_GLOBAL_STATIC(QtGL1EngineStorage, qt_gl_engine) #endif Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine() { #if defined(QT_OPENGL_ES_1) - return qt_gl_engine(); + return qt_gl_engine()->engine(); #elif defined(QT_OPENGL_ES_2) - return qt_gl_2_engine(); + return qt_gl_2_engine()->engine(); #else if (qt_gl_preferGL2Engine()) - return qt_gl_2_engine(); + return qt_gl_2_engine()->engine(); else - return qt_gl_engine(); + return qt_gl_engine()->engine(); #endif } -- cgit v0.12 From 38922774119817f4bf1595b9651f914e5c3d9f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 22 Jun 2010 12:51:00 +0200 Subject: More work on GL threading. Removed QObject inheritance from QGLEngineSharedShaders and made it thread-local, so that paintengines in different threads can use programs without clashing. Lifted some restrictions on QPixmap so that they may be used in threads when the GL2 engine is active. Made the QGLContextGroup a part of the pixmap and image cache keys. --- src/gui/image/qpixmap.cpp | 1 + src/gui/painting/qpainter.cpp | 11 ++- .../gl2paintengineex/qglengineshadermanager.cpp | 94 +++++++++++++++++----- .../gl2paintengineex/qglengineshadermanager_p.h | 13 ++- src/opengl/qgl.cpp | 12 ++- src/opengl/qgl_p.h | 3 + 6 files changed, 98 insertions(+), 36 deletions(-) diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 20e4b50..e630e80 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -94,6 +94,7 @@ Q_GUI_EXPORT qint64 qt_pixmap_id(const QPixmap &pixmap) static bool qt_pixmap_thread_test() { + return true; if (!qApp) { qFatal("QPixmap: Must construct a QApplication before a QPaintDevice"); return false; diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 312cc95..ec2aca4 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5252,7 +5252,8 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + if (d->engine->type() != QPaintEngine::OpenGL2) + qt_painter_thread_test(d->device->devType(), "drawPixmap()"); #endif if (d->extended) { @@ -5322,7 +5323,8 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) if (!d->engine || pm.isNull()) return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + if (d->engine->type() != QPaintEngine::OpenGL2) + qt_painter_thread_test(d->device->devType(), "drawPixmap()"); #endif qreal x = r.x(); @@ -5926,7 +5928,7 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText // Recreate the layout of the static text because the matrix or font has changed if (staticTextNeedsReinit) - staticText_d->init(); + staticText_d->init(); if (transformedPosition != staticText_d->position) { // Translate to actual position QFixed fx = QFixed::fromReal(transformedPosition.x()); @@ -6666,7 +6668,8 @@ void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPo return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()"); + if (d->engine->type() != QPaintEngine::OpenGL2) + qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()"); #endif qreal sw = pixmap.width(); diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 40b3641..5330706 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -51,19 +51,61 @@ QT_BEGIN_NAMESPACE static void qt_shared_shaders_free(void *data) { + qDebug() << "qt_shared_shaders_free() for thread:" << hex << QThread::currentThread(); delete reinterpret_cast(data); } -Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free)) + +class QGLThreadLocalShaders { +public: + QGLThreadLocalShaders(QGLContextResource *resource) : m_resource(resource), m_shaders(0) {} + ~QGLThreadLocalShaders() { + if (m_shaders) { + qDebug() << "~QGLThreadLocalShaders() for thread:" << hex << QThread::currentThread(); + m_shaders->cleanupBeforeDestruction(); + } + } + QGLContextResource *m_resource; + QGLEngineSharedShaders *m_shaders; +}; + +class QGLThreadShaders +{ +public: + QGLContextResource *shadersForThread() { + QGLThreadLocalShaders *shaders = m_storage.localData(); + if (!shaders) { + // The QGLContextResource is needed because the shaders need to be cleaned up + // when the context is destroyed, not just when a thread exits + QGLContextResource *resource = new QGLContextResource(qt_shared_shaders_free); + qDebug() << "new local resource for thread:" << hex << QThread::currentThread() << resource; + shaders = new QGLThreadLocalShaders(resource); + m_storage.setLocalData(shaders); + } + return shaders->m_resource; + } + + void setShadersForThread(const QGLContext *context, QGLEngineSharedShaders *sharedShaders) { + shadersForThread()->insert(context, sharedShaders); + m_storage.localData()->m_shaders = sharedShaders; + qDebug() << " -> context:" << context; + } + +private: + QThreadStorage m_storage; +}; + +Q_GLOBAL_STATIC(QGLThreadShaders, qt_shared_shaders); QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context) { - QGLEngineSharedShaders *p = reinterpret_cast(qt_shared_shaders()->value(context)); - if (!p) { + QGLEngineSharedShaders *shaders = reinterpret_cast(qt_shared_shaders()->shadersForThread()->value(context)); + if (!shaders) { QGLShareContextScope scope(context); - qt_shared_shaders()->insert(context, p = new QGLEngineSharedShaders(context)); + shaders = new QGLEngineSharedShaders(context); + qt_shared_shaders()->setShadersForThread(context, shaders); } - return p; + return shaders; } const char* QGLEngineSharedShaders::qShaderSnippets[] = { @@ -170,18 +212,20 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) source.clear(); source.append(qShaderSnippets[MainVertexShader]); source.append(qShaderSnippets[PositionOnlyVertexShader]); - vertexShader = new QGLShader(QGLShader::Vertex, context, this); + vertexShader = new QGLShader(QGLShader::Vertex, context, 0); + shaders.append(vertexShader); if (!vertexShader->compileSourceCode(source)) qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile"); source.clear(); source.append(qShaderSnippets[MainFragmentShader]); source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); - fragShader = new QGLShader(QGLShader::Fragment, context, this); + fragShader = new QGLShader(QGLShader::Fragment, context, 0); + shaders.append(fragShader); if (!fragShader->compileSourceCode(source)) qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); - simpleShaderProg = new QGLShaderProgram(context, this); + simpleShaderProg = new QGLShaderProgram(context, 0); simpleShaderProg->addShader(vertexShader); simpleShaderProg->addShader(fragShader); simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); @@ -198,18 +242,20 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) source.clear(); source.append(qShaderSnippets[MainWithTexCoordsVertexShader]); source.append(qShaderSnippets[UntransformedPositionVertexShader]); - vertexShader = new QGLShader(QGLShader::Vertex, context, this); + vertexShader = new QGLShader(QGLShader::Vertex, context, 0); + shaders.append(vertexShader); if (!vertexShader->compileSourceCode(source)) qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile"); source.clear(); source.append(qShaderSnippets[MainFragmentShader]); source.append(qShaderSnippets[ImageSrcFragmentShader]); - fragShader = new QGLShader(QGLShader::Fragment, context, this); + fragShader = new QGLShader(QGLShader::Fragment, context, 0); + shaders.append(fragShader); if (!fragShader->compileSourceCode(source)) qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); - blitShaderProg = new QGLShaderProgram(context, this); + blitShaderProg = new QGLShaderProgram(context, 0); blitShaderProg->addShader(vertexShader); blitShaderProg->addShader(fragShader); blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); @@ -224,9 +270,20 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) QGLEngineSharedShaders::~QGLEngineSharedShaders() { - QList::iterator itr; - for (itr = cachedPrograms.begin(); itr != cachedPrograms.end(); ++itr) - delete *itr; + cleanupBeforeDestruction(); +} + + +// This might be called both when a thread exits, or when the a +// context is destroyed + +void QGLEngineSharedShaders::cleanupBeforeDestruction() +{ + qDeleteAll(shaders); + shaders.clear(); + + qDeleteAll(cachedPrograms); + cachedPrograms.clear(); if (blitShaderProg) { delete blitShaderProg; @@ -276,7 +333,8 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS source.append(qShaderSnippets[prog.compositionFragShader]); if (prog.maskFragShader) source.append(qShaderSnippets[prog.maskFragShader]); - fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this); + fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0); + shaders.append(fragShader); QByteArray description; #if defined(QT_DEBUG) // Name the shader for easier debugging @@ -302,7 +360,8 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS source.clear(); source.append(qShaderSnippets[prog.mainVertexShader]); source.append(qShaderSnippets[prog.positionVertexShader]); - vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this); + vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0); + shaders.append(vertexShader); #if defined(QT_DEBUG) // Name the shader for easier debugging description.clear(); @@ -320,7 +379,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS newProg = new QGLEngineShaderProg(prog); // If the shader program's not found in the cache, create it now. - newProg->program = new QGLShaderProgram(ctxGuard.context(), this); + newProg->program = new QGLShaderProgram(ctxGuard.context(), 0); newProg->program->addShader(vertexShader); newProg->program->addShader(fragShader); @@ -413,7 +472,6 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) currentShaderProg(0) { sharedShaders = QGLEngineSharedShaders::shadersForContext(context); - connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot())); } QGLEngineShaderManager::~QGLEngineShaderManager() diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index 06b96ae..8d3697b 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -259,9 +259,9 @@ static const GLuint QT_PMV_MATRIX_3_ATTR = 5; class QGLEngineShaderProg; -class QGLEngineSharedShaders : public QObject +class QGLEngineSharedShaders { - Q_OBJECT + Q_GADGET public: enum SnippetName { @@ -364,14 +364,16 @@ public: // full. void cleanupCustomStage(QGLCustomShaderStage* stage); -signals: - void shaderProgNeedsChanging(); + // 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; QGLShaderProgram *simpleShaderProg; QList cachedPrograms; + QList shaders; static const char* qShaderSnippets[TotalSnippetCount]; }; @@ -492,9 +494,6 @@ public: QGLEngineSharedShaders* sharedShaders; -private slots: - void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; } - private: QGLContext* ctx; bool shaderProgNeedsChanging; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index b875fd1..fa6dd37 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2236,7 +2236,7 @@ QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_prem QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options) { - const qint64 key = image.cacheKey(); + const qint64 key = image.cacheKey() | (qint64) group; QGLTexture *texture = textureCacheLookup(key, target); if (texture) { glBindTexture(target, texture->id); @@ -2509,7 +2509,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, Q_UNUSED(q); #endif - const qint64 key = pixmap.cacheKey(); + const qint64 key = pixmap.cacheKey() | (qint64) group; QGLTexture *texture = textureCacheLookup(key, target); if (texture) { glBindTexture(target, texture->id); @@ -2532,6 +2532,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, } #endif + printf(" -> bindTexture key: %llx\n", key); if (!texture) { QImage image = pixmap.toImage(); // If the system depth is 16 and the pixmap doesn't have an alpha channel @@ -4061,11 +4062,7 @@ bool QGLWidget::event(QEvent *e) #if defined(Q_WS_X11) // prevents X errors on some systems, where we get a flush to a // hidden widget - if (e->type() == QEvent::Hide) { - makeCurrent(); - glFinish(); - doneCurrent(); - } else if (e->type() == QEvent::ParentChange) { + if (e->type() == QEvent::ParentChange) { // if we've reparented a window that has the current context // bound, we need to rebind that context to the new window id if (d->glcx == QGLContext::currentContext()) @@ -5373,6 +5370,7 @@ void *QGLContextResource::value(const QGLContext *key) void QGLContextResource::cleanup(const QGLContext *ctx, void *value) { + qDebug() << "QGLContextResource::cleanup() this:" << hex << this << "thread:" << QThread::currentThread(); QGLShareContextScope scope(ctx); free(value); active.deref(); diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 16c225f..9b862eb 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -473,6 +473,8 @@ private: QGLContext *m_ctx; }; +#include +#include class QGLTexture { public: QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D, @@ -489,6 +491,7 @@ public: ~QGLTexture() { if (options & QGLContext::MemoryManagedBindOption) { Q_ASSERT(context); + qDebug()<< "~QGLTexture: thread:" << hex <thread() << ")" << "context:" << context << "current context:" << QGLContext::currentContext(); QGLShareContextScope scope(context); #if defined(Q_WS_X11) // Although glXReleaseTexImage is a glX call, it must be called while there -- cgit v0.12 From 15ac2bc856735cdd81dde9f3d3dc2c47177ef814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 26 Mar 2010 10:05:16 +0100 Subject: Only use the texture_from_pixmap extension in the main thread. It's not possible to bind several texture ids to the same surface that wraps a native X11 Pixmap, which means we can't use it reliably from more than one thread at a time. For now we limit the usage to the main thread. --- src/opengl/qgl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index fa6dd37..995e753 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2521,7 +2521,8 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, const QX11Info *xinfo = qt_x11Info(paintDevice); if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType && xinfo && xinfo->screen() == pixmap.x11Info().screen() - && target == GL_TEXTURE_2D) + && target == GL_TEXTURE_2D + && QApplication::instance()->thread() == QThread::currentThread()) { texture = bindTextureFromNativePixmap(const_cast(&pixmap), key, options); if (texture) { -- cgit v0.12 From ac2818bef95f1347e80be8ce847f2557339b76e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Wed, 7 Apr 2010 14:57:24 +0200 Subject: Make it possible to call QWidget::metric() from a different thread. Under Windows. --- src/gui/kernel/qwidget_win.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 9d96fcb..60ba879 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -1633,8 +1633,6 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) } } -extern Q_GUI_EXPORT HDC qt_win_display_dc(); - int QWidget::metric(PaintDeviceMetric m) const { Q_D(const QWidget); @@ -1644,7 +1642,7 @@ int QWidget::metric(PaintDeviceMetric m) const } else if (m == PdmHeight) { val = data->crect.height(); } else { - HDC gdc = qt_win_display_dc(); + HDC gdc = GetDC(0); switch (m) { case PdmDpiX: case PdmPhysicalDpiX: @@ -1695,6 +1693,7 @@ int QWidget::metric(PaintDeviceMetric m) const val = 0; qWarning("QWidget::metric: Invalid metric command"); } + ReleaseDC(0, gdc); } return val; } -- cgit v0.12 From 7e464e38009f2492a41e9972a75f868cf88d353a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 9 Apr 2010 17:52:38 +0200 Subject: Simplify how the QGLEngineSharedShaders object is cleaned up. There are two things that needs to be done when cleaning up those objects: 1) if the context is destroyed before the specific thread exits, the shaders that is allocated within that context needs to be cleanup before the context is destroyed. 2) if the thread exits before the context is destroyed, the thread needs to clean up the shaders and then delete the QGLEngineSharedShaders object. We can't use a QGLContextResouce for that because a) we don't know if our context ptrs are valid, b) QGLContextResource doesn't remove themselves from the QGLContextGroups internal list when destroyed, so we might get a free() call *after* the resource had been destroyed. Use the contextDestroyed() signal from QGLSignalProxy() instead, which is cleaner and actually works.. --- .../gl2paintengineex/qglengineshadermanager.cpp | 67 +++++++++++----------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 5330706..7d6d8a6 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -46,66 +46,61 @@ #include #endif - QT_BEGIN_NAMESPACE -static void qt_shared_shaders_free(void *data) +class QGLThreadLocalShaders : public QObject { - qDebug() << "qt_shared_shaders_free() for thread:" << hex << QThread::currentThread(); - delete reinterpret_cast(data); -} - - -class QGLThreadLocalShaders { + Q_OBJECT public: - QGLThreadLocalShaders(QGLContextResource *resource) : m_resource(resource), m_shaders(0) {} + QGLThreadLocalShaders(const QGLContext *context, QGLEngineSharedShaders *shaders) + : m_context(context), m_shaders(shaders) + { + connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), + SLOT(contextDestroyed(const QGLContext*))); + } ~QGLThreadLocalShaders() { - if (m_shaders) { - qDebug() << "~QGLThreadLocalShaders() for thread:" << hex << QThread::currentThread(); + qDebug() << "~QGLThreadLocalShaders() for thread:" << hex << QThread::currentThread(); + qDebug() << " -> deleting shader cache:" << hex << m_shaders; + delete m_shaders; + } + const QGLContext *m_context; + QGLEngineSharedShaders *m_shaders; + +private slots: + void contextDestroyed(const QGLContext * context) { + if (context == m_context) { + qDebug() << "QGLThreadLocalShaders::contextDestroyed():"; + qDebug() << " -> cleaning up shader cache for thread:" << hex << QThread::currentThread(); + qDebug() << " -> shaders:" << hex << m_shaders; m_shaders->cleanupBeforeDestruction(); } } - QGLContextResource *m_resource; - QGLEngineSharedShaders *m_shaders; }; -class QGLThreadShaders +class QGLShaderStorage { public: - QGLContextResource *shadersForThread() { + QGLEngineSharedShaders *shadersForThread(const QGLContext *context) { QGLThreadLocalShaders *shaders = m_storage.localData(); if (!shaders) { - // The QGLContextResource is needed because the shaders need to be cleaned up - // when the context is destroyed, not just when a thread exits - QGLContextResource *resource = new QGLContextResource(qt_shared_shaders_free); - qDebug() << "new local resource for thread:" << hex << QThread::currentThread() << resource; - shaders = new QGLThreadLocalShaders(resource); + 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); } - return shaders->m_resource; - } - - void setShadersForThread(const QGLContext *context, QGLEngineSharedShaders *sharedShaders) { - shadersForThread()->insert(context, sharedShaders); - m_storage.localData()->m_shaders = sharedShaders; - qDebug() << " -> context:" << context; + return shaders->m_shaders; } private: QThreadStorage m_storage; }; -Q_GLOBAL_STATIC(QGLThreadShaders, qt_shared_shaders); +Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage); QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context) { - QGLEngineSharedShaders *shaders = reinterpret_cast(qt_shared_shaders()->shadersForThread()->value(context)); - if (!shaders) { - QGLShareContextScope scope(context); - shaders = new QGLEngineSharedShaders(context); - qt_shared_shaders()->setShadersForThread(context, shaders); - } - return shaders; + return reinterpret_cast(qt_shader_storage()->shadersForThread(context)); } const char* QGLEngineSharedShaders::qShaderSnippets[] = { @@ -845,3 +840,5 @@ bool QGLEngineShaderManager::useCorrectShaderProg() } QT_END_NAMESPACE + +#include "qglengineshadermanager.moc" -- cgit v0.12 From 4c3ac765b26e56fbf08c9f70cf43aa00a6565cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 16 Apr 2010 11:38:20 +0200 Subject: Don't use the QGLSignalProxy to clean up the thread-local shaders. After much back and forth I think we can use this approach for cleaning up thread-local, shared resources. Main problem has been dealing with dangling pointers and references, but they should be solved now. --- .../gl2paintengineex/qglengineshadermanager.cpp | 49 ++++++++++++++-------- src/opengl/qgl.cpp | 9 ++++ src/opengl/qgl_p.h | 2 + 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 7d6d8a6..0ba324d 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -48,42 +48,59 @@ QT_BEGIN_NAMESPACE -class QGLThreadLocalShaders : public QObject + +// 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); + +class QGLThreadLocalShaders { - Q_OBJECT public: QGLThreadLocalShaders(const QGLContext *context, QGLEngineSharedShaders *shaders) : m_context(context), m_shaders(shaders) { - connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), - SLOT(contextDestroyed(const QGLContext*))); + m_resource = new QGLContextResource(qt_gl_free_shared_shaders); + m_resource->insert(context, this); } ~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; - -private slots: - void contextDestroyed(const QGLContext * context) { - if (context == m_context) { - qDebug() << "QGLThreadLocalShaders::contextDestroyed():"; - qDebug() << " -> cleaning up shader cache for thread:" << hex << QThread::currentThread(); - qDebug() << " -> shaders:" << hex << m_shaders; - m_shaders->cleanupBeforeDestruction(); - } - } + QGLContextResource *m_resource; }; +static void qt_gl_free_shared_shaders(void *value) +{ + QGLThreadLocalShaders *local = reinterpret_cast(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; +} + class QGLShaderStorage { public: QGLEngineSharedShaders *shadersForThread(const QGLContext *context) { QGLThreadLocalShaders *shaders = m_storage.localData(); if (!shaders) { - qDebug() << "new shader cache for thread:" << hex << QThread::currentThread(); + qDebug() << "New shader cache for thread:" << hex << QThread::currentThread(); QGLShareContextScope scope(context); shaders = new QGLThreadLocalShaders(context, new QGLEngineSharedShaders(context)); qDebug() << " -> context:" << context; @@ -840,5 +857,3 @@ bool QGLEngineShaderManager::useCorrectShaderProg() } QT_END_NAMESPACE - -#include "qglengineshadermanager.moc" diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 995e753..1223552 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -5377,6 +5377,15 @@ void QGLContextResource::cleanup(const QGLContext *ctx, void *value) active.deref(); } +void QGLContextResource::remove(const QGLContext *ctx) +{ + if (ctx) { + QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx); + group->m_resources.remove(this); + active.deref(); + } +} + void QGLContextGroup::cleanupResources(const QGLContext *ctx) { // If there are still shares, then no cleanup to be done yet. diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 9b862eb..d5083e9 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -624,6 +624,8 @@ public: void *value(const QGLContext *key); // Cleanup 'value' in response to a context group being destroyed. void cleanup(const QGLContext *ctx, void *value); + // Remove this resource from the group's resource list. + void remove(const QGLContext *ctx); private: FreeFunc free; QAtomicInt active; -- cgit v0.12 From 80a2ebd93346f885d904e4e1020e112cc635dbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 22 Jun 2010 13:02:54 +0200 Subject: 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. --- .../gl2paintengineex/qglengineshadermanager.cpp | 80 ++++++++-------------- .../gl2paintengineex/qglengineshadermanager_p.h | 4 -- src/opengl/gl2paintengineex/qglgradientcache.cpp | 12 ++-- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 1 + .../gl2paintengineex/qtextureglyphcache_gl.cpp | 47 +++---------- .../gl2paintengineex/qtextureglyphcache_gl_p.h | 31 +++------ src/opengl/qgl.cpp | 61 +++++------------ src/opengl/qgl_p.h | 32 +++++++-- src/opengl/qglframebufferobject.cpp | 8 +-- src/opengl/qglpixelbuffer.cpp | 13 ++-- src/opengl/qglpixmapfilter.cpp | 12 ++-- 11 files changed, 116 insertions(+), 185 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(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(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(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(ptr); -} +public: + void freeResource(void *value) + { + delete reinterpret_cast(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(nextCtx); - } - } + if (m_width || m_height) + glDeleteTextures(1, &m_texture); } private: diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 1223552..753a984 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2028,6 +2028,7 @@ QGLContext::~QGLContext() // remove any textures cached in this context QGLTextureCache::instance()->removeContextTextures(this); + qDebug() << "~QGLContext(): about to clean up" << hex << this; d_ptr->group->cleanupResources(this); QGLSignalProxy::instance()->emitAboutToDestroyContext(this); @@ -2533,7 +2534,6 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, } #endif - printf(" -> bindTexture key: %llx\n", key); if (!texture) { QImage image = pixmap.toImage(); // If the system depth is 16 and the pixmap doesn't have an alpha channel @@ -5029,41 +5029,12 @@ void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QM } #endif -#if !defined(QT_OPENGL_ES_1) -class QtGL2EngineStorage -{ -public: - QPaintEngine *engine() { - QPaintEngine *localEngine = storage.localData(); - if (!localEngine) { - localEngine = new QGL2PaintEngineEx; - storage.setLocalData(localEngine); - } - return localEngine; - } - -private: - QThreadStorage storage; -}; -Q_GLOBAL_STATIC(QtGL2EngineStorage, qt_gl_2_engine) +#ifndef QT_OPENGL_ES_1 +Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_gl_2_engine) #endif #ifndef QT_OPENGL_ES_2 -class QtGL1EngineStorage -{ -public: - QPaintEngine *engine() { - QPaintEngine *localEngine = storage.localData(); - if (!localEngine) { - localEngine = new QOpenGLPaintEngine; - storage.setLocalData(localEngine); - } - return localEngine; - } -private: - QThreadStorage storage; -}; -Q_GLOBAL_STATIC(QtGL1EngineStorage, qt_gl_engine) +Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_gl_engine) #endif Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine() @@ -5339,13 +5310,17 @@ void QGLContextGroup::removeShare(const QGLContext *context) { group->m_shares.clear(); } -QGLContextResource::QGLContextResource(FreeFunc f) - : free(f), active(0) +QGLContextResource::QGLContextResource() + : active(0) { } QGLContextResource::~QGLContextResource() { + 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" @@ -5360,6 +5335,7 @@ void QGLContextResource::insert(const QGLContext *key, void *value) QGLContextGroup *group = QGLContextPrivate::contextGroup(key); Q_ASSERT(!group->m_resources.contains(this)); group->m_resources.insert(this, value); + m_groups.append(group); active.ref(); } @@ -5371,23 +5347,18 @@ void *QGLContextResource::value(const QGLContext *key) void QGLContextResource::cleanup(const QGLContext *ctx, void *value) { - qDebug() << "QGLContextResource::cleanup() this:" << hex << this << "thread:" << QThread::currentThread(); + qDebug() << "QGLContextResource::cleanup() this:" << hex << this << "ctx:" << ctx << "thread:" << (void *)QThread::currentThread(); QGLShareContextScope scope(ctx); - free(value); + freeResource(value); active.deref(); -} -void QGLContextResource::remove(const QGLContext *ctx) -{ - if (ctx) { - QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx); - group->m_resources.remove(this); - active.deref(); - } + QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx); + m_groups.removeOne(group); } void QGLContextGroup::cleanupResources(const QGLContext *ctx) { + qDebug() << "QGLContextGroup::cleanupResources() for ctx:" << hex << ctx << "shares:" << m_shares.size() << "res:" << m_resources.size(); // If there are still shares, then no cleanup to be done yet. if (m_shares.size() > 1) return; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index d5083e9..1399359 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -229,6 +229,7 @@ public: static void addShare(const QGLContext *context, const QGLContext *share); static void removeShare(const QGLContext *context); + private: QGLContextGroup(const QGLContext *context); @@ -491,7 +492,6 @@ public: ~QGLTexture() { if (options & QGLContext::MemoryManagedBindOption) { Q_ASSERT(context); - qDebug()<< "~QGLTexture: thread:" << hex <thread() << ")" << "context:" << context << "current context:" << QGLContext::currentContext(); QGLShareContextScope scope(context); #if defined(Q_WS_X11) // Although glXReleaseTexImage is a glX call, it must be called while there @@ -615,19 +615,17 @@ inline GLenum qt_gl_preferredTextureTarget() class Q_OPENGL_EXPORT QGLContextResource { public: - typedef void (*FreeFunc)(void *); - QGLContextResource(FreeFunc f); - ~QGLContextResource(); + QGLContextResource(); + virtual ~QGLContextResource(); // Set resource 'value' for 'key' and all its shared contexts. void insert(const QGLContext *key, void *value); // Return resource for 'key' or a shared context. void *value(const QGLContext *key); // Cleanup 'value' in response to a context group being destroyed. void cleanup(const QGLContext *ctx, void *value); - // Remove this resource from the group's resource list. - void remove(const QGLContext *ctx); + virtual void freeResource(void *value) = 0; private: - FreeFunc free; + QList m_groups; QAtomicInt active; }; @@ -720,6 +718,26 @@ private: int gl_extensions_length; }; + +// this is a class that wraps a QThreadStorage object for storing +// thread local instances of the GL 1 and GL 2 paint engines + +template +class QGLEngineThreadStorage +{ +public: + QPaintEngine *engine() { + QPaintEngine *localEngine = storage.localData(); + if (!localEngine) { + localEngine = new T; + storage.setLocalData(localEngine); + } + return localEngine; + } + +private: + QThreadStorage storage; +}; QT_END_NAMESPACE #endif // QGL_P_H diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index deffc20..fe60e83 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -984,11 +984,11 @@ QImage QGLFramebufferObject::toImage() const } #if !defined(QT_OPENGL_ES_1) -Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine) +Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_buffer_2_engine) #endif #ifndef QT_OPENGL_ES_2 -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine) +Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_buffer_engine) #endif /*! \reimp */ @@ -1002,7 +1002,7 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const #if !defined (QT_OPENGL_ES_2) if (qt_gl_preferGL2Engine()) { #endif - QPaintEngine *engine = qt_buffer_2_engine(); + QPaintEngine *engine = qt_buffer_2_engine()->engine(); if (engine->isActive() && engine->paintDevice() != this) { d->engine = new QGL2PaintEngineEx; return d->engine; @@ -1014,7 +1014,7 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const #endif #if !defined(QT_OPENGL_ES_2) - QPaintEngine *engine = qt_buffer_engine(); + QPaintEngine *engine = qt_buffer_engine()->engine(); if (engine->isActive() && engine->paintDevice() != this) { d->engine = new QOpenGLPaintEngine; return d->engine; diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 9a8b243..e5aed44 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -388,25 +388,26 @@ bool QGLPixelBuffer::isValid() const } #if !defined(QT_OPENGL_ES_1) -Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine) +Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_buffer_2_engine) #endif #ifndef QT_OPENGL_ES_2 -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine) +Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_buffer_engine) #endif /*! \reimp */ QPaintEngine *QGLPixelBuffer::paintEngine() const { + return qt_qgl_paint_engine(); #if defined(QT_OPENGL_ES_1) - return qt_buffer_engine(); + return qt_buffer_engine()->engine(); #elif defined(QT_OPENGL_ES_2) - return qt_buffer_2_engine(); + return qt_buffer_2_engine()->engine(); #else if (qt_gl_preferGL2Engine()) - return qt_buffer_2_engine(); + return qt_buffer_2_engine()->engine(); else - return qt_buffer_engine(); + return qt_buffer_engine()->engine(); #endif } diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index bfa5ef1..011869e 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -337,12 +337,16 @@ private: QList QGLBlurTextureCache::blurTextureCaches; -static void QGLBlurTextureCache_free(void *ptr) +class QGLBlurCacheResource : public QGLContextResource { - delete reinterpret_cast(ptr); -} +public: + void freeResource(void *value) + { + delete reinterpret_cast(value); + } +}; -Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_blur_texture_caches, (QGLBlurTextureCache_free)) +Q_GLOBAL_STATIC(QGLBlurCacheResource, qt_blur_texture_caches) QGLBlurTextureCache::QGLBlurTextureCache() : timerId(0) -- cgit v0.12 From 83abd5b9c8cf2b069c6b065ad37c93afe59d5d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 22 Jun 2010 13:12:13 +0200 Subject: Make the GL texture cache share textures between shared contexts. Up until now the GL 2 engine texture cache did not share glyph textures between sharing contexts, which is bad. Fix this by using the context group's context as the cache key. --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 260e797..fe0d6c9 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1453,12 +1453,13 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QOpenGL2PaintEngineState *s = q->state(); + void *cacheKey = const_cast(QGLContextPrivate::contextGroup(ctx)->context()); QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform()); + (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(cacheKey, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); cache->insert(ctx, cache); - staticTextItem->fontEngine->setGlyphCache(ctx, cache); + staticTextItem->fontEngine->setGlyphCache(cacheKey, cache); } cache->setPaintEnginePrivate(this); -- cgit v0.12 From 0441db10ddf2bd9141d7801e1e53c9cbdde2ebc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Wed, 28 Apr 2010 14:36:25 +0200 Subject: Remove the DDS texture cache. It has no practical use and is a leftover from when pixmap/image textures and dds textures used the same cache. --- src/opengl/qgl.cpp | 26 -------------------------- src/opengl/qgl_p.h | 3 --- 2 files changed, 29 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 753a984..3e556e0 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2089,20 +2089,10 @@ void QGLContextPrivate::syncGlState() GLuint QGLContext::bindTexture(const QString &fileName) { - Q_D(QGLContext); - QGLDDSCache *dds_cache = &(d->group->m_dds_cache); - QGLDDSCache::const_iterator it = dds_cache->constFind(fileName); - if (it != dds_cache->constEnd()) { - glBindTexture(GL_TEXTURE_2D, it.value()); - return it.value(); - } - QGLTexture texture(this); QSize size = texture.bindCompressedTexture(fileName); if (!size.isValid()) return 0; - - dds_cache->insert(fileName, texture.id); return texture.id; } @@ -2728,24 +2718,8 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, Q */ void QGLContext::deleteTexture(GLuint id) { - Q_D(QGLContext); - if (QGLTextureCache::instance()->remove(this, id)) return; - - // check the DDS cache if the texture wasn't found in the pixmap/image - // cache - QGLDDSCache *dds_cache = &(d->group->m_dds_cache); - QList ddsKeys = dds_cache->keys(); - for (int i = 0; i < ddsKeys.size(); ++i) { - GLuint texture = dds_cache->value(ddsKeys.at(i)); - if (id == texture) { - dds_cache->remove(ddsKeys.at(i)); - break; - } - } - - // Finally, actually delete the texture ID glDeleteTextures(1, &id); } diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 1399359..9b1856e 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -209,8 +209,6 @@ public: class QGLContextResource; class QGLSharedResourceGuard; -typedef QHash QGLDDSCache; - // QGLContextPrivate has the responsibility of creating context groups. // QGLContextPrivate maintains the reference counter and destroys // context groups when needed. @@ -239,7 +237,6 @@ private: QHash m_resources; QGLSharedResourceGuard *m_guards; // double-linked list of active guards. QAtomicInt m_refs; - QGLDDSCache m_dds_cache; void cleanupResources(const QGLContext *ctx); -- cgit v0.12 From 6451874792f515e5e30597e815a21a3a6cc325bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 30 Apr 2010 13:03:12 +0200 Subject: QGLPixelBuffer should manage its own paint engines. --- src/opengl/qgl.cpp | 2 -- src/opengl/qglpixelbuffer.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 3e556e0..74efb34 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -4035,8 +4035,6 @@ bool QGLWidget::event(QEvent *e) } #if defined(Q_WS_X11) - // prevents X errors on some systems, where we get a flush to a - // hidden widget if (e->type() == QEvent::ParentChange) { // if we've reparented a window that has the current context // bound, we need to rebind that context to the new window id diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index e5aed44..3d9cd21 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -398,7 +398,6 @@ Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_buffer_engine) /*! \reimp */ QPaintEngine *QGLPixelBuffer::paintEngine() const { - return qt_qgl_paint_engine(); #if defined(QT_OPENGL_ES_1) return qt_buffer_engine()->engine(); #elif defined(QT_OPENGL_ES_2) -- cgit v0.12 From decda7ea196b610ab1d70345cb89a4a67bfd1e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 30 Apr 2010 13:17:14 +0200 Subject: Unnecessary alloc + remove unused headers. --- src/opengl/qgl_p.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 9b1856e..acd799a 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -471,8 +471,6 @@ private: QGLContext *m_ctx; }; -#include -#include class QGLTexture { public: QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D, @@ -724,11 +722,9 @@ class QGLEngineThreadStorage { public: QPaintEngine *engine() { - QPaintEngine *localEngine = storage.localData(); - if (!localEngine) { + QPaintEngine *&localEngine = storage.localData(); + if (!localEngine) localEngine = new T; - storage.setLocalData(localEngine); - } return localEngine; } -- cgit v0.12 From 778ee2e9a2db3f3a1bc9d282356798baa77f6efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 30 Apr 2010 15:33:26 +0200 Subject: Add an application attribute to control XInitThreads(). In order to make Xlib thread-safe XInitThreads() needs to be the first Xlib call issued. This attribute controls this behavior. Having Xlib thread-safe will most likely incur some overhead, which is why this is not done by default. --- src/corelib/global/qnamespace.h | 1 + src/corelib/global/qnamespace.qdoc | 4 ++++ src/gui/image/qpixmap.cpp | 3 +-- src/gui/kernel/qapplication_x11.cpp | 3 +++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index a9c56f6..84ab567 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -530,6 +530,7 @@ public: AA_DontUseNativeMenuBar = 6, AA_MacDontSwapCtrlAndMeta = 7, AA_S60DontConstructApplicationPanes = 8, + AA_X11InitThreads = 9, // Add new attributes before this line AA_AttributeCount diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 7eae3a5..ce1176d 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -170,6 +170,10 @@ whole lifetime. This attribute must be set before QApplication is constructed. + \value AA_X11InitThreads Calls XInitThreads() as part of the QApplication + construction in order to make Xlib calls thread-safe. + + \omitvalue AA_AttributeCount */ diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index e630e80..a2b0b95 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -94,13 +94,12 @@ Q_GUI_EXPORT qint64 qt_pixmap_id(const QPixmap &pixmap) static bool qt_pixmap_thread_test() { - return true; if (!qApp) { qFatal("QPixmap: Must construct a QApplication before a QPaintDevice"); return false; } #ifndef Q_WS_WIN - if (qApp->thread() != QThread::currentThread()) { + if (!QApplication::testAttribute(Qt::AA_X11InitThreads) && qApp->thread() != QThread::currentThread()) { qWarning("QPixmap: It is not safe to use pixmaps outside the GUI thread"); return false; } diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 9d5a7c0..5e212ca 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -1710,6 +1710,9 @@ void qt_init(QApplicationPrivate *priv, int, } else { // Qt controls everything (default) + if (QApplication::testAttribute(Qt::AA_X11InitThreads)) + XInitThreads(); + // Set application name and class char *app_class = 0; if (argv && argv[0]) { -- cgit v0.12 From 76a14c8254f4f8beb16de897f31bab13dc7609a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 30 Apr 2010 15:53:06 +0200 Subject: Check Qt::AA_X11InitThreads to determine pixmap usage in threads. --- src/gui/painting/qpainter.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index ec2aca4..8ac40ee 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -155,6 +155,10 @@ static bool qt_painter_thread_test(int devType, const char *what, bool extraCond #endif break; default: +#ifdef Q_WS_X11 + if (QApplication::testAttribute(Qt::AA_X11InitThreads)) + return true; +#endif if (!extraCondition && QThread::currentThread() != qApp->thread()) { qWarning("QPainter: It is not safe to use %s outside the GUI thread", what); return false; @@ -5252,8 +5256,7 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) return; #ifndef QT_NO_DEBUG - if (d->engine->type() != QPaintEngine::OpenGL2) - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawPixmap()"); #endif if (d->extended) { @@ -5323,8 +5326,7 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) if (!d->engine || pm.isNull()) return; #ifndef QT_NO_DEBUG - if (d->engine->type() != QPaintEngine::OpenGL2) - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawPixmap()"); #endif qreal x = r.x(); @@ -6668,8 +6670,7 @@ void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPo return; #ifndef QT_NO_DEBUG - if (d->engine->type() != QPaintEngine::OpenGL2) - qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()"); #endif qreal sw = pixmap.width(); -- cgit v0.12 From b2de72a51124333b639fdfbda829f54088dff838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Thu, 17 Jun 2010 14:46:27 +0200 Subject: Rework the internal GL resource system yet again. Instead of having to sub-class QGLContextResource, we now have two template classes: 1. 'QGLContextResource' to handle context specific resources that are *not* shared in a group, even though the context itself is in a sharing group 2. 'QGLContextGroupResource' to handle resources shared in a context group. Classes used as the template class type must have a constructor with the following signature: T(const QGLContext *); The resources that the templates wrap are freed up when the context or context group it is tied to is destroyed. The resource is also freed when the QGLContextResource object is destroyed, which might lead to context switches, depending on where and in how many non-sharing contexts the resource is used. The templates wrap some boiler plate code that were common for all the use cases. --- .../gl2paintengineex/qglengineshadermanager.cpp | 49 +------- src/opengl/gl2paintengineex/qglgradientcache.cpp | 19 +-- src/opengl/gl2paintengineex/qglgradientcache_p.h | 4 +- .../gl2paintengineex/qtextureglyphcache_gl_p.h | 2 +- src/opengl/qgl.cpp | 34 +++-- src/opengl/qgl.h | 1 + src/opengl/qgl_p.h | 137 ++++++++++++++++++--- src/opengl/qglpixmapfilter.cpp | 23 +--- 8 files changed, 161 insertions(+), 108 deletions(-) diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 888bac9..c06bb3c 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -48,65 +48,27 @@ QT_BEGIN_NAMESPACE -class QGLSharedShaderResource : public QGLContextResource -{ -public: - ~QGLSharedShaderResource() { - qDebug() << "~QGLSharedShaderResource cleaned up" << hex << this; - } - - void freeResource(void *value) - { - qDebug() << "Context destroyed:"; - qDebug() << " -> deleting shader cache" << hex << value; - delete reinterpret_cast(value); - } -}; - -class QGLThreadLocalShaders -{ -public: - QGLEngineSharedShaders *shadersForContext(const QGLContext *context) { - QGLEngineSharedShaders *shaders = reinterpret_cast(m_resource.value(context)); - if (!shaders) { - QGLShareContextScope scope(context); - shaders = new QGLEngineSharedShaders(context); - qDebug() << " -> new shader cache for context:" << hex << context << "cache:" << shaders; - m_resource.insert(context, shaders); - } - return shaders; - } - - ~QGLThreadLocalShaders() { - qDebug() << "Thread exit:"; - qDebug() << "~QGLThreadLocalShaders() for thread:" << hex << QThread::currentThread(); - } - -private: - QGLSharedShaderResource m_resource; -}; - class QGLShaderStorage { public: QGLEngineSharedShaders *shadersForThread(const QGLContext *context) { - QGLThreadLocalShaders *&shaders = m_storage.localData(); + QGLContextGroupResource *&shaders = m_storage.localData(); if (!shaders) { qDebug() << "New thread storage for:" << hex << QThread::currentThread(); - shaders = new QGLThreadLocalShaders; + shaders = new QGLContextGroupResource(); } - return shaders->shadersForContext(context); + return shaders->value(context); } private: - QThreadStorage m_storage; + QThreadStorage *> m_storage; }; Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage); QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context) { - return reinterpret_cast(qt_shader_storage()->shadersForThread(context)); + return qt_shader_storage()->shadersForThread(context); } const char* QGLEngineSharedShaders::qShaderSnippets[] = { @@ -271,6 +233,7 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) QGLEngineSharedShaders::~QGLEngineSharedShaders() { + qDebug() << "####### ~QGLEngineSharedShaders() ##########"; qDeleteAll(shaders); shaders.clear(); diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index a0a3f8f..f1b095d 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache.cpp +++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp @@ -46,26 +46,11 @@ QT_BEGIN_NAMESPACE -class QGLGradientCacheResource : public QGLContextResource -{ -public: - void freeResource(void *value) - { - delete reinterpret_cast(value); - } -}; - -Q_GLOBAL_STATIC(QGLGradientCacheResource, qt_gradient_caches) +Q_GLOBAL_STATIC(QGLContextGroupResource, qt_gradient_caches) QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context) { - QGL2GradientCache *p = reinterpret_cast(qt_gradient_caches()->value(context)); - if (!p) { - QGLShareContextScope scope(context); - p = new QGL2GradientCache; - qt_gradient_caches()->insert(context, p); - } - return p; + return qt_gradient_caches()->value(context); } void QGL2GradientCache::cleanCache() { diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h index 0a5f846..8ecb34e 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache_p.h +++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h @@ -75,8 +75,8 @@ class QGL2GradientCache public: static QGL2GradientCache *cacheForContext(const QGLContext *context); - QGL2GradientCache() { } - ~QGL2GradientCache() {cleanCache();} + QGL2GradientCache(const QGLContext *) {} + ~QGL2GradientCache() { cleanCache(); } GLuint getBuffer(const QGradient &gradient, qreal opacity); inline int paletteSize() const { return 1024; } diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index 710a12d..1a78eed 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QGL2PaintEngineExPrivate; -class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QGLContextResource, public QImageTextureGlyphCache +class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QGLContextGroupResourceBase, public QImageTextureGlyphCache { public: QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 74efb34..6755d93 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2029,6 +2029,9 @@ QGLContext::~QGLContext() QGLTextureCache::instance()->removeContextTextures(this); qDebug() << "~QGLContext(): about to clean up" << hex << this; + // clean up resources specific to this context + d_ptr->cleanup(); + // clean up resources belonging to this context's group d_ptr->group->cleanupResources(this); QGLSignalProxy::instance()->emitAboutToDestroyContext(this); @@ -2037,6 +2040,10 @@ QGLContext::~QGLContext() void QGLContextPrivate::cleanup() { + QHash::ConstIterator it; + for (it = m_resources.begin(); it != m_resources.end(); ++it) + it.key()->freeResource(it.value()); + m_resources.clear(); } #define ctx q_ptr @@ -5282,15 +5289,17 @@ void QGLContextGroup::removeShare(const QGLContext *context) { group->m_shares.clear(); } -QGLContextResource::QGLContextResource() +QGLContextGroupResourceBase::QGLContextGroupResourceBase() : active(0) { } -QGLContextResource::~QGLContextResource() +QGLContextGroupResourceBase::~QGLContextGroupResourceBase() { + qDebug() << "~QGLContextGroupResourceBase()" << hex << this << "group size:" << m_groups.size(); for (int i = 0; i < m_groups.size(); ++i) { m_groups.at(i)->m_resources.remove(this); + qDebug() << " ->removing from group resource list:" << hex << this; active.deref(); } #ifndef QT_NO_DEBUG @@ -5302,24 +5311,24 @@ QGLContextResource::~QGLContextResource() #endif } -void QGLContextResource::insert(const QGLContext *key, void *value) +void QGLContextGroupResourceBase::insert(const QGLContext *context, void *value) { - QGLContextGroup *group = QGLContextPrivate::contextGroup(key); + QGLContextGroup *group = QGLContextPrivate::contextGroup(context); Q_ASSERT(!group->m_resources.contains(this)); group->m_resources.insert(this, value); m_groups.append(group); active.ref(); } -void *QGLContextResource::value(const QGLContext *key) +void *QGLContextGroupResourceBase::value(const QGLContext *context) { - QGLContextGroup *group = QGLContextPrivate::contextGroup(key); + QGLContextGroup *group = QGLContextPrivate::contextGroup(context); return group->m_resources.value(this, 0); } -void QGLContextResource::cleanup(const QGLContext *ctx, void *value) +void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value) { - qDebug() << "QGLContextResource::cleanup() this:" << hex << this << "ctx:" << ctx << "thread:" << (void *)QThread::currentThread(); + qDebug() << "QGLContextGroupResourceBase::cleanup() this:" << hex << this << "ctx:" << ctx << "thread:" << (void *)QThread::currentThread(); QGLShareContextScope scope(ctx); freeResource(value); active.deref(); @@ -5328,17 +5337,18 @@ void QGLContextResource::cleanup(const QGLContext *ctx, void *value) m_groups.removeOne(group); } -void QGLContextGroup::cleanupResources(const QGLContext *ctx) +void QGLContextGroup::cleanupResources(const QGLContext *context) { - qDebug() << "QGLContextGroup::cleanupResources() for ctx:" << hex << ctx << "shares:" << m_shares.size() << "res:" << m_resources.size(); + qDebug() << "QGLContextGroup::cleanupResources() for ctx:" << hex << context + << "shares:" << m_shares.size() << "res:" << m_resources.size(); // If there are still shares, then no cleanup to be done yet. if (m_shares.size() > 1) return; // Iterate over all resources and free each in turn. - QHash::ConstIterator it; + QHash::ConstIterator it; for (it = m_resources.begin(); it != m_resources.end(); ++it) - it.key()->cleanup(ctx, it.value()); + it.key()->cleanup(context, it.value()); } QGLSharedResourceGuard::~QGLSharedResourceGuard() diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index f0b36f7..d354f92 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -436,6 +436,7 @@ private: friend class QGLWidgetGLPaintDevice; friend class QX11GLPixmapData; friend class QX11GLSharedContexts; + friend class QGLContextResourceBase; private: Q_DISABLE_COPY(QGLContext) }; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index acd799a..3be30de 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -206,7 +206,7 @@ public: #endif }; -class QGLContextResource; +class QGLContextGroupResourceBase; class QGLSharedResourceGuard; // QGLContextPrivate has the responsibility of creating context groups. @@ -234,7 +234,7 @@ private: QGLExtensionFuncs m_extensionFuncs; const QGLContext *m_context; // context group's representative QList m_shares; - QHash m_resources; + QHash m_resources; QGLSharedResourceGuard *m_guards; // double-linked list of active guards. QAtomicInt m_refs; @@ -242,7 +242,7 @@ private: friend class QGLContext; friend class QGLContextPrivate; - friend class QGLContextResource; + friend class QGLContextGroupResourceBase; }; // Get the context that resources for "ctx" will transfer to once @@ -307,6 +307,8 @@ class QGLTexture; // all the GL2 engine uses: #define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3 +class QGLContextResourceBase; + class QGLContextPrivate { Q_DECLARE_PUBLIC(QGLContext) @@ -398,6 +400,7 @@ public: GLuint current_fbo; GLuint default_fbo; QPaintEngine *active_engine; + QHash m_resources; bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT]; @@ -606,24 +609,130 @@ inline GLenum qt_gl_preferredTextureTarget() #endif } -// One resource per group of shared contexts. -class Q_OPENGL_EXPORT QGLContextResource +/* + Base for resources that are shared in a context group. +*/ +class QGLContextGroupResourceBase { public: - QGLContextResource(); - virtual ~QGLContextResource(); - // Set resource 'value' for 'key' and all its shared contexts. - void insert(const QGLContext *key, void *value); - // Return resource for 'key' or a shared context. - void *value(const QGLContext *key); - // Cleanup 'value' in response to a context group being destroyed. - void cleanup(const QGLContext *ctx, void *value); + QGLContextGroupResourceBase(); + virtual ~QGLContextGroupResourceBase(); + void insert(const QGLContext *context, void *value); + void *value(const QGLContext *context); + void cleanup(const QGLContext *context, void *value); virtual void freeResource(void *value) = 0; -private: + +protected: QList 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); + } +}; + +/* + Base for resources that are context specific. +*/ +class QGLContextResourceBase +{ +public: + virtual ~QGLContextResourceBase() { + for (int i = 0; i < m_contexts.size(); ++i) + m_contexts.at(i)->d_ptr->m_resources.remove(this); + } + + void insert(const QGLContext *context, void *value) { + context->d_ptr->m_resources.insert(this, value); + } + + void *value(const QGLContext *context) { + return context->d_ptr->m_resources.value(this, 0); + } + virtual void freeResource(void *value) = 0; + +protected: + QList m_contexts; +}; + +/* + The QGLContextResource template is used to manage a resource for a + single GL context. Just before the context is destroyed (while it's + still the current context), or when the QGLContextResource object + itself is destroyed (implies potential context switches), the + resource will be freed. The class used as the template class type + needs to have a constructor with the following signature: T(const + QGLContext *); +*/ +template +class QGLContextResource : public QGLContextResourceBase +{ +public: + ~QGLContextResource() { + for (int i = 0; i < m_contexts.size(); ++i) { + const QGLContext *context = m_contexts.at(i); + T *resource = reinterpret_cast(QGLContextResourceBase::value(context)); + if (resource) { + QGLShareContextScope scope(context); + delete resource; + } + } + } + + T *value(const QGLContext *context) { + T *resource = reinterpret_cast(QGLContextResourceBase::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 diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 011869e..68586c1 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -315,7 +315,7 @@ class QGLBlurTextureCache : public QObject public: static QGLBlurTextureCache *cacheForContext(const QGLContext *context); - QGLBlurTextureCache(); + QGLBlurTextureCache(const QGLContext *); ~QGLBlurTextureCache(); QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap); @@ -336,19 +336,9 @@ private: }; QList QGLBlurTextureCache::blurTextureCaches; +Q_GLOBAL_STATIC(QGLContextGroupResource, qt_blur_texture_caches) -class QGLBlurCacheResource : public QGLContextResource -{ -public: - void freeResource(void *value) - { - delete reinterpret_cast(value); - } -}; - -Q_GLOBAL_STATIC(QGLBlurCacheResource, qt_blur_texture_caches) - -QGLBlurTextureCache::QGLBlurTextureCache() +QGLBlurTextureCache::QGLBlurTextureCache(const QGLContext *) : timerId(0) { cache.setMaxCost(4 * 1024 * 1024); @@ -370,12 +360,7 @@ void QGLBlurTextureCache::timerEvent(QTimerEvent *) QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context) { - QGLBlurTextureCache *p = reinterpret_cast(qt_blur_texture_caches()->value(context)); - if (!p) { - p = new QGLBlurTextureCache; - qt_blur_texture_caches()->insert(context, p); - } - return p; + return qt_blur_texture_caches()->value(context); } QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap) -- cgit v0.12 From 7348a762379bbc615194281806949e7fbac503a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Thu, 17 Jun 2010 15:57:03 +0200 Subject: Clarification regarding the WA_X11InitThreads flag. --- src/corelib/global/qnamespace.qdoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index ce1176d..19742e7 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -171,7 +171,8 @@ constructed. \value AA_X11InitThreads Calls XInitThreads() as part of the QApplication - construction in order to make Xlib calls thread-safe. + construction in order to make Xlib calls thread-safe. This + attribute must be set before QApplication is constructed. \omitvalue AA_AttributeCount -- cgit v0.12 From 35f0729a36f1562abc4b3bb12e35d86afdd19a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 22 Jun 2010 13:15:49 +0200 Subject: Clean up debug output. --- .../gl2paintengineex/qglengineshadermanager.cpp | 13 +++++++++---- .../gl2paintengineex/qtextureglyphcache_gl.cpp | 8 ++++++-- .../gl2paintengineex/qtextureglyphcache_gl_p.h | 5 ++++- src/opengl/qgl.cpp | 20 ++++++++++++++------ 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index c06bb3c..4b5f53e 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -46,6 +46,8 @@ #include #endif +// #define QT_GL_SHARED_SHADER_DEBUG + QT_BEGIN_NAMESPACE class QGLShaderStorage @@ -53,10 +55,8 @@ class QGLShaderStorage public: QGLEngineSharedShaders *shadersForThread(const QGLContext *context) { QGLContextGroupResource *&shaders = m_storage.localData(); - if (!shaders) { - qDebug() << "New thread storage for:" << hex << QThread::currentThread(); + if (!shaders) shaders = new QGLContextGroupResource(); - } return shaders->value(context); } @@ -229,11 +229,16 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) << simpleShaderProg->log(); } +#ifdef QT_GL_SHARED_SHADER_DEBUG + qDebug(" -> QGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread()); +#endif } QGLEngineSharedShaders::~QGLEngineSharedShaders() { - qDebug() << "####### ~QGLEngineSharedShaders() ##########"; +#ifdef QT_GL_SHARED_SHADER_DEBUG + qDebug(" -> ~QGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread()); +#endif qDeleteAll(shaders); shaders.clear(); diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 001a09e..290c57e 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -66,12 +66,16 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngin if (!ctx->d_ptr->workaround_brokenFBOReadBack && pex != 0) glGenFramebuffers(1, &m_fbo); - fprintf(stderr, "## QGLTextureGlyphCache(): ctx: %p - this: %p\n", ctx, this); +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, ctx); +#endif } QGLTextureGlyphCache::~QGLTextureGlyphCache() { - fprintf(stderr, "## ~QGLTextureGlyphCache(): context: %p - this: %p\n", ctx, this); +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug(" -> ~QGLTextureGlyphCache() %p.", this); +#endif } void QGLTextureGlyphCache::createTextureData(int width, int height) diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index 1a78eed..04d1354 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -57,6 +57,7 @@ #include #include +// #define QT_GL_TEXTURE_GLYPH_CACHE_DEBUG QT_BEGIN_NAMESPACE @@ -87,7 +88,9 @@ public: } void freeResource(void *) { - qDebug() << "QGLTextureGlyphCache::freeResource():" << this << "ctx:" << ctx; +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug("Freeing glyph cache resource %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 diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 6755d93..19ab51d 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -94,6 +94,8 @@ #include +// #define QT_GL_CONTEXT_RESOURCE_DEBUG + QT_BEGIN_NAMESPACE #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) @@ -2028,7 +2030,6 @@ QGLContext::~QGLContext() // remove any textures cached in this context QGLTextureCache::instance()->removeContextTextures(this); - qDebug() << "~QGLContext(): about to clean up" << hex << this; // clean up resources specific to this context d_ptr->cleanup(); // clean up resources belonging to this context's group @@ -5292,14 +5293,18 @@ void QGLContextGroup::removeShare(const QGLContext *context) { QGLContextGroupResourceBase::QGLContextGroupResourceBase() : active(0) { +#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG + qDebug("Creating context group resource object %p.", this); +#endif } QGLContextGroupResourceBase::~QGLContextGroupResourceBase() { - qDebug() << "~QGLContextGroupResourceBase()" << hex << this << "group size:" << m_groups.size(); +#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); - qDebug() << " ->removing from group resource list:" << hex << this; active.deref(); } #ifndef QT_NO_DEBUG @@ -5313,6 +5318,9 @@ QGLContextGroupResourceBase::~QGLContextGroupResourceBase() 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); @@ -5328,7 +5336,9 @@ void *QGLContextGroupResourceBase::value(const QGLContext *context) void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value) { - qDebug() << "QGLContextGroupResourceBase::cleanup() this:" << hex << this << "ctx:" << ctx << "thread:" << (void *)QThread::currentThread(); +#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(); @@ -5339,8 +5349,6 @@ void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value) void QGLContextGroup::cleanupResources(const QGLContext *context) { - qDebug() << "QGLContextGroup::cleanupResources() for ctx:" << hex << context - << "shares:" << m_shares.size() << "res:" << m_resources.size(); // If there are still shares, then no cleanup to be done yet. if (m_shares.size() > 1) return; -- cgit v0.12 From 48ecc50d1d5cb698749df97e4ecee0f096904618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Mon, 21 Jun 2010 17:04:09 +0200 Subject: Make qt_pixmap_serial thread-safe. --- src/gui/image/qpixmap_x11.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index 6bebefc..d61f21d 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -310,7 +310,7 @@ static int defaultScreen = -1; QPixmap member functions *****************************************************************************/ -static int qt_pixmap_serial = 0; +QBasicAtomicInt qt_pixmap_serial = Q_BASIC_ATOMIC_INITIALIZER(0); int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0; QX11PixmapData::QX11PixmapData(PixelType type) @@ -327,7 +327,7 @@ QPixmapData *QX11PixmapData::createCompatiblePixmapData() const void QX11PixmapData::resize(int width, int height) { - setSerialNumber(++qt_pixmap_serial); + setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); w = width; h = height; @@ -410,7 +410,7 @@ struct QX11AlphaDetector void QX11PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { - setSerialNumber(++qt_pixmap_serial); + setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); w = img.width(); h = img.height(); @@ -1950,7 +1950,7 @@ QPixmap QX11PixmapData::transformed(const QTransform &transform, x11Data->hd = (Qt::HANDLE)XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()), w, h, d); - x11Data->setSerialNumber(++qt_pixmap_serial); + x11Data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); #ifndef QT_NO_XRENDER if (X11->use_xrender) { @@ -2201,7 +2201,7 @@ void QX11PixmapData::copy(const QPixmapData *data, const QRect &rect) const QX11PixmapData *x11Data = static_cast(data); - setSerialNumber(++qt_pixmap_serial); + setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); flags &= ~Uninitialized; xinfo = x11Data->xinfo; @@ -2321,7 +2321,7 @@ QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE pixmap, QPixmap::ShareMode mode) } QX11PixmapData *data = new QX11PixmapData(depth == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType); - data->setSerialNumber(++qt_pixmap_serial); + data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); data->flags = QX11PixmapData::Readonly; data->share_mode = mode; data->w = width; -- cgit v0.12 From de7a1e3780c145b8721f42bb9477224b5a8ae93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Mon, 21 Jun 2010 17:04:43 +0200 Subject: Enable glyph uploads from a thread in the X11 font engine. Note: this doesn't necessarily mean it's thread-safe yet. --- src/gui/text/qfontengine_x11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp index b7e4be2..aee21f6 100644 --- a/src/gui/text/qfontengine_x11.cpp +++ b/src/gui/text/qfontengine_x11.cpp @@ -992,7 +992,7 @@ QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int s face_id.filename = file_name; face_id.index = face_index; - canUploadGlyphsToServer = qApp->thread() == QThread::currentThread(); + canUploadGlyphsToServer = QApplication::testAttribute(Qt::AA_X11InitThreads) || (qApp->thread() == QThread::currentThread()); subpixelType = Subpixel_None; if (antialias) { -- cgit v0.12 From 10ac24c98ea7f2738662be91fda7feec7f322dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 22 Jun 2010 12:34:07 +0200 Subject: The group pointer should no longer be a part of the 64 bit int. The group is now a proper part of the QGLTextureCacheKey, and it's no longer necessary with this hack. --- src/opengl/qgl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 19ab51d..1f2a886 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2235,7 +2235,7 @@ QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_prem QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options) { - const qint64 key = image.cacheKey() | (qint64) group; + const qint64 key = image.cacheKey(); QGLTexture *texture = textureCacheLookup(key, target); if (texture) { glBindTexture(target, texture->id); @@ -2508,7 +2508,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, Q_UNUSED(q); #endif - const qint64 key = pixmap.cacheKey() | (qint64) group; + const qint64 key = pixmap.cacheKey(); QGLTexture *texture = textureCacheLookup(key, target); if (texture) { glBindTexture(target, texture->id); -- cgit v0.12 From e11af338a0d0e96a8100d0e78cc42e67e1447864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Wed, 23 Jun 2010 16:04:28 +0200 Subject: Rework how QGLTextureGlyphCache makes use of the resource system. Separate out the GL objects (the texture and the fbo) that needs to be tracked into a QGLGlyphTexture structure and make that accessible via a QGLContextGroupResource object. --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 1 - .../gl2paintengineex/qtextureglyphcache_gl.cpp | 45 ++++++----- .../gl2paintengineex/qtextureglyphcache_gl_p.h | 86 ++++++++++++++-------- src/opengl/qgl.h | 1 + 4 files changed, 77 insertions(+), 56 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index fe0d6c9..756180f 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1458,7 +1458,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(cacheKey, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); - cache->insert(ctx, cache); staticTextItem->fontEngine->setGlyphCache(cacheKey, cache); } diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 290c57e..b4dc4fa 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -54,21 +54,12 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled; QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) : QImageTextureGlyphCache(type, matrix) - , ctx(context) - , m_width(0) - , m_height(0) + , ctx(0) { - // 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. - // Switching to NPOT and GL_RGBA would both cost a lot more graphics memory and - // be slower, so that is not desireable. - if (!ctx->d_ptr->workaround_brokenFBOReadBack && pex != 0) - glGenFramebuffers(1, &m_fbo); - #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, ctx); #endif + setContext(context); } QGLTextureGlyphCache::~QGLTextureGlyphCache() @@ -78,6 +69,12 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache() #endif } +void QGLTextureGlyphCache::setContext(const QGLContext *context) +{ + ctx = context; + m_h = 0; +} + void QGLTextureGlyphCache::createTextureData(int width, int height) { if (ctx == 0) { @@ -97,11 +94,12 @@ void QGLTextureGlyphCache::createTextureData(int width, int height) if (height < 16) height = 16; - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); + QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx); + glGenTextures(1, &glyphTexture->m_texture); + glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture); - m_width = width; - m_height = height; + glyphTexture->m_width = width; + glyphTexture->m_height = height; QVarLengthArray data(width * height); for (int i = 0; i < data.size(); ++i) @@ -122,9 +120,10 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context"); return; } + QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx); - int oldWidth = m_width; - int oldHeight = m_height; + int oldWidth = glyphTexture->m_width; + int oldHeight = glyphTexture->m_height; // Make the lower glyph texture size 16 x 16. if (width < 16) @@ -132,7 +131,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) if (height < 16) height = 16; - GLuint oldTexture = m_texture; + GLuint oldTexture = glyphTexture->m_texture; createTextureData(width, height); if (pex == 0 || ctx->d_ptr->workaround_brokenFBOReadBack) { @@ -146,7 +145,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) // ### the QTextureGlyphCache API needs to be reworked to allow // ### resizeTextureData to fail - glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, glyphTexture->m_fbo); GLuint tmp_texture; glGenTextures(1, &tmp_texture); @@ -201,7 +200,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindTexture(GL_TEXTURE_2D, m_texture); + glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); @@ -223,10 +222,11 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) return; } + QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx); if (pex == 0 || ctx->d_ptr->workaround_brokenFBOReadBack) { QImageTextureGlyphCache::fillTexture(c, glyph); - glBindTexture(GL_TEXTURE_2D, m_texture); + glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture); const QImage &texture = image(); const uchar *bits = texture.constBits(); bits += c.y * texture.bytesPerLine() + c.x; @@ -234,7 +234,6 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits); bits += texture.bytesPerLine(); } - return; } @@ -264,7 +263,7 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) } } - glBindTexture(GL_TEXTURE_2D, m_texture); + glBindTexture(GL_TEXTURE_2D, glyphTexture->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 { diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index 04d1354..66aed91 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -63,7 +63,42 @@ QT_BEGIN_NAMESPACE class QGL2PaintEngineExPrivate; -class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QGLContextGroupResourceBase, public QImageTextureGlyphCache +struct QGLGlyphTexture +{ + QGLGlyphTexture(const QGLContext *ctx) + : m_width(0) + , m_height(0) + { + if (ctx && !ctx->d_ptr->workaround_brokenFBOReadBack) + glGenFramebuffers(1, &m_fbo); + +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug(" -> QGLGlyphTexture() %p for context %p.", this, ctx); +#endif + } + + ~QGLGlyphTexture() { + const QGLContext *ctx = QGLContext::currentContext(); +#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); + } + } + + GLuint m_texture; + GLuint m_fbo; + int m_width; + int m_height; +}; + +class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache { public: QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); @@ -75,46 +110,33 @@ public: virtual int glyphMargin() const; virtual int glyphPadding() const; - inline GLuint texture() const { return m_texture; } - - inline int width() const { return m_width; } - inline int height() const { return m_height; } - - inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } - - inline const QGLContext *context() const - { - return ctx; + inline GLuint texture() const { + QGLTextureGlyphCache *that = const_cast(this); + QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx); + return glyphTexture ? glyphTexture->m_texture : 0; } - void freeResource(void *) { -#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG - qDebug("Freeing glyph cache resource %p for context %p.", this, ctx); -#endif + inline int width() const { + QGLTextureGlyphCache *that = const_cast(this); + QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx); + return glyphTexture ? glyphTexture->m_width : 0; + } + inline int height() const { + QGLTextureGlyphCache *that = const_cast(this); + QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx); + return glyphTexture ? glyphTexture->m_height : 0; + } - // 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); + inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } - if (m_width || m_height) - glDeleteTextures(1, &m_texture); - } + void setContext(const QGLContext *context); + inline const QGLContext *context() const { return ctx; } private: - void cleanUpContext(); + QGLContextGroupResource m_textureResource; const QGLContext *ctx; - QGL2PaintEngineExPrivate *pex; - - GLuint m_texture; - GLuint m_fbo; - - int m_width; - int m_height; - - QGLShaderProgram *m_program; }; QT_END_NAMESPACE diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index d354f92..1bef33d 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -417,6 +417,7 @@ private: friend class QGLPixmapData; friend class QGLPixmapFilterBase; friend class QGLTextureGlyphCache; + friend class QGLGlyphTexture; friend class QGLContextGroup; friend class QGLSharedResourceGuard; friend class QGLPixmapBlurFilter; -- cgit v0.12 From 449cbdfd1b8523e721d8b86e49647495b67005e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 2 Jul 2010 15:38:07 +0200 Subject: Fix the tests for the internal GL resource system. --- src/opengl/qgl_p.h | 4 ++-- tests/auto/qgl/tst_qgl.cpp | 26 +++++++++----------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 3be30de..fd6b7f0 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -612,7 +612,7 @@ inline GLenum qt_gl_preferredTextureTarget() /* Base for resources that are shared in a context group. */ -class QGLContextGroupResourceBase +class Q_OPENGL_EXPORT QGLContextGroupResourceBase { public: QGLContextGroupResourceBase(); @@ -673,7 +673,7 @@ protected: /* Base for resources that are context specific. */ -class QGLContextResourceBase +class Q_OPENGL_EXPORT QGLContextResourceBase { public: virtual ~QGLContextResourceBase() { diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp index 8ee494f..c05f730 100644 --- a/tests/auto/qgl/tst_qgl.cpp +++ b/tests/auto/qgl/tst_qgl.cpp @@ -1871,11 +1871,10 @@ void tst_QGL::destroyFBOAfterContext() #ifdef QT_BUILD_INTERNAL -class tst_QGLResource : public QObject +class tst_QGLResource { - Q_OBJECT public: - tst_QGLResource(QObject *parent = 0) : QObject(parent) {} + tst_QGLResource(const QGLContext * = 0) {} ~tst_QGLResource() { ++deletions; } static int deletions; @@ -1883,12 +1882,7 @@ public: int tst_QGLResource::deletions = 0; -static void qt_shared_test_free(void *data) -{ - delete reinterpret_cast(data); -} - -Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_test, (qt_shared_test_free)) +Q_GLOBAL_STATIC(QGLContextGroupResource, qt_shared_test) #endif @@ -1908,10 +1902,9 @@ void tst_QGL::shareRegister() guard.setId(3); QVERIFY(guard.id() == 3); - // Add a resource to the first context. - tst_QGLResource *res1 = new tst_QGLResource(); - QVERIFY(!qt_shared_test()->value(glw1->context())); - qt_shared_test()->insert(glw1->context(), res1); + // Request a tst_QGLResource object for the first context. + tst_QGLResource *res1 = qt_shared_test()->value(glw1->context()); + QVERIFY(res1); QVERIFY(qt_shared_test()->value(glw1->context()) == res1); // Create another context that shares with the first. @@ -1950,10 +1943,9 @@ void tst_QGL::shareRegister() QGLSharedResourceGuard guard3(glw3->context()); guard3.setId(5); - // Add a resource to the third context. - tst_QGLResource *res3 = new tst_QGLResource(); - QVERIFY(!qt_shared_test()->value(glw3->context())); - qt_shared_test()->insert(glw3->context(), res3); + // Request a resource to the third context. + tst_QGLResource *res3 = qt_shared_test()->value(glw3->context()); + QVERIFY(res3); QVERIFY(qt_shared_test()->value(glw1->context()) == res1); QVERIFY(qt_shared_test()->value(glw2->context()) == res1); QVERIFY(qt_shared_test()->value(glw3->context()) == res3); -- cgit v0.12 From 6f0597a198912628c52f22ece63cb5d169dcaed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 2 Jul 2010 16:35:44 +0200 Subject: Remove warning. --- src/opengl/qgl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 1bef33d..b6a95e7 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -417,7 +417,7 @@ private: friend class QGLPixmapData; friend class QGLPixmapFilterBase; friend class QGLTextureGlyphCache; - friend class QGLGlyphTexture; + friend struct QGLGlyphTexture; friend class QGLContextGroup; friend class QGLSharedResourceGuard; friend class QGLPixmapBlurFilter; -- cgit v0.12 From 21158f7b31b6053b4c704f434f3f480328a0ba65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Fri, 2 Jul 2010 17:55:49 +0200 Subject: Initialize pex. This got lost in a conflict resolving session. --- src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index b4dc4fa..9ce5d55 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -55,6 +55,7 @@ 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) { #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, ctx); -- cgit v0.12 From 40c8aba524831dd0d2f8dfcdf07797f5c2c47f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Mon, 5 Jul 2010 14:15:57 +0200 Subject: QGLPixelBuffer should not rely on temporary QGLWidgets. Use QGLTemporaryContext instead. Also, to re-use already registered window classes for the temporary native window, make qt_reg_wndclass() register a QWidget default class if it's passed a 0 pointer. Reviewed-by: Gunnar --- src/gui/kernel/qapplication_win.cpp | 25 +++++++++++++++++-------- src/gui/painting/qpainter.cpp | 10 +++++----- src/opengl/qglpixelbuffer_win.cpp | 8 ++------ 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index e10a6b0..c5340c0 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -944,26 +944,33 @@ bool qt_nograb() // application no-grab option typedef QHash WinClassNameHash; Q_GLOBAL_STATIC(WinClassNameHash, winclassNames) +// +// If 0 is passed as the widget pointer, register a window class +// for QWidget as default. This is used in QGLTemporaryContext +// during GL initialization, where we don't want to use temporary +// QWidgets or QGLWidgets, neither do we want to have separate code +// to register window classes. +// const QString qt_reg_winclass(QWidget *w) // register window class { - int flags = w->windowFlags(); + int flags = w ? w->windowFlags() : 0; int type = flags & Qt::WindowType_Mask; uint style; bool icon; QString cname; - if (qt_widget_private(w)->isGLWidget) { + if (w && qt_widget_private(w)->isGLWidget) { cname = QLatin1String("QGLWidget"); style = CS_DBLCLKS; icon = true; - } else if (flags & Qt::MSWindowsOwnDC) { + } else if (w && (flags & Qt::MSWindowsOwnDC)) { cname = QLatin1String("QWidgetOwnDC"); style = CS_DBLCLKS; #ifndef Q_WS_WINCE style |= CS_OWNDC; #endif icon = true; - } else if (type == Qt::Tool || type == Qt::ToolTip){ + } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) { style = CS_DBLCLKS; if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) { if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP @@ -978,7 +985,7 @@ const QString qt_reg_winclass(QWidget *w) // register window class style |= CS_SAVEBITS; #endif icon = false; - } else if (type == Qt::Popup) { + } else if (w && (type == Qt::Popup)) { cname = QLatin1String("QPopup"); style = CS_DBLCLKS; #ifndef Q_WS_WINCE @@ -1049,7 +1056,10 @@ const QString qt_reg_winclass(QWidget *w) // register window class } wc.hCursor = 0; #ifndef Q_WS_WINCE - wc.hbrBackground = qt_widget_private(w)->isGLWidget ? 0 : (HBRUSH)GetSysColorBrush(COLOR_WINDOW); + HBRUSH brush = 0; + if (w && !qt_widget_private(w)->isGLWidget) + brush = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); + wc.hbrBackground = brush; #else wc.hbrBackground = 0; #endif @@ -1071,8 +1081,7 @@ const QString qt_reg_winclass(QWidget *w) // register window class Q_GUI_EXPORT const QString qt_getRegisteredWndClass() { - QWidget w; - return qt_reg_winclass(&w); + return qt_reg_winclass(0); } static void unregWinClasses() diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 8ac40ee..0911d4f 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5256,7 +5256,7 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawPixmap()", true); #endif if (d->extended) { @@ -5326,7 +5326,7 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) if (!d->engine || pm.isNull()) return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawPixmap()", true); #endif qreal x = r.x(); @@ -5733,7 +5733,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) int count = qMin(glyphIndexes.size(), glyphPositions.size()); QVarLengthArray fixedPointPositions(count); for (int i=0; idrawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count); @@ -5742,7 +5742,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray, int glyphCount) -{ +{ QVarLengthArray positions(glyphCount); for (int i=0; idevice->devType(), "drawTiledPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()", true); #endif qreal sw = pixmap.width(); diff --git a/src/opengl/qglpixelbuffer_win.cpp b/src/opengl/qglpixelbuffer_win.cpp index 8d0d105..df83566 100644 --- a/src/opengl/qglpixelbuffer_win.cpp +++ b/src/opengl/qglpixelbuffer_win.cpp @@ -239,8 +239,7 @@ static void qt_format_to_attrib_list(bool has_render_texture, const QGLFormat &f bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget) { - QGLWidget dmy; - dmy.makeCurrent(); // needed for wglGetProcAddress() to succeed + QGLTemporaryContext tempContext; PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC) wglGetProcAddress("wglCreatePbufferARB"); @@ -254,7 +253,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge if (!wglCreatePbufferARB) // assumes that if one can be resolved, all of them can return false; - dc = GetDC(dmy.winId()); + dc = wglGetCurrentDC(); Q_ASSERT(dc); PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = @@ -284,7 +283,6 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge if (num_formats == 0) { qWarning("QGLPixelBuffer: Unable to find a pixel format with pbuffer - giving up."); - ReleaseDC(dmy.winId(), dc); return false; } format = pfiToQGLFormat(dc, pixel_format); @@ -303,12 +301,10 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge has_render_texture = false; if (!pbuf) { qWarning("QGLPixelBuffer: Unable to create pbuffer [w=%d, h=%d] - giving up.", size.width(), size.height()); - ReleaseDC(dmy.winId(), dc); return false; } } - ReleaseDC(dmy.winId(), dc); dc = wglGetPbufferDCARB(pbuf); ctx = wglCreateContext(dc); -- cgit v0.12