diff -r b72c6db6890b -r 5dc02b23752f src/opengl/qpixmapdata_x11gl_egl.cpp --- a/src/opengl/qpixmapdata_x11gl_egl.cpp Wed Jun 23 19:07:03 2010 +0300 +++ b/src/opengl/qpixmapdata_x11gl_egl.cpp Tue Jul 06 15:10:48 2010 +0300 @@ -41,149 +41,194 @@ #include -#include -#include -#include +#include +#include +#include +#include -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) -#include +#if !defined(QT_OPENGL_ES_1) +#include #endif #ifndef QT_OPENGL_ES_2 -#include +#include #endif +#include +#include + #include "qpixmapdata_x11gl_p.h" QT_BEGIN_NAMESPACE -extern EGLConfig qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly); // in qgl_x11egl.cpp -extern bool qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly); // in qgl_x11egl.cpp + +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(); + + 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. + } + } + + if (!argbContext->isValid()) + break; + + // 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); -// On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need -// different contexts: -static EGLContext qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; -static EGLContext qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; + // 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); + argbPixmapData->gl_surface = 0; + } + + if (!valid) { + qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); + break; + } + + // The pixmap surface destruction hooks are installed by QGLTextureCache, so we + // must make sure this is instanciated: + QGLTextureCache::instance(); + } while(0); + + if (!valid) + cleanup(); + else + qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); + + } + + ~QX11GLSharedContexts() { + cleanup(); + } + + void cleanup() { + if (sharedQGLContext) { + delete sharedQGLContext; + sharedQGLContext = 0; + } + if (argbContext && argbContext != rgbContext) + delete argbContext; + argbContext = 0; + + if (rgbContext) { + delete rgbContext; + rgbContext = 0; + } + + // Deleting the QPixmap will fire the pixmap destruction cleanup hooks which in turn + // will destroy the egl surface: + if (sharePixmap) { + delete sharePixmap; + sharePixmap = 0; + } + } + + bool isValid() { return valid;} + + // On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need + // different contexts: + QEglContext *rgbContext; + QEglContext *argbContext; + + // 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; +}; + +static void qt_cleanup_x11gl_share_contexts(); + +Q_GLOBAL_STATIC_WITH_INITIALIZER(QX11GLSharedContexts, qt_x11gl_share_contexts, + { + qAddPostRoutine(qt_cleanup_x11gl_share_contexts); + }) + +static void qt_cleanup_x11gl_share_contexts() +{ + qt_x11gl_share_contexts()->cleanup(); +} + + +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; - - QX11PixmapData *argbPixmapData = 0; - QX11PixmapData *rgbPixmapData = 0; - do { - if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) - break; - - // Check we actually have EGL configs which support pixmaps - EGLConfig argbConfig = qt_chooseEGLConfigForPixmap(true, false); - EGLConfig rgbConfig = qt_chooseEGLConfigForPixmap(false, false); - - if (argbConfig == 0 || rgbConfig == 0) - break; - - // Create the shared contexts: - eglBindAPI(EGL_OPENGL_ES_API); - EGLint contextAttribs[] = { -#if defined(QT_OPENGL_ES_2) - EGL_CONTEXT_CLIENT_VERSION, 2, -#endif - EGL_NONE - }; - qPixmapARGBSharedEglContext = eglCreateContext(QEglContext::display(), - argbConfig, 0, contextAttribs); - - if (argbConfig == rgbConfig) { - // If the configs are the same, we can re-use the same context. - qPixmapRGBSharedEglContext = qPixmapARGBSharedEglContext; - } else { - qPixmapRGBSharedEglContext = eglCreateContext(QEglContext::display(), - rgbConfig, 0, contextAttribs); - } - - argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - argbPixmapData->resize(100, 100); - argbPixmapData->fill(Qt::transparent); // Force ARGB - - if (!qt_createEGLSurfaceForPixmap(argbPixmapData, false)) - break; - - haveX11Pixmaps = eglMakeCurrent(QEglContext::display(), - (EGLSurface)argbPixmapData->gl_surface, - (EGLSurface)argbPixmapData->gl_surface, - qPixmapARGBSharedEglContext); - if (!haveX11Pixmaps) { - EGLint err = eglGetError(); - qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); - break; - } + static bool checkedForX11GLPixmaps = false; + static bool haveX11GLPixmaps = false; - // If the ARGB & RGB configs are the same, we don't need to check RGB too - if (haveX11Pixmaps && (argbConfig != rgbConfig)) { - rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - rgbPixmapData->resize(100, 100); - rgbPixmapData->fill(Qt::red); - - // Try to actually create an EGL pixmap surface - if (!qt_createEGLSurfaceForPixmap(rgbPixmapData, false)) - break; - - haveX11Pixmaps = eglMakeCurrent(QEglContext::display(), - (EGLSurface)rgbPixmapData->gl_surface, - (EGLSurface)rgbPixmapData->gl_surface, - qPixmapRGBSharedEglContext); - if (!haveX11Pixmaps) { - EGLint err = eglGetError(); - qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); - break; - } - } - } while (0); - - if (qPixmapARGBSharedEglContext || qPixmapRGBSharedEglContext) { - eglMakeCurrent(QEglContext::display(), - EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } + if (checkedForX11GLPixmaps) + return haveX11GLPixmaps; - if (argbPixmapData) { - if (argbPixmapData->gl_surface) - QGLContextPrivate::destroyGlSurfaceForPixmap(argbPixmapData); - delete argbPixmapData; - argbPixmapData = 0; - } - if (rgbPixmapData) { - if (rgbPixmapData->gl_surface) - QGLContextPrivate::destroyGlSurfaceForPixmap(rgbPixmapData); - delete rgbPixmapData; - rgbPixmapData = 0; - } + haveX11GLPixmaps = qt_x11gl_share_contexts()->isValid(); + checkedForX11GLPixmaps = true; - if (!haveX11Pixmaps) { - // Clean up the context(s) if we can't use X11GL pixmaps - if (qPixmapARGBSharedEglContext != EGL_NO_CONTEXT) - eglDestroyContext(QEglContext::display(), qPixmapARGBSharedEglContext); - - if (qPixmapRGBSharedEglContext != qPixmapARGBSharedEglContext && - qPixmapRGBSharedEglContext != EGL_NO_CONTEXT) - { - eglDestroyContext(QEglContext::display(), qPixmapRGBSharedEglContext); - } - qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; - qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; - } - - if (haveX11Pixmaps) - qDebug("QX11GLPixmapData is supported"); - else - qDebug("QX11GLPixmapData is *NOT* being used"); - - return haveX11Pixmaps; + return haveX11GLPixmaps; } QX11GLPixmapData::QX11GLPixmapData() @@ -194,9 +239,65 @@ QX11GLPixmapData::~QX11GLPixmapData() { + if (ctx) + delete ctx; +} + + +void QX11GLPixmapData::fill(const QColor &color) +{ + if (ctx) { + ctx->makeCurrent(); + glFinish(); + eglWaitClient(); + } + + QX11PixmapData::fill(color); + XSync(X11->display, False); + + if (ctx) { + ctx->makeCurrent(); + eglWaitNative(EGL_CORE_NATIVE_ENGINE); + } } -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +void QX11GLPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + if (ctx) { + ctx->makeCurrent(); + glFinish(); + eglWaitClient(); + } + + QX11PixmapData::copy(data, rect); + XSync(X11->display, False); + + if (ctx) { + ctx->makeCurrent(); + eglWaitNative(EGL_CORE_NATIVE_ENGINE); + } +} + +bool QX11GLPixmapData::scroll(int dx, int dy, const QRect &rect) +{ + if (ctx) { + ctx->makeCurrent(); + glFinish(); + eglWaitClient(); + } + + bool success = QX11PixmapData::scroll(dx, dy, rect); + XSync(X11->display, False); + + if (ctx) { + ctx->makeCurrent(); + eglWaitNative(EGL_CORE_NATIVE_ENGINE); + } + + return success; +} + +#if !defined(QT_OPENGL_ES_1) Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_pixmap_2_engine) #endif @@ -210,16 +311,23 @@ // We need to create the context before beginPaint - do it here: if (!ctx) { ctx = new QGLContext(glFormat()); - if (ctx->d_func()->eglContext == 0) - ctx->d_func()->eglContext = new QEglContext(); - ctx->d_func()->eglContext->setApi(QEgl::OpenGL); - ctx->d_func()->eglContext->setContext(hasAlphaChannel() ? qPixmapARGBSharedEglContext - : qPixmapRGBSharedEglContext); + Q_ASSERT(ctx->d_func()->eglContext == 0); + 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, sharedContexts()->sharedQGLContext); + + // Update the glFormat for the QGLContext: + qt_glformat_from_eglconfig(ctx->d_func()->glFormat, ctx->d_func()->eglContext->config()); } QPaintEngine* engine; -#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) +#if defined(QT_OPENGL_ES_1) engine = qt_gl_pixmap_engine(); #elif defined(QT_OPENGL_ES_2) engine = qt_gl_pixmap_2_engine(); @@ -236,7 +344,7 @@ if (engine->isActive()) { qWarning("Pixmap paint engine already active"); -#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) +#if defined(QT_OPENGL_ES_1) engine = new QOpenGLPaintEngine; #elif defined(QT_OPENGL_ES_2) engine = new QGL2PaintEngineEx; @@ -257,20 +365,25 @@ void QX11GLPixmapData::beginPaint() { // qDebug("QX11GLPixmapData::beginPaint()"); + // TODO: Check to see if the surface is renderable if ((EGLSurface)gl_surface == EGL_NO_SURFACE) { - qt_createEGLSurfaceForPixmap(this, false); - ctx->d_func()->eglSurface = (EGLSurface)gl_surface; - ctx->d_func()->valid = true; // ;-) + QPixmap tmpPixmap(this); + EGLConfig cfg = ctx->d_func()->eglContext->config(); + Q_ASSERT(cfg != QEGL_NO_CONFIG); + +// qDebug("QX11GLPixmapData - using EGL Config ID %d", ctx->d_func()->eglContext->configAttrib(EGL_CONFIG_ID)); + EGLSurface surface = QEgl::createSurface(&tmpPixmap, cfg); + if (surface == EGL_NO_SURFACE) { + qWarning() << "Error creating EGL surface for pixmap:" << QEgl::errorString(); + return; + } + gl_surface = (void*)surface; + ctx->d_func()->eglSurface = surface; + ctx->d_func()->valid = true; } QGLPaintDevice::beginPaint(); } -void QX11GLPixmapData::endPaint() -{ - glFinish(); - QGLPaintDevice::endPaint(); -} - QGLContext* QX11GLPixmapData::context() const { return ctx;