Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/opengl/qgl_x11egl.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4343#include <private/qt_x11_p.h>
    4444#include <private/qpixmap_x11_p.h>
    45 #include <private/qimagepixmapcleanuphooks_p.h>
    4645#include <private/qgl_p.h>
    4746#include <private/qpaintengine_opengl_p.h>
     
    4948#include "qcolormap.h"
    5049#include <QDebug>
     50#include <QPixmap>
    5151
    5252
    5353QT_BEGIN_NAMESPACE
    5454
    55 
    56 bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config,
    57                              const QX11Info &x11Info, bool useArgbVisual);
    5855
    5956/*
     
    8077    int screen = 0;
    8178
    82     d->display = eglGetDisplay(EGLNativeDisplayType(X11->display));
    83 
    84     if (!eglInitialize(d->display, NULL, NULL)) {
    85         qWarning("QGLTemporaryContext: Unable to initialize EGL display.");
    86         return;
    87     }
     79    d->display = QEgl::display();
    8880
    8981    EGLConfig config;
     
    10698    XVisualInfo *vi;
    10799    int numVisuals;
    108     EGLint id = 0;
    109 
    110     eglGetConfigAttrib(d->display, config, EGL_NATIVE_VISUAL_ID, &id);
    111     if (id == 0) {
    112         // EGL_NATIVE_VISUAL_ID is optional and might not be supported
    113         // on some implementations - we'll have to do it the hard way
    114         QX11Info xinfo;
    115         qt_egl_setup_x11_visual(visualInfo, d->display, config, xinfo, false);
    116     } else {
    117         visualInfo.visualid = id;
    118     }
     100
     101    visualInfo.visualid = QEgl::getCompatibleVisualId(config);
    119102    vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals);
    120103    if (!vi || numVisuals < 1) {
     
    171154}
    172155
    173 void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
    174 {
    175     if (device->devType() == QInternal::Image)
    176         props.setPixelFormat(static_cast<QImage *>(device)->format());
    177 }
    178 
    179156// Chooses the EGL config and creates the EGL context
    180157bool QGLContext::chooseContext(const QGLContext* shareContext)
     
    187164    int devType = device()->devType();
    188165
    189     // Get the display and initialize it.
     166    QX11PixmapData *x11PixmapData = 0;
     167    if (devType == QInternal::Pixmap) {
     168        QPixmapData *pmd = static_cast<QPixmap*>(device())->data_ptr().data();
     169        if (pmd->classId() == QPixmapData::X11Class)
     170            x11PixmapData = static_cast<QX11PixmapData*>(pmd);
     171        else {
     172            // TODO: Replace the pixmap's data with a new QX11PixmapData
     173            qWarning("WARNING: Creating a QGLContext on a QPixmap is only supported for X11 pixmap backend");
     174            return false;
     175        }
     176    } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
     177        qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType);
     178        return false;
     179    }
     180
     181    // Only create the eglContext if we don't already have one:
    190182    if (d->eglContext == 0) {
    191183        d->eglContext = new QEglContext();
     184        d->ownsEglContext = true;
    192185        d->eglContext->setApi(QEgl::OpenGL);
     186
     187        // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat
     188        // has the alpha channel option set:
     189        if (devType == QInternal::Widget) {
     190            QWidget* widget = static_cast<QWidget*>(device());
     191            if (widget->testAttribute(Qt::WA_TranslucentBackground))
     192                d->glFormat.setAlpha(true);
     193        }
    193194
    194195        // Construct the configuration we need for this surface.
    195196        QEglProperties configProps;
    196         qt_egl_set_format(configProps, devType, d->glFormat);
    197         qt_egl_add_platform_config(configProps, device());
     197        configProps.setDeviceType(devType);
    198198        configProps.setRenderableType(QEgl::OpenGL);
    199 
    200 #if We_have_an_EGL_library_which_bothers_to_check_EGL_BUFFER_SIZE
    201         if (device()->depth() == 16 && configProps.value(EGL_ALPHA_SIZE) <= 0) {
    202             qDebug("Setting EGL_BUFFER_SIZE to 16");
    203             configProps.setValue(EGL_BUFFER_SIZE, 16);
    204             configProps.setValue(EGL_ALPHA_SIZE, 0);
    205         }
     199        qt_eglproperties_set_glformat(configProps, d->glFormat);
     200
     201        // Set buffer preserved for regular QWidgets, QGLWidgets are ok with either preserved or destroyed:
     202        if ((devType == QInternal::Widget) && qobject_cast<QGLWidget*>(static_cast<QWidget*>(device())) == 0)
     203            configProps.setValue(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
    206204
    207205        if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
     
    210208            return false;
    211209        }
    212 #else
    213         QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat;
    214         if ((device()->depth() == 16) && configProps.value(EGL_ALPHA_SIZE) == 0) {
    215             configProps.setValue(EGL_RED_SIZE, 5);
    216             configProps.setValue(EGL_GREEN_SIZE, 6);
    217             configProps.setValue(EGL_BLUE_SIZE, 5);
    218             configProps.setValue(EGL_ALPHA_SIZE, 0);
    219             matchType = QEgl::ExactPixelFormat;
    220         }
    221 
    222         // Search for a matching configuration, reducing the complexity
    223         // each time until we get something that matches.
    224         if (!d->eglContext->chooseConfig(configProps, matchType)) {
     210
     211        // Create a new context for the configuration.
     212        QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0;
     213        if (!d->eglContext->createContext(eglSharedContext)) {
    225214            delete d->eglContext;
    226215            d->eglContext = 0;
    227216            return false;
    228217        }
    229 #endif
    230 
    231 //        qDebug("QGLContext::chooseContext() - using EGL config %d:", d->eglContext->config());
    232 //        qDebug() << QEglProperties(d->eglContext->config()).toString();
    233 
    234         // Create a new context for the configuration.
    235         if (!d->eglContext->createContext
    236                 (shareContext ? shareContext->d_func()->eglContext : 0)) {
    237             delete d->eglContext;
    238             d->eglContext = 0;
    239             return false;
    240         }
    241218        d->sharing = d->eglContext->isSharing();
    242219        if (d->sharing && shareContext)
    243220            const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
    244 
    245 #if defined(EGL_VERSION_1_1)
    246         if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
    247             eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
    248 #endif
    249     }
    250 
    251     // Inform the higher layers about the actual format properties.
    252     qt_egl_update_format(*(d->eglContext), d->glFormat);
     221    }
     222
     223    // Inform the higher layers about the actual format properties
     224    qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config());
     225
     226    // Do don't create the EGLSurface for everything.
     227    //    QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
     228    //    QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
     229    //    QPixmap - yes, create the EGLSurface but store it in QX11PixmapData::gl_surface
     230    //    QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf
     231
     232    if (devType == QInternal::Widget) {
     233        if (d->eglSurface != EGL_NO_SURFACE)
     234            eglDestroySurface(d->eglContext->display(), d->eglSurface);
     235        d->eglSurface = QEgl::createSurface(device(), d->eglContext->config());
     236        XFlush(X11->display);
     237        setWindowCreated(true);
     238    }
     239
     240    if (x11PixmapData) {
     241        // TODO: Actually check to see if the existing surface can be re-used
     242        if (x11PixmapData->gl_surface)
     243            eglDestroySurface(d->eglContext->display(), (EGLSurface)x11PixmapData->gl_surface);
     244
     245        x11PixmapData->gl_surface = (void*)QEgl::createSurface(device(), d->eglContext->config());
     246    }
    253247
    254248    return true;
     
    282276}
    283277
    284 //#define QT_DEBUG_X11_VISUAL_SELECTION 1
    285 
    286 bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual)
    287 {
    288     bool foundVisualIsArgb = useArgbVisual;
    289 
    290 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
    291     qDebug("qt_egl_setup_x11_visual() - useArgbVisual=%d", useArgbVisual);
    292 #endif
    293 
    294     memset(&vi, 0, sizeof(XVisualInfo));
    295 
    296     EGLint eglConfigColorSize;
    297     eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &eglConfigColorSize);
    298 
    299     // Check to see if EGL is suggesting an appropriate visual id:
    300     EGLint nativeVisualId;
    301     eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId);
    302     vi.visualid = nativeVisualId;
    303 
    304     if (vi.visualid) {
    305         // EGL has suggested a visual id, so get the rest of the visual info for that id:
    306         XVisualInfo *chosenVisualInfo;
    307         int matchingCount = 0;
    308         chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount);
    309         if (chosenVisualInfo) {
    310 #if !defined(QT_NO_XRENDER)
    311             if (useArgbVisual) {
    312                 // Check to make sure the visual provided by EGL is ARGB
    313                 XRenderPictFormat *format;
    314                 format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual);
    315                 if (format->type == PictTypeDirect && format->direct.alphaMask) {
    316 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
    317                     qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid);
    318 #endif
    319                     foundVisualIsArgb = true;
    320                     vi = *chosenVisualInfo;
    321                 }
    322                 else {
    323                     qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB",
    324                              nativeVisualId, (int)config);
    325                     vi.visualid = 0;
    326                 }
    327             } else
    328 #endif
    329             {
    330                 if (eglConfigColorSize == chosenVisualInfo->depth) {
    331 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
    332                     qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
    333 #endif
    334                     vi = *chosenVisualInfo;
    335                 } else
    336                     qWarning("Warning: EGL suggested using X visual ID %d (%d bpp) for config %d (%d bpp), but the depths do not match!",
    337                              nativeVisualId, chosenVisualInfo->depth, (int)config, eglConfigColorSize);
    338             }
    339             XFree(chosenVisualInfo);
    340         }
    341         else {
    342             qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
    343                      nativeVisualId, (int)config);
    344             vi.visualid = 0;
    345         }
    346     }
    347 
    348     // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
    349     // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
    350 
    351 #if !defined(QT_NO_XRENDER)
    352     if (vi.visualid == 0 && useArgbVisual) {
    353         // Try to use XRender to find an ARGB visual we can use
    354         vi.screen  = x11Info.screen();
    355         vi.depth   = 32; //### We might at some point (soon) get ARGB4444
    356         vi.c_class = TrueColor;
    357         XVisualInfo *matchingVisuals;
    358         int matchingCount = 0;
    359         matchingVisuals = XGetVisualInfo(x11Info.display(),
    360                                          VisualScreenMask|VisualDepthMask|VisualClassMask,
    361                                          &vi, &matchingCount);
    362 
    363         for (int i = 0; i < matchingCount; ++i) {
    364             XRenderPictFormat *format;
    365             format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual);
    366             if (format->type == PictTypeDirect && format->direct.alphaMask) {
    367                 vi = matchingVisuals[i];
    368                 foundVisualIsArgb = true;
    369 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
    370                 qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);
    371 #endif
    372                 break;
    373             }
    374         }
    375         XFree(matchingVisuals);
    376     }
    377 #endif
    378 
    379     if (vi.visualid == 0) {
    380         EGLint depth;
    381         eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);
    382         int err;
    383         err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
    384         if (err == 0) {
    385             qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",
    386                      (int)config, depth);
    387             depth = x11Info.depth();
    388             err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
    389             if (err == 0) {
    390                 qWarning("Error: Couldn't get any matching X visual!");
    391                 return false;
    392             } else
    393                 qWarning("         - Falling back to X11 suggested depth (%d)", depth);
    394         }
    395 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
    396         else
    397             qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);
    398 #endif
    399 
    400         // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(
    401         if (useArgbVisual)
    402             foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444
    403     }
    404 
    405 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
    406     qDebug("Visual Info:");
    407     qDebug("   bits_per_rgb=%d", vi.bits_per_rgb);
    408     qDebug("   red_mask=0x%x", vi.red_mask);
    409     qDebug("   green_mask=0x%x", vi.green_mask);
    410     qDebug("   blue_mask=0x%x", vi.blue_mask);
    411     qDebug("   colormap_size=%d", vi.colormap_size);
    412     qDebug("   c_class=%d", vi.c_class);
    413     qDebug("   depth=%d", vi.depth);
    414     qDebug("   screen=%d", vi.screen);
    415     qDebug("   visualid=%d", vi.visualid);
    416 #endif
    417     return foundVisualIsArgb;
    418 }
    419 
    420278void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
    421279{
     
    434292    QGLContext* oldcx = d->glcx;
    435293    d->glcx = context;
    436 
    437     if (parentWidget()) {
    438         // force creation of delay-created widgets
    439         parentWidget()->winId();
    440         if (parentWidget()->x11Info().screen() != x11Info().screen())
    441             d_func()->xinfo = parentWidget()->d_func()->xinfo;
    442     }
    443 
    444     // If the application has set WA_TranslucentBackground and not explicitly set
    445     // the alpha buffer size to zero, modify the format so it have an alpha channel
    446     QGLFormat& fmt = d->glcx->d_func()->glFormat;
    447     const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground) || fmt.alpha();
    448     if (tryArgbVisual && fmt.alphaBufferSize() == -1)
    449         fmt.setAlphaBufferSize(1);
    450294
    451295    bool createFailed = false;
     
    462306    }
    463307
    464     if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
    465         if (deleteOldContext)
    466             delete oldcx;
    467         return;
    468     }
    469 
    470     bool visible = isVisible();
    471     if (visible)
    472         hide();
    473 
    474     XVisualInfo vi;
    475     QEglContext *eglContext = d->glcx->d_func()->eglContext;
    476     bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(),
    477                                                    x11Info(), tryArgbVisual);
    478 
    479     XSetWindowAttributes a;
    480 
    481     Window p = RootWindow(x11Info().display(), x11Info().screen());
    482     if (parentWidget())
    483         p = parentWidget()->winId();
    484 
    485     QColormap colmap = QColormap::instance(vi.screen);
    486     a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
    487     a.border_pixel = colmap.pixel(Qt::black);
    488 
    489     unsigned int valueMask = CWBackPixel|CWBorderPixel;
    490     if (usingArgbVisual) {
    491         a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone);
    492         valueMask |= CWColormap;
    493     }
    494 
    495     Window w = XCreateWindow(x11Info().display(), p, x(), y(), width(), height(),
    496                              0, vi.depth, InputOutput, vi.visual, valueMask, &a);
    497 
    498     if (deleteOldContext)
    499         delete oldcx;
    500     oldcx = 0;
    501 
    502     create(w); // Create with the ID of the window we've just created
    503 
    504 
    505     // Create the EGL surface to draw into.
    506     QGLContextPrivate *ctxpriv = d->glcx->d_func();
    507     ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(this);
    508     if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
    509         delete ctxpriv->eglContext;
    510         ctxpriv->eglContext = 0;
    511         return;
    512     }
    513 
    514     d->eglSurfaceWindowId = w; // Remember the window id we created the surface for
    515 
    516     if (visible)
    517         show();
    518 
    519     XFlush(X11->display);
    520     d->glcx->setWindowCreated(true);
     308
     309    d->eglSurfaceWindowId = winId(); // Remember the window id we created the surface for
    521310}
    522311
     
    527316    initContext(context, shareWidget);
    528317
    529     if(q->isValid() && glcx->format().hasOverlay()) {
     318    if (q->isValid() && glcx->format().hasOverlay()) {
    530319        //no overlay
    531320        qWarning("QtOpenGL ES doesn't currently support overlays");
     
    546335}
    547336
    548 // Re-creates the EGL surface if the window ID has changed or if force is true
    549 void QGLWidgetPrivate::recreateEglSurface(bool force)
     337// Re-creates the EGL surface if the window ID has changed or if there isn't a surface
     338void QGLWidgetPrivate::recreateEglSurface()
    550339{
    551340    Q_Q(QGLWidget);
     
    553342    Window currentId = q->winId();
    554343
    555     if ( force || (currentId != eglSurfaceWindowId) ) {
    556         // The window id has changed so we need to re-create the EGL surface
    557         QEglContext *ctx = glcx->d_func()->eglContext;
    558         EGLSurface surface = glcx->d_func()->eglSurface;
    559         if (surface != EGL_NO_SURFACE)
    560             ctx->destroySurface(surface); // Will force doneCurrent() if nec.
    561         surface = ctx->createSurface(q);
    562         if (surface == EGL_NO_SURFACE)
    563             qWarning("Error creating EGL window surface: 0x%x", eglGetError());
    564         glcx->d_func()->eglSurface = surface;
    565 
     344    // If the window ID has changed since the surface was created, we need to delete the
     345    // old surface before re-creating a new one. Note: This should not be the case as the
     346    // surface should be deleted before the old window id.
     347    if (glcx->d_func()->eglSurface != EGL_NO_SURFACE && (currentId != eglSurfaceWindowId)) {
     348        qWarning("EGL surface for deleted window %x was not destroyed", uint(eglSurfaceWindowId));
     349        glcx->d_func()->destroyEglSurfaceForDevice();
     350    }
     351
     352    if (glcx->d_func()->eglSurface == EGL_NO_SURFACE) {
     353        glcx->d_func()->eglSurface = glcx->d_func()->eglContext->createSurface(q);
    566354        eglSurfaceWindowId = currentId;
    567355    }
    568356}
    569357
    570 // Selects which configs should be used
    571 EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly)
    572 {
    573     // Cache the configs we select as they wont change:
    574     static EGLConfig roPixmapRGBConfig = 0;
    575     static EGLConfig roPixmapRGBAConfig = 0;
    576     static EGLConfig rwPixmapRGBConfig = 0;
    577     static EGLConfig rwPixmapRGBAConfig = 0;
    578 
    579     EGLConfig* targetConfig;
    580 
    581     if (hasAlpha) {
    582         if (readOnly)
    583             targetConfig = &roPixmapRGBAConfig;
    584         else
    585             targetConfig = &rwPixmapRGBAConfig;
    586     }
    587     else {
    588         if (readOnly)
    589             targetConfig = &roPixmapRGBConfig;
    590         else
    591             targetConfig = &rwPixmapRGBConfig;
    592     }
    593 
    594     if (*targetConfig == 0) {
    595         QEglProperties configAttribs;
    596         configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT);
    597         configAttribs.setRenderableType(QEgl::OpenGL);
    598         if (hasAlpha)
    599             configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
    600         else
    601             configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
    602 
    603         // If this is going to be a render target, it needs to have a depth, stencil & sample buffer
    604         if (!readOnly) {
    605             configAttribs.setValue(EGL_DEPTH_SIZE, 1);
    606             configAttribs.setValue(EGL_STENCIL_SIZE, 1);
    607             configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1);
    608         }
    609 
    610         EGLint configCount = 0;
    611         do {
    612             eglChooseConfig(QEglContext::display(), configAttribs.properties(), targetConfig, 1, &configCount);
    613             if (configCount > 0) {
    614                 // Got one
    615                 qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" )
    616                          << "config (" << int(*targetConfig) << ") to create a pixmap surface:";
    617 
    618 //                QEglProperties configProps(*targetConfig);
    619 //                qDebug() << configProps.toString();
    620                 break;
    621             }
    622             qWarning("choosePixmapConfig() - No suitible config found, reducing requirements");
    623         } while (configAttribs.reduceConfiguration());
    624     }
    625 
    626     if (*targetConfig == 0)
    627         qWarning("choosePixmapConfig() - Couldn't find a suitable config");
    628 
    629     return *targetConfig;
    630 }
    631 
    632 bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly)
    633 {
    634     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
    635     QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd);
    636 
    637     bool hasAlpha = pixmapData->hasAlphaChannel();
    638 
    639     EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly);
    640 
    641     QEglProperties pixmapAttribs;
    642 
    643     // If the pixmap can't be bound to a texture, it's pretty useless
    644     pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
    645     if (hasAlpha)
    646         pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
    647     else
    648         pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
    649 
    650     EGLSurface pixmapSurface;
    651     pixmapSurface = eglCreatePixmapSurface(QEglContext::display(),
    652                                            pixmapConfig,
    653                                            (EGLNativePixmapType) pixmapData->handle(),
    654                                            pixmapAttribs.properties());
    655 //    qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x",
    656 //           pixmapSurface, pixmapData->handle());
    657     if (pixmapSurface == EGL_NO_SURFACE) {
    658         qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig
    659                    << ":" << QEglContext::errorString(eglGetError());
    660         return false;
    661     }
    662 
    663     static bool doneOnce = false;
    664     if (!doneOnce) {
    665         // Make sure QGLTextureCache is instanciated so it can install cleanup hooks
    666         // which cleanup the EGL surface.
    667         QGLTextureCache::instance();
    668         doneOnce = true;
    669     }
    670 
    671     Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
    672     pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
    673     QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData); // Make sure the cleanup hook gets called
    674 
    675     return true;
    676 }
    677 
    678 
    679 QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key,
     358
     359QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
    680360                                                           QGLContext::BindOptions options)
    681361{
     
    686366        return 0;
    687367
    688     Q_ASSERT(pd->classId() == QPixmapData::X11Class);
    689368
    690369    static bool checkedForTFP = false;
    691370    static bool haveTFP = false;
     371    static bool checkedForEglImageTFP = false;
     372    static bool haveEglImageTFP = false;
     373
     374
     375    if (!checkedForEglImageTFP) {
     376        checkedForEglImageTFP = true;
     377
     378        // We need to be able to create an EGLImage from a native pixmap, which was split
     379        // into a separate EGL extension, EGL_KHR_image_pixmap. It is possible to have
     380        // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must
     381        // check we have the EGLImage from pixmap functionality.
     382        if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) {
     383
     384            // Being able to create an EGLImage from a native pixmap is also pretty useless
     385            // without the ability to bind that EGLImage as a texture, which is provided by
     386            // the GL_OES_EGL_image extension, which we try to resolve here:
     387            haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q);
     388
     389            if (haveEglImageTFP)
     390                qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!");
     391        }
     392    }
    692393
    693394    if (!checkedForTFP) {
    694395        // Check for texture_from_pixmap egl extension
    695396        checkedForTFP = true;
    696         if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
    697             eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
     397        if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") ||
     398            QEgl::hasExtension("EGL_EXT_texture_from_pixmap"))
    698399        {
    699400            qDebug("Found texture_from_pixmap EGL extension!");
     
    702403    }
    703404
    704     if (!haveTFP)
     405    if (!haveTFP && !haveEglImageTFP)
    705406        return 0;
    706407
    707     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
    708 
     408
     409    QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
     410    Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
    709411    bool hasAlpha = pixmapData->hasAlphaChannel();
    710 
    711     // Check to see if the surface is still valid
    712     if (pixmapData->gl_surface &&
    713         hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
    714     {
    715         // Surface is invalid!
    716         destroyGlSurfaceForPixmap(pixmapData);
    717     }
    718 
    719     if (pixmapData->gl_surface == 0) {
    720         bool success = qt_createEGLSurfaceForPixmap(pixmapData, true);
    721         if (!success) {
    722             haveTFP = false;
    723             return 0;
    724         }
    725     }
    726 
    727     Q_ASSERT(pixmapData->gl_surface);
    728 
     412    bool pixmapHasValidSurface = false;
     413    bool textureIsBound = false;
    729414    GLuint textureId;
    730415    glGenTextures(1, &textureId);
    731416    glBindTexture(GL_TEXTURE_2D, textureId);
    732417
    733     // bind the egl pixmap surface to a texture
    734     EGLBoolean success;
    735     success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
    736     if (success == EGL_FALSE) {
    737         qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
    738         eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
    739         pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
    740         haveTFP = false;
    741         return 0;
    742     }
    743 
    744     QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
    745     pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
    746 
    747     // We assume the cost of bound pixmaps is zero
    748     QGLTextureCache::instance()->insert(q, key, texture, 0);
    749 
    750     glBindTexture(GL_TEXTURE_2D, textureId);
     418    if (haveTFP && pixmapData->gl_surface &&
     419        hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
     420    {
     421        pixmapHasValidSurface = true;
     422    }
     423
     424    // If we already have a valid EGL surface for the pixmap, we should use it
     425    if (pixmapHasValidSurface) {
     426        EGLBoolean success;
     427        success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
     428        if (success == EGL_FALSE) {
     429            qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
     430            eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
     431            pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
     432        } else
     433            textureIsBound = true;
     434    }
     435
     436    // If the pixmap doesn't already have a valid surface, try binding it via EGLImage
     437    // first, as going through EGLImage should be faster and better supported:
     438    if (!textureIsBound && haveEglImageTFP) {
     439        EGLImageKHR eglImage;
     440
     441        EGLint attribs[] = {
     442            EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
     443            EGL_NONE
     444        };
     445        eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
     446                                     (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs);
     447
     448        QGLContext* ctx = q;
     449        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);
     450
     451        GLint err = glGetError();
     452        if (err == GL_NO_ERROR)
     453            textureIsBound = true;
     454
     455        // Once the egl image is bound, the texture becomes a new sibling image and we can safely
     456        // destroy the EGLImage we created for the pixmap:
     457        if (eglImage != EGL_NO_IMAGE_KHR)
     458            QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
     459    }
     460
     461    if (!textureIsBound && haveTFP) {
     462        // Check to see if the surface is still valid
     463        if (pixmapData->gl_surface &&
     464            hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
     465        {
     466            // Surface is invalid!
     467            destroyGlSurfaceForPixmap(pixmapData);
     468        }
     469
     470        if (pixmapData->gl_surface == 0) {
     471            EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
     472                                                   QEgl::OpenGL,
     473                                                   hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
     474
     475            pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config);
     476            if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE)
     477                return false;
     478        }
     479
     480        EGLBoolean success;
     481        success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
     482        if (success == EGL_FALSE) {
     483            qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
     484            eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
     485            pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
     486            haveTFP = false; // If TFP isn't working, disable it's use
     487        } else
     488            textureIsBound = true;
     489    }
     490
     491    QGLTexture *texture = 0;
     492
     493    if (textureIsBound) {
     494        texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
     495        pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
     496
     497        // We assume the cost of bound pixmaps is zero
     498        QGLTextureCache::instance()->insert(q, key, texture, 0);
     499
     500        glBindTexture(GL_TEXTURE_2D, textureId);
     501    } else
     502        glDeleteTextures(1, &textureId);
     503
    751504    return texture;
    752505}
     506
    753507
    754508void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
     
    758512    if (pixmapData->gl_surface) {
    759513        EGLBoolean success;
    760         success = eglDestroySurface(QEglContext::display(), (EGLSurface)pixmapData->gl_surface);
     514        success = eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
    761515        if (success == EGL_FALSE) {
    762516            qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
    763                        << QEglContext::errorString(eglGetError());
     517                       << QEgl::errorString();
    764518        }
    765519        pixmapData->gl_surface = 0;
     
    773527    if (pixmapData->gl_surface) {
    774528        EGLBoolean success;
    775         success = eglReleaseTexImage(QEglContext::display(),
     529        success = eglReleaseTexImage(QEgl::display(),
    776530                                     (EGLSurface)pixmapData->gl_surface,
    777531                                     EGL_BACK_BUFFER);
    778532        if (success == EGL_FALSE) {
    779533            qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
    780                        << QEglContext::errorString(eglGetError());
     534                       << QEgl::errorString();
    781535        }
    782536    }
Note: See TracChangeset for help on using the changeset viewer.