src/opengl/qgl_x11egl.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qgl.h"
       
    43 #include <private/qt_x11_p.h>
       
    44 #include <private/qpixmap_x11_p.h>
       
    45 #include <private/qgl_p.h>
       
    46 #include <private/qpaintengine_opengl_p.h>
       
    47 #include "qgl_egl_p.h"
       
    48 #include "qcolormap.h"
       
    49 #include <QDebug>
       
    50 
       
    51 
       
    52 QT_BEGIN_NAMESPACE
       
    53 
       
    54 bool QGLFormat::hasOpenGLOverlays()
       
    55 {
       
    56     return false;
       
    57 }
       
    58 
       
    59 void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
       
    60 {
       
    61     if (device->devType() == QInternal::Image)
       
    62         props.setPixelFormat(static_cast<QImage *>(device)->format());
       
    63 }
       
    64 
       
    65 bool QGLContext::chooseContext(const QGLContext* shareContext)
       
    66 {
       
    67     Q_D(QGLContext);
       
    68 
       
    69     if (!device())
       
    70         return false;
       
    71 
       
    72     int devType = device()->devType();
       
    73 
       
    74     // Get the display and initialize it.
       
    75     d->eglContext = new QEglContext();
       
    76     d->eglContext->setApi(QEgl::OpenGL);
       
    77     if (!d->eglContext->openDisplay(device())) {
       
    78         delete d->eglContext;
       
    79         d->eglContext = 0;
       
    80         return false;
       
    81     }
       
    82 
       
    83     // Construct the configuration we need for this surface.
       
    84     QEglProperties configProps;
       
    85     qt_egl_set_format(configProps, devType, d->glFormat);
       
    86     qt_egl_add_platform_config(configProps, device());
       
    87     configProps.setRenderableType(QEgl::OpenGL);
       
    88 
       
    89     QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat;
       
    90     if (device()->depth() == 16) {
       
    91         configProps.setValue(EGL_RED_SIZE, 5);
       
    92         configProps.setValue(EGL_GREEN_SIZE, 6);
       
    93         configProps.setValue(EGL_BLUE_SIZE, 5);
       
    94         configProps.setValue(EGL_ALPHA_SIZE, 0);
       
    95         matchType = QEgl::ExactPixelFormat;
       
    96     }
       
    97     configProps.setRenderableType(QEgl::OpenGL);
       
    98 
       
    99     // Search for a matching configuration, reducing the complexity
       
   100     // each time until we get something that matches.
       
   101     if (!d->eglContext->chooseConfig(configProps, matchType)) {
       
   102         delete d->eglContext;
       
   103         d->eglContext = 0;
       
   104         return false;
       
   105     }
       
   106 
       
   107     // Inform the higher layers about the actual format properties.
       
   108     qt_egl_update_format(*(d->eglContext), d->glFormat);
       
   109 
       
   110     // Create a new context for the configuration.
       
   111     if (!d->eglContext->createContext
       
   112             (shareContext ? shareContext->d_func()->eglContext : 0)) {
       
   113         delete d->eglContext;
       
   114         d->eglContext = 0;
       
   115         return false;
       
   116     }
       
   117 
       
   118 #if defined(EGL_VERSION_1_1)
       
   119     if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
       
   120         eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
       
   121 #endif
       
   122 
       
   123     return true;
       
   124 }
       
   125 
       
   126 void QGLWidget::resizeEvent(QResizeEvent *)
       
   127 {
       
   128     Q_D(QGLWidget);
       
   129     if (!isValid())
       
   130         return;
       
   131     makeCurrent();
       
   132     if (!d->glcx->initialized())
       
   133         glInit();
       
   134     resizeGL(width(), height());
       
   135     //handle overlay
       
   136 }
       
   137 
       
   138 const QGLContext* QGLWidget::overlayContext() const
       
   139 {
       
   140     return 0;
       
   141 }
       
   142 
       
   143 void QGLWidget::makeOverlayCurrent()
       
   144 {
       
   145     //handle overlay
       
   146 }
       
   147 
       
   148 void QGLWidget::updateOverlayGL()
       
   149 {
       
   150     //handle overlay
       
   151 }
       
   152 
       
   153 bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual)
       
   154 {
       
   155     bool foundVisualIsArgb = useArgbVisual;
       
   156 
       
   157     memset(&vi, 0, sizeof(XVisualInfo));
       
   158 
       
   159     // Check to see if EGL is suggesting an appropriate visual id:
       
   160     EGLint nativeVisualId;
       
   161     eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId);
       
   162     vi.visualid = nativeVisualId;
       
   163 
       
   164     if (vi.visualid) {
       
   165         // EGL has suggested a visual id, so get the rest of the visual info for that id:
       
   166         XVisualInfo *chosenVisualInfo;
       
   167         int matchingCount = 0;
       
   168         chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount);
       
   169         if (chosenVisualInfo) {
       
   170 #if !defined(QT_NO_XRENDER)
       
   171             if (useArgbVisual) {
       
   172                 // Check to make sure the visual provided by EGL is ARGB
       
   173                 XRenderPictFormat *format;
       
   174                 format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual);
       
   175                 if (format->type == PictTypeDirect && format->direct.alphaMask) {
       
   176 //                    qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid);
       
   177                     foundVisualIsArgb = true;
       
   178                     vi = *chosenVisualInfo;
       
   179                 }
       
   180                 else {
       
   181                     qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB",
       
   182                              nativeVisualId, (int)config);
       
   183                     vi.visualid = 0;
       
   184                 }
       
   185             } else
       
   186 #endif
       
   187             {
       
   188 //                qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
       
   189                 vi = *chosenVisualInfo;
       
   190             }
       
   191             XFree(chosenVisualInfo);
       
   192         }
       
   193         else {
       
   194             qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
       
   195                      nativeVisualId, (int)config);
       
   196             vi.visualid = 0;
       
   197         }
       
   198     }
       
   199 
       
   200     // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
       
   201     // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
       
   202           
       
   203 #if !defined(QT_NO_XRENDER)
       
   204     if (vi.visualid == 0 && useArgbVisual) {
       
   205         // Try to use XRender to find an ARGB visual we can use
       
   206         vi.screen  = x11Info.screen();
       
   207         vi.depth   = 32; //### We might at some point (soon) get ARGB4444
       
   208         vi.c_class = TrueColor;
       
   209         XVisualInfo *matchingVisuals;
       
   210         int matchingCount = 0;
       
   211         matchingVisuals = XGetVisualInfo(x11Info.display(),
       
   212                                          VisualScreenMask|VisualDepthMask|VisualClassMask,
       
   213                                          &vi, &matchingCount);
       
   214 
       
   215         for (int i = 0; i < matchingCount; ++i) {
       
   216             XRenderPictFormat *format;
       
   217             format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual);
       
   218             if (format->type == PictTypeDirect && format->direct.alphaMask) {
       
   219                 vi = matchingVisuals[i];
       
   220                 foundVisualIsArgb = true;
       
   221 //                qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);
       
   222                 break;
       
   223             }
       
   224         }
       
   225         XFree(matchingVisuals);
       
   226     }
       
   227 #endif
       
   228 
       
   229     if (vi.visualid == 0) {
       
   230         EGLint depth;
       
   231         eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);
       
   232         int err;
       
   233         err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
       
   234         if (err == 0) {
       
   235             qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",
       
   236                      (int)config, depth);
       
   237             depth = x11Info.depth();
       
   238             err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
       
   239             if (err == 0) {
       
   240                 qWarning("Error: Couldn't get any matching X visual!");
       
   241                 return false;
       
   242             } else
       
   243                 qWarning("         - Falling back to X11 suggested depth (%d)", depth);
       
   244         }
       
   245 //        else
       
   246 //            qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);
       
   247 
       
   248         // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(
       
   249         if (useArgbVisual)
       
   250             foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444
       
   251     }
       
   252 
       
   253 //    qDebug("Visual Info:");
       
   254 //    qDebug("   bits_per_rgb=%d", vi.bits_per_rgb);
       
   255 //    qDebug("   red_mask=0x%x", vi.red_mask);
       
   256 //    qDebug("   green_mask=0x%x", vi.green_mask);
       
   257 //    qDebug("   blue_mask=0x%x", vi.blue_mask);
       
   258 //    qDebug("   colormap_size=%d", vi.colormap_size);
       
   259 //    qDebug("   c_class=%d", vi.c_class);
       
   260 //    qDebug("   depth=%d", vi.depth);
       
   261 //    qDebug("   screen=%d", vi.screen);
       
   262 //    qDebug("   visualid=%d", vi.visualid);
       
   263     return foundVisualIsArgb;
       
   264 }
       
   265 
       
   266 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
       
   267 {
       
   268     Q_D(QGLWidget);
       
   269     if (context == 0) {
       
   270         qWarning("QGLWidget::setContext: Cannot set null context");
       
   271         return;
       
   272     }
       
   273     if (!context->deviceIsPixmap() && context->device() != this) {
       
   274         qWarning("QGLWidget::setContext: Context must refer to this widget");
       
   275         return;
       
   276     }
       
   277 
       
   278     if (d->glcx)
       
   279         d->glcx->doneCurrent();
       
   280     QGLContext* oldcx = d->glcx;
       
   281     d->glcx = context;
       
   282 
       
   283     if (parentWidget()) {
       
   284         // force creation of delay-created widgets
       
   285         parentWidget()->winId();
       
   286         if (parentWidget()->x11Info().screen() != x11Info().screen())
       
   287             d_func()->xinfo = parentWidget()->d_func()->xinfo;
       
   288     }
       
   289 
       
   290     // If the application has set WA_TranslucentBackground and not explicitly set
       
   291     // the alpha buffer size to zero, modify the format so it have an alpha channel
       
   292     QGLFormat& fmt = d->glcx->d_func()->glFormat;
       
   293     const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground);
       
   294     if (tryArgbVisual && fmt.alphaBufferSize() == -1)
       
   295         fmt.setAlphaBufferSize(1);
       
   296 
       
   297     bool createFailed = false;
       
   298     if (!d->glcx->isValid()) {
       
   299         if (!d->glcx->create(shareContext ? shareContext : oldcx))
       
   300             createFailed = true;
       
   301     }
       
   302     if (createFailed) {
       
   303         if (deleteOldContext)
       
   304             delete oldcx;
       
   305         return;
       
   306     }
       
   307 
       
   308     if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
       
   309         if (deleteOldContext)
       
   310             delete oldcx;
       
   311         return;
       
   312     }
       
   313 
       
   314     bool visible = isVisible();
       
   315     if (visible)
       
   316         hide();
       
   317 
       
   318     XVisualInfo vi;
       
   319     QEglContext *eglContext = d->glcx->d_func()->eglContext;
       
   320     bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(),
       
   321                                                    x11Info(), tryArgbVisual);
       
   322 
       
   323     XSetWindowAttributes a;
       
   324 
       
   325     Window p = RootWindow(x11Info().display(), x11Info().screen());
       
   326     if (parentWidget())
       
   327         p = parentWidget()->winId();
       
   328 
       
   329     QColormap colmap = QColormap::instance(vi.screen);
       
   330     a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
       
   331     a.border_pixel = colmap.pixel(Qt::black);
       
   332 
       
   333     unsigned int valueMask = CWBackPixel|CWBorderPixel;
       
   334     if (usingArgbVisual) {
       
   335         a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone);
       
   336         valueMask |= CWColormap;
       
   337     }
       
   338 
       
   339     Window w = XCreateWindow(x11Info().display(), p, x(), y(), width(), height(),
       
   340                              0, vi.depth, InputOutput, vi.visual, valueMask, &a);
       
   341 
       
   342     if (deleteOldContext)
       
   343         delete oldcx;
       
   344     oldcx = 0;
       
   345 
       
   346     create(w); // Create with the ID of the window we've just created
       
   347 
       
   348 
       
   349     // Create the EGL surface to draw into.
       
   350     QGLContextPrivate *ctxpriv = d->glcx->d_func();
       
   351     ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(this);
       
   352     if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
       
   353         delete ctxpriv->eglContext;
       
   354         ctxpriv->eglContext = 0;
       
   355         return;
       
   356     }
       
   357 
       
   358     d->eglSurfaceWindowId = w; // Remember the window id we created the surface for
       
   359 
       
   360     if (visible)
       
   361         show();
       
   362 
       
   363     XFlush(X11->display);
       
   364     d->glcx->setWindowCreated(true);
       
   365 }
       
   366 
       
   367 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
       
   368 {
       
   369     Q_Q(QGLWidget);
       
   370 
       
   371     initContext(context, shareWidget);
       
   372 
       
   373     if(q->isValid() && glcx->format().hasOverlay()) {
       
   374         //no overlay
       
   375         qWarning("QtOpenGL ES doesn't currently support overlays");
       
   376     }
       
   377 }
       
   378 
       
   379 void QGLWidgetPrivate::cleanupColormaps()
       
   380 {
       
   381 }
       
   382 
       
   383 const QGLColormap & QGLWidget::colormap() const
       
   384 {
       
   385     return d_func()->cmap;
       
   386 }
       
   387 
       
   388 void QGLWidget::setColormap(const QGLColormap &)
       
   389 {
       
   390 }
       
   391 
       
   392 void QGLExtensions::init()
       
   393 {
       
   394     static bool init_done = false;
       
   395 
       
   396     if (init_done)
       
   397         return;
       
   398     init_done = true;
       
   399 
       
   400     // We need a context current to initialize the extensions.
       
   401     QGLWidget tmpWidget;
       
   402     tmpWidget.makeCurrent();
       
   403 
       
   404     init_extensions();
       
   405 
       
   406     tmpWidget.doneCurrent();
       
   407 }
       
   408 
       
   409 // Re-creates the EGL surface if the window ID has changed or if force is true
       
   410 void QGLWidgetPrivate::recreateEglSurface(bool force)
       
   411 {
       
   412     Q_Q(QGLWidget);
       
   413 
       
   414     Window currentId = q->winId();
       
   415 
       
   416     if ( force || (currentId != eglSurfaceWindowId) ) {
       
   417         // The window id has changed so we need to re-create the EGL surface
       
   418         QEglContext *ctx = glcx->d_func()->eglContext;
       
   419         EGLSurface surface = glcx->d_func()->eglSurface;
       
   420         if (surface != EGL_NO_SURFACE)
       
   421             ctx->destroySurface(surface); // Will force doneCurrent() if nec.
       
   422         surface = ctx->createSurface(q);
       
   423         if (surface == EGL_NO_SURFACE)
       
   424             qWarning("Error creating EGL window surface: 0x%x", eglGetError());
       
   425         glcx->d_func()->eglSurface = surface;
       
   426 
       
   427         eglSurfaceWindowId = currentId;
       
   428     }
       
   429 }
       
   430 
       
   431 // Selects which configs should be used
       
   432 EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly)
       
   433 {
       
   434     // Cache the configs we select as they wont change:
       
   435     static EGLConfig roPixmapRGBConfig = 0;
       
   436     static EGLConfig roPixmapRGBAConfig = 0;
       
   437     static EGLConfig rwPixmapRGBConfig = 0;
       
   438     static EGLConfig rwPixmapRGBAConfig = 0;
       
   439 
       
   440     EGLConfig* targetConfig;
       
   441 
       
   442     if (hasAlpha) {
       
   443         if (readOnly)
       
   444             targetConfig = &roPixmapRGBAConfig;
       
   445         else
       
   446             targetConfig = &rwPixmapRGBAConfig;
       
   447     }
       
   448     else {
       
   449         if (readOnly)
       
   450             targetConfig = &roPixmapRGBConfig;
       
   451         else
       
   452             targetConfig = &rwPixmapRGBConfig;
       
   453     }
       
   454 
       
   455     if (*targetConfig == 0) {
       
   456         QEglProperties configAttribs;
       
   457         configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT);
       
   458         configAttribs.setRenderableType(QEgl::OpenGL);
       
   459         if (hasAlpha)
       
   460             configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
       
   461         else
       
   462             configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
       
   463 
       
   464         // If this is going to be a render target, it needs to have a depth, stencil & sample buffer
       
   465         if (!readOnly) {
       
   466             configAttribs.setValue(EGL_DEPTH_SIZE, 1);
       
   467             configAttribs.setValue(EGL_STENCIL_SIZE, 1);
       
   468             configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1);
       
   469         }
       
   470 
       
   471         EGLint configCount = 0;
       
   472         do {
       
   473             eglChooseConfig(QEglContext::defaultDisplay(0), configAttribs.properties(), targetConfig, 1, &configCount);
       
   474             if (configCount > 0) {
       
   475                 // Got one
       
   476                 qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" )
       
   477                          << "config (" << int(*targetConfig) << ") to create a pixmap surface:";
       
   478 
       
   479 //                QEglProperties configProps(*targetConfig);
       
   480 //                qDebug() << configProps.toString();
       
   481                 break;
       
   482             }
       
   483             qWarning("choosePixmapConfig() - No suitible config found, reducing requirements");
       
   484         } while (configAttribs.reduceConfiguration());
       
   485     }
       
   486 
       
   487     if (*targetConfig == 0)
       
   488         qWarning("choosePixmapConfig() - Couldn't find a suitable config");
       
   489 
       
   490     return *targetConfig;
       
   491 }
       
   492 
       
   493 bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly)
       
   494 {
       
   495     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
       
   496     QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd);
       
   497 
       
   498     bool hasAlpha = pixmapData->hasAlphaChannel();
       
   499 
       
   500     EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly);
       
   501 
       
   502     QEglProperties pixmapAttribs;
       
   503 
       
   504     // If the pixmap can't be bound to a texture, it's pretty useless
       
   505     pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
       
   506     if (hasAlpha)
       
   507         pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
       
   508     else
       
   509         pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
       
   510 
       
   511     EGLSurface pixmapSurface;
       
   512     pixmapSurface = eglCreatePixmapSurface(QEglContext::defaultDisplay(0),
       
   513                                            pixmapConfig,
       
   514                                            (EGLNativePixmapType) pixmapData->handle(),
       
   515                                            pixmapAttribs.properties());
       
   516 //    qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x",
       
   517 //           pixmapSurface, pixmapData->handle());
       
   518     if (pixmapSurface == EGL_NO_SURFACE) {
       
   519         qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig
       
   520                    << ":" << QEglContext::errorString(eglGetError());
       
   521         return false;
       
   522     }
       
   523 
       
   524     static bool doneOnce = false;
       
   525     if (!doneOnce) {
       
   526         // Make sure QGLTextureCache is instanciated so it can install cleanup hooks
       
   527         // which cleanup the EGL surface.
       
   528         QGLTextureCache::instance();
       
   529         doneOnce = true;
       
   530     }
       
   531 
       
   532     Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
       
   533     pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
       
   534     pixmapData->is_cached = true; // Make sure the cleanup hook gets called
       
   535 
       
   536     return true;
       
   537 }
       
   538 
       
   539 
       
   540 QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key,
       
   541                                                            QGLContext::BindOptions options)
       
   542 {
       
   543     Q_Q(QGLContext);
       
   544 
       
   545     // The EGL texture_from_pixmap has no facility to invert the y coordinate
       
   546     if (!(options & QGLContext::CanFlipNativePixmapBindOption))
       
   547         return 0;
       
   548 
       
   549     Q_ASSERT(pd->classId() == QPixmapData::X11Class);
       
   550 
       
   551     static bool checkedForTFP = false;
       
   552     static bool haveTFP = false;
       
   553 
       
   554     if (!checkedForTFP) {
       
   555         // Check for texture_from_pixmap egl extension
       
   556         checkedForTFP = true;
       
   557         if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
       
   558             eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
       
   559         {
       
   560             qDebug("Found texture_from_pixmap EGL extension!");
       
   561             haveTFP = true;
       
   562         }
       
   563     }
       
   564 
       
   565     if (!haveTFP)
       
   566         return 0;
       
   567 
       
   568     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
       
   569 
       
   570     bool hasAlpha = pixmapData->hasAlphaChannel();
       
   571 
       
   572     // Check to see if the surface is still valid
       
   573     if (pixmapData->gl_surface &&
       
   574         hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
       
   575     {
       
   576         // Surface is invalid!
       
   577         destroyGlSurfaceForPixmap(pixmapData);
       
   578     }
       
   579 
       
   580     if (pixmapData->gl_surface == 0) {
       
   581         bool success = qt_createEGLSurfaceForPixmap(pixmapData, true);
       
   582         if (!success) {
       
   583             haveTFP = false;
       
   584             return 0;
       
   585         }
       
   586     }
       
   587 
       
   588     Q_ASSERT(pixmapData->gl_surface);
       
   589 
       
   590     GLuint textureId;
       
   591     glGenTextures(1, &textureId);
       
   592     glEnable(GL_TEXTURE_2D);
       
   593     glBindTexture(GL_TEXTURE_2D, textureId);
       
   594 
       
   595     // bind the egl pixmap surface to a texture
       
   596     EGLBoolean success;
       
   597     success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
       
   598     if (success == EGL_FALSE) {
       
   599         qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
       
   600         eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
       
   601         pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
       
   602         haveTFP = false;
       
   603         return 0;
       
   604     }
       
   605 
       
   606     QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
       
   607     pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
       
   608 
       
   609     // We assume the cost of bound pixmaps is zero
       
   610     QGLTextureCache::instance()->insert(q, key, texture, 0);
       
   611 
       
   612     glBindTexture(GL_TEXTURE_2D, textureId);
       
   613     return texture;
       
   614 }
       
   615 
       
   616 void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
       
   617 {
       
   618     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
       
   619     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
       
   620     if (pixmapData->gl_surface) {
       
   621         EGLBoolean success;
       
   622         success = eglDestroySurface(QEglContext::defaultDisplay(0), (EGLSurface)pixmapData->gl_surface);
       
   623         if (success == EGL_FALSE) {
       
   624             qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
       
   625                        << QEglContext::errorString(eglGetError());
       
   626         }
       
   627         pixmapData->gl_surface = 0;
       
   628     }
       
   629 }
       
   630 
       
   631 void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
       
   632 {
       
   633     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
       
   634     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
       
   635     if (pixmapData->gl_surface) {
       
   636         EGLBoolean success;
       
   637         success = eglReleaseTexImage(QEglContext::defaultDisplay(0),
       
   638                                      (EGLSurface)pixmapData->gl_surface,
       
   639                                      EGL_BACK_BUFFER);
       
   640         if (success == EGL_FALSE) {
       
   641             qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
       
   642                        << QEglContext::errorString(eglGetError());
       
   643         }
       
   644     }
       
   645 }
       
   646 
       
   647 QT_END_NAMESPACE