diff options
author | Tom Cooksey <thomas.cooksey@nokia.com> | 2010-04-21 15:40:04 (GMT) |
---|---|---|
committer | Tom Cooksey <thomas.cooksey@nokia.com> | 2010-04-22 14:38:00 (GMT) |
commit | 1a00c7dec743c05b0f64bcacc03b3d2c90ac881d (patch) | |
tree | d5978862d076dbd43c0c03f8ecc0bbc8e35e1544 | |
parent | 71d6e5a73b6e4434c47194d938a8b74c92170644 (diff) | |
download | Qt-1a00c7dec743c05b0f64bcacc03b3d2c90ac881d.zip Qt-1a00c7dec743c05b0f64bcacc03b3d2c90ac881d.tar.gz Qt-1a00c7dec743c05b0f64bcacc03b3d2c90ac881d.tar.bz2 |
QX11GL: Move the shared context ownership into a seperate class
This patch moves initialisation into a new QX11GLSharedContexts
class which is created as a Q_GLOBAL_STATIC. This class owns both
the RGB/ARGB EGL contexts and the QGLContext used for sharing.
Finally, the shared QGLContext is make a valid context wrapping the
RGB EGL context and a small pixmap surface. This makes the shared
QGLContext the QGLContextGroup master, so when it is deleted, it
can be made current to delete the GL resources. Among other benefits,
this patch stops apps seg-faulting when they gracefully quit.
Reviewed-By: TrustMe
-rw-r--r-- | src/opengl/qgl.h | 1 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_x11gl_egl.cpp | 241 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_x11gl_p.h | 7 |
3 files changed, 148 insertions, 101 deletions
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index b1e2ede..92a064f 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -432,6 +432,7 @@ private: friend class QGLFBOGLPaintDevice; friend class QGLPaintDevice; friend class QX11GLPixmapData; + friend class QX11GLSharedContexts; private: Q_DISABLE_COPY(QGLContext) }; diff --git a/src/opengl/qpixmapdata_x11gl_egl.cpp b/src/opengl/qpixmapdata_x11gl_egl.cpp index 3b11749..58d34fc 100644 --- a/src/opengl/qpixmapdata_x11gl_egl.cpp +++ b/src/opengl/qpixmapdata_x11gl_egl.cpp @@ -62,123 +62,170 @@ QT_BEGIN_NAMESPACE -// On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need -// different contexts: - -Q_GLOBAL_STATIC(QEglContext, qt_x11gl_rgbContext); -Q_GLOBAL_STATIC(QEglContext, qt_x11gl_argbContext); -Q_GLOBAL_STATIC_WITH_ARGS(QGLContext, qt_x11gl_fake_shared_context, (QX11GLPixmapData::glFormat())); +class QX11GLSharedContexts +{ +public: + QX11GLSharedContexts() + : rgbContext(0) + , argbContext(0) + , sharedQGLContext(0) + , sharePixmap(0) + { + EGLint rgbConfigId; + EGLint argbConfigId; + + + do { + EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); + EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, + QEgl::Renderable | QEgl::Translucent); + + eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); + eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); + + rgbContext = new QEglContext; + rgbContext->setConfig(rgbConfig); + rgbContext->createContext(); -QEglContext* QX11GLPixmapData::rgbContext = 0; -QEglContext* QX11GLPixmapData::argbContext = 0; + if (!rgbContext->isValid()) + break; + // If the RGB & ARGB configs are the same, use the same egl context for both: + if (rgbConfig == argbConfig) + argbContext = rgbContext; + + // Otherwise, create a seperate context to be used for ARGB pixmaps: + if (!argbContext) { + argbContext = new QEglContext; + argbContext->setConfig(argbConfig); + bool success = argbContext->createContext(rgbContext); + if (!success) { + qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); + success = argbContext->createContext(); + if (!success) + argbContext = rgbContext; // Might work, worth a shot at least. + } + } -bool QX11GLPixmapData::hasX11GLPixmaps() -{ - static bool checkedForX11Pixmaps = false; - static bool haveX11Pixmaps = false; + if (!argbContext->isValid()) + break; - if (checkedForX11Pixmaps) - return haveX11Pixmaps; + // Create the pixmap which will be used to create the egl surface for the share QGLContext + QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); + rgbPixmapData->resize(8, 8); + rgbPixmapData->fill(Qt::red); + sharePixmap = new QPixmap(rgbPixmapData); + EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig); + rgbPixmapData->gl_surface = (void*)sharePixmapSurface; + + // Create the actual QGLContext which will be used for sharing + sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat()); + sharedQGLContext->d_func()->eglContext = rgbContext; + sharedQGLContext->d_func()->eglSurface = sharePixmapSurface; + sharedQGLContext->d_func()->valid = true; + qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig); + + + valid = rgbContext->makeCurrent(sharePixmapSurface); + + // If the ARGB & RGB configs are different, check ARGB works too: + if (argbConfig != rgbConfig) { + QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); + argbPixmapData->resize(8, 8); + argbPixmapData->fill(Qt::transparent); // Force ARGB + QPixmap argbPixmap(argbPixmapData); // destroys pixmap data when goes out of scope + EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); + valid = argbContext->makeCurrent(argbPixmapSurface); + argbContext->doneCurrent(); + eglDestroySurface(QEgl::display(), argbPixmapSurface); + } - checkedForX11Pixmaps = true; + if (!valid) { + qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); + break; + } - EGLint rgbConfigId; - EGLint argbConfigId; + // The pixmap surface destruction hooks are installed by QGLTextureCache, so we + // must make sure this is instanciated: + QGLTextureCache::instance(); + } while(0); - do { - if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) - break; - EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); - EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, - QEgl::Renderable | QEgl::Translucent); + if (!valid) + cleanup(); + else + qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); - eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); - eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); + } - if (!rgbContext) { - rgbContext = qt_x11gl_rgbContext(); - rgbContext->setConfig(rgbConfig); - rgbContext->createContext(); + void cleanup() { + if (sharedQGLContext) { + delete sharedQGLContext; + sharedQGLContext = 0; } + if (argbContext && argbContext != rgbContext) + delete argbContext; + argbContext = 0; - if (!rgbContext->isValid()) - break; - - // If the configs are the same, use the same egl contexts: - if (rgbConfig == argbConfig) - argbContext = rgbContext; - - if (!argbContext) { - argbContext = qt_x11gl_argbContext(); - argbContext->setConfig(argbConfig); - bool success = argbContext->createContext(rgbContext); - if (!success) { - qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); - success = argbContext->createContext(); - if (!success) - argbContext = rgbContext; // Might work, worth a shot at least. - } + if (rgbContext) { + delete rgbContext; + rgbContext = 0; } - if (!argbContext->isValid()) - break; - - { - QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - argbPixmapData->resize(100, 100); - argbPixmapData->fill(Qt::transparent); // Force ARGB - QPixmap argbPixmap(argbPixmapData); - EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); - haveX11Pixmaps = argbContext->makeCurrent(argbPixmapSurface); - argbContext->doneCurrent(); - eglDestroySurface(QEgl::display(), argbPixmapSurface); + // Deleting the QPixmap will fire the pixmap destruction cleanup hooks which in turn + // will destroy the egl surface: + if (sharePixmap) { + delete sharePixmap; + sharePixmap = 0; } + } - if (!haveX11Pixmaps) { - qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); - break; - } + bool isValid() { return valid;} - // If the ARGB & RGB configs are different, check RGB too: - if (argbConfig != rgbConfig) { - QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - rgbPixmapData->resize(100, 100); - rgbPixmapData->fill(Qt::red); + // On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need + // different contexts: + QEglContext *rgbContext; + QEglContext *argbContext; - QPixmap rgbPixmap(rgbPixmapData); - EGLSurface rgbPixmapSurface = QEgl::createSurface(&rgbPixmap, rgbConfig); - haveX11Pixmaps = rgbContext->makeCurrent(rgbPixmapSurface); - rgbContext->doneCurrent(); - eglDestroySurface(QEgl::display(), rgbPixmapSurface); + // The share context wraps the rgbContext and is used as the master of the context share + // group. As all other contexts will have the same egl context (or a shared one if rgb != argb) + // all QGLContexts will actually be sharing and can be in the same context group. + QGLContext *sharedQGLContext; +private: + QPixmap *sharePixmap; + bool valid; +}; - if (!haveX11Pixmaps) { - qWarning() << "Unable to make pixmap config current:" << QEgl::errorString(); - break; - } - } +static void qt_cleanup_x11gl_share_contexts(); - // The pixmap surface destruction hooks are installed by QGLTextureCache, so we - // must make sure this is instanciated: - QGLTextureCache::instance(); - } while (0); +Q_GLOBAL_STATIC_WITH_INITIALIZER(QX11GLSharedContexts, qt_x11gl_share_contexts, + { + qAddPostRoutine(qt_cleanup_x11gl_share_contexts); + }) - if (!haveX11Pixmaps) { - if (argbContext && (argbContext != rgbContext)) { - delete argbContext; - argbContext = 0; - } - if (rgbContext) { - delete rgbContext; - rgbContext = 0; - } - } +static void qt_cleanup_x11gl_share_contexts() +{ + qt_x11gl_share_contexts()->cleanup(); +} - if (haveX11Pixmaps) - qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); - else - qDebug("QX11GLPixmapData is *NOT* being used"); + +QX11GLSharedContexts* QX11GLPixmapData::sharedContexts() +{ + return qt_x11gl_share_contexts(); +} + +bool QX11GLPixmapData::hasX11GLPixmaps() +{ + static bool checkedForX11Pixmaps = false; + static bool haveX11Pixmaps = false; + + if (checkedForX11Pixmaps) + return haveX11Pixmaps; + + checkedForX11Pixmaps = true; + + if (!qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty() && sharedContexts()->isValid()) + haveX11Pixmaps = true; return haveX11Pixmaps; } @@ -264,14 +311,14 @@ QPaintEngine* QX11GLPixmapData::paintEngine() const if (!ctx) { ctx = new QGLContext(glFormat()); Q_ASSERT(ctx->d_func()->eglContext == 0); - ctx->d_func()->eglContext = hasAlphaChannel() ? argbContext : rgbContext; + ctx->d_func()->eglContext = hasAlphaChannel() ? sharedContexts()->argbContext : sharedContexts()->rgbContext; // While we use a seperate QGLContext for each pixmap, the underlying QEglContext is // the same. So we must use a "fake" QGLContext and fool the texture cache into thinking // each pixmap's QGLContext is sharing with this central one. The only place this is // going to fail is where we the underlying EGL RGB and ARGB contexts aren't sharing. ctx->d_func()->sharing = true; - QGLContextGroup::addShare(ctx, qt_x11gl_fake_shared_context()); + QGLContextGroup::addShare(ctx, sharedContexts()->sharedQGLContext); // Update the glFormat for the QGLContext: qt_glformat_from_eglconfig(ctx->d_func()->glFormat, ctx->d_func()->eglContext->config()); diff --git a/src/opengl/qpixmapdata_x11gl_p.h b/src/opengl/qpixmapdata_x11gl_p.h index b613eba..2d1336b 100644 --- a/src/opengl/qpixmapdata_x11gl_p.h +++ b/src/opengl/qpixmapdata_x11gl_p.h @@ -65,6 +65,8 @@ QT_BEGIN_NAMESPACE +class QX11GLSharedContexts; + class QX11GLPixmapData : public QX11PixmapData, public QGLPaintDevice { public: @@ -84,11 +86,8 @@ public: static bool hasX11GLPixmaps(); static QGLFormat glFormat(); + static QX11GLSharedContexts* sharedContexts(); -#ifndef QT_NO_EGL - static QEglContext* rgbContext; - static QEglContext* argbContext; -#endif private: mutable QGLContext* ctx; }; |