src/opengl/qgl_x11egl.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include "qgl.h"
    42 #include "qgl.h"
    43 #include <private/qt_x11_p.h>
    43 #include <private/qt_x11_p.h>
    44 #include <private/qpixmap_x11_p.h>
    44 #include <private/qpixmap_x11_p.h>
    45 #include <private/qimagepixmapcleanuphooks_p.h>
       
    46 #include <private/qgl_p.h>
    45 #include <private/qgl_p.h>
    47 #include <private/qpaintengine_opengl_p.h>
    46 #include <private/qpaintengine_opengl_p.h>
    48 #include "qgl_egl_p.h"
    47 #include "qgl_egl_p.h"
    49 #include "qcolormap.h"
    48 #include "qcolormap.h"
    50 #include <QDebug>
    49 #include <QDebug>
       
    50 #include <QPixmap>
    51 
    51 
    52 
    52 
    53 QT_BEGIN_NAMESPACE
    53 QT_BEGIN_NAMESPACE
    54 
    54 
    55 
       
    56 bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config,
       
    57                              const QX11Info &x11Info, bool useArgbVisual);
       
    58 
    55 
    59 /*
    56 /*
    60     QGLTemporaryContext implementation
    57     QGLTemporaryContext implementation
    61 */
    58 */
    62 
    59 
    77     d->window = 0;
    74     d->window = 0;
    78     d->context = 0;
    75     d->context = 0;
    79     d->surface = 0;
    76     d->surface = 0;
    80     int screen = 0;
    77     int screen = 0;
    81 
    78 
    82     d->display = eglGetDisplay(EGLNativeDisplayType(X11->display));
    79     d->display = QEgl::display();
    83 
       
    84     if (!eglInitialize(d->display, NULL, NULL)) {
       
    85         qWarning("QGLTemporaryContext: Unable to initialize EGL display.");
       
    86         return;
       
    87     }
       
    88 
    80 
    89     EGLConfig config;
    81     EGLConfig config;
    90     int numConfigs = 0;
    82     int numConfigs = 0;
    91     EGLint attribs[] = {
    83     EGLint attribs[] = {
    92         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    84         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
   105     XVisualInfo visualInfo;
    97     XVisualInfo visualInfo;
   106     XVisualInfo *vi;
    98     XVisualInfo *vi;
   107     int numVisuals;
    99     int numVisuals;
   108     EGLint id = 0;
   100     EGLint id = 0;
   109 
   101 
   110     eglGetConfigAttrib(d->display, config, EGL_NATIVE_VISUAL_ID, &id);
   102     visualInfo.visualid = QEgl::getCompatibleVisualId(config);
   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     }
       
   119     vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals);
   103     vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals);
   120     if (!vi || numVisuals < 1) {
   104     if (!vi || numVisuals < 1) {
   121         qWarning("QGLTemporaryContext: Unable to get X11 visual info id.");
   105         qWarning("QGLTemporaryContext: Unable to get X11 visual info id.");
   122         return;
   106         return;
   123     }
   107     }
   168 bool QGLFormat::hasOpenGLOverlays()
   152 bool QGLFormat::hasOpenGLOverlays()
   169 {
   153 {
   170     return false;
   154     return false;
   171 }
   155 }
   172 
   156 
   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 
       
   179 // Chooses the EGL config and creates the EGL context
   157 // Chooses the EGL config and creates the EGL context
   180 bool QGLContext::chooseContext(const QGLContext* shareContext)
   158 bool QGLContext::chooseContext(const QGLContext* shareContext)
   181 {
   159 {
   182     Q_D(QGLContext);
   160     Q_D(QGLContext);
   183 
   161 
   184     if (!device())
   162     if (!device())
   185         return false;
   163         return false;
   186 
   164 
   187     int devType = device()->devType();
   165     int devType = device()->devType();
   188 
   166 
   189     // Get the display and initialize it.
   167     QX11PixmapData *x11PixmapData = 0;
       
   168     if (devType == QInternal::Pixmap) {
       
   169         QPixmapData *pmd = static_cast<QPixmap*>(device())->data_ptr().data();
       
   170         if (pmd->classId() == QPixmapData::X11Class)
       
   171             x11PixmapData = static_cast<QX11PixmapData*>(pmd);
       
   172         else {
       
   173             // TODO: Replace the pixmap's data with a new QX11PixmapData
       
   174             qWarning("WARNING: Creating a QGLContext on a QPixmap is only supported for X11 pixmap backend");
       
   175             return false;
       
   176         }
       
   177     } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
       
   178         qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType);
       
   179         return false;
       
   180     }
       
   181 
       
   182     // Only create the eglContext if we don't already have one:
   190     if (d->eglContext == 0) {
   183     if (d->eglContext == 0) {
   191         d->eglContext = new QEglContext();
   184         d->eglContext = new QEglContext();
       
   185         d->ownsEglContext = true;
   192         d->eglContext->setApi(QEgl::OpenGL);
   186         d->eglContext->setApi(QEgl::OpenGL);
       
   187 
       
   188         // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat
       
   189         // has the alpha channel option set:
       
   190         if (devType == QInternal::Widget) {
       
   191             QWidget* widget = static_cast<QWidget*>(device());
       
   192             if (widget->testAttribute(Qt::WA_TranslucentBackground))
       
   193                 d->glFormat.setAlpha(true);
       
   194         }
   193 
   195 
   194         // Construct the configuration we need for this surface.
   196         // Construct the configuration we need for this surface.
   195         QEglProperties configProps;
   197         QEglProperties configProps;
   196         qt_egl_set_format(configProps, devType, d->glFormat);
   198         configProps.setDeviceType(devType);
   197         qt_egl_add_platform_config(configProps, device());
       
   198         configProps.setRenderableType(QEgl::OpenGL);
   199         configProps.setRenderableType(QEgl::OpenGL);
   199 
   200         qt_eglproperties_set_glformat(configProps, d->glFormat);
   200 #if We_have_an_EGL_library_which_bothers_to_check_EGL_BUFFER_SIZE
   201 
   201         if (device()->depth() == 16 && configProps.value(EGL_ALPHA_SIZE) <= 0) {
   202         // Set buffer preserved for regular QWidgets, QGLWidgets are ok with either preserved or destroyed:
   202             qDebug("Setting EGL_BUFFER_SIZE to 16");
   203         if ((devType == QInternal::Widget) && qobject_cast<QGLWidget*>(static_cast<QWidget*>(device())) == 0)
   203             configProps.setValue(EGL_BUFFER_SIZE, 16);
   204             configProps.setValue(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
   204             configProps.setValue(EGL_ALPHA_SIZE, 0);
       
   205         }
       
   206 
   205 
   207         if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
   206         if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
   208             delete d->eglContext;
   207             delete d->eglContext;
   209             d->eglContext = 0;
   208             d->eglContext = 0;
   210             return false;
   209             return false;
   211         }
   210         }
   212 #else
   211 
   213         QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat;
   212         // Create a new context for the configuration.
   214         if ((device()->depth() == 16) && configProps.value(EGL_ALPHA_SIZE) == 0) {
   213         QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0;
   215             configProps.setValue(EGL_RED_SIZE, 5);
   214         if (!d->eglContext->createContext(eglSharedContext)) {
   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)) {
       
   225             delete d->eglContext;
   215             delete d->eglContext;
   226             d->eglContext = 0;
   216             d->eglContext = 0;
   227             return false;
   217             return false;
   228         }
   218         }
   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         }
       
   241         d->sharing = d->eglContext->isSharing();
   219         d->sharing = d->eglContext->isSharing();
   242         if (d->sharing && shareContext)
   220         if (d->sharing && shareContext)
   243             const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
   221             const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
   244 
   222     }
   245 #if defined(EGL_VERSION_1_1)
   223 
   246         if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
   224     // Inform the higher layers about the actual format properties
   247             eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
   225     qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config());
   248 #endif
   226 
   249     }
   227     // Do don't create the EGLSurface for everything.
   250 
   228     //    QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
   251     // Inform the higher layers about the actual format properties.
   229     //    QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
   252     qt_egl_update_format(*(d->eglContext), d->glFormat);
   230     //    QPixmap - yes, create the EGLSurface but store it in QX11PixmapData::gl_surface
       
   231     //    QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf
       
   232 
       
   233     if (devType == QInternal::Widget) {
       
   234         if (d->eglSurface != EGL_NO_SURFACE)
       
   235             eglDestroySurface(d->eglContext->display(), d->eglSurface);
       
   236         d->eglSurface = QEgl::createSurface(device(), d->eglContext->config());
       
   237         XFlush(X11->display);
       
   238         setWindowCreated(true);
       
   239     }
       
   240 
       
   241     if (x11PixmapData) {
       
   242         // TODO: Actually check to see if the existing surface can be re-used
       
   243         if (x11PixmapData->gl_surface)
       
   244             eglDestroySurface(d->eglContext->display(), (EGLSurface)x11PixmapData->gl_surface);
       
   245 
       
   246         x11PixmapData->gl_surface = (void*)QEgl::createSurface(device(), d->eglContext->config());
       
   247     }
   253 
   248 
   254     return true;
   249     return true;
   255 }
   250 }
   256 
   251 
   257 void QGLWidget::resizeEvent(QResizeEvent *)
   252 void QGLWidget::resizeEvent(QResizeEvent *)
   279 void QGLWidget::updateOverlayGL()
   274 void QGLWidget::updateOverlayGL()
   280 {
   275 {
   281     //handle overlay
   276     //handle overlay
   282 }
   277 }
   283 
   278 
   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 
       
   420 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
   279 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
   421 {
   280 {
   422     Q_D(QGLWidget);
   281     Q_D(QGLWidget);
   423     if (context == 0) {
   282     if (context == 0) {
   424         qWarning("QGLWidget::setContext: Cannot set null context");
   283         qWarning("QGLWidget::setContext: Cannot set null context");
   431 
   290 
   432     if (d->glcx)
   291     if (d->glcx)
   433         d->glcx->doneCurrent();
   292         d->glcx->doneCurrent();
   434     QGLContext* oldcx = d->glcx;
   293     QGLContext* oldcx = d->glcx;
   435     d->glcx = context;
   294     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);
       
   450 
   295 
   451     bool createFailed = false;
   296     bool createFailed = false;
   452     if (!d->glcx->isValid()) {
   297     if (!d->glcx->isValid()) {
   453         // Create the QGLContext here, which in turn chooses the EGL config
   298         // Create the QGLContext here, which in turn chooses the EGL config
   454         // and creates the EGL context:
   299         // and creates the EGL context:
   459         if (deleteOldContext)
   304         if (deleteOldContext)
   460             delete oldcx;
   305             delete oldcx;
   461         return;
   306         return;
   462     }
   307     }
   463 
   308 
   464     if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
   309 
   465         if (deleteOldContext)
   310     d->eglSurfaceWindowId = winId(); // Remember the window id we created the surface for
   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);
       
   521 }
   311 }
   522 
   312 
   523 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
   313 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
   524 {
   314 {
   525     Q_Q(QGLWidget);
   315     Q_Q(QGLWidget);
   526 
   316 
   527     initContext(context, shareWidget);
   317     initContext(context, shareWidget);
   528 
   318 
   529     if(q->isValid() && glcx->format().hasOverlay()) {
   319     if (q->isValid() && glcx->format().hasOverlay()) {
   530         //no overlay
   320         //no overlay
   531         qWarning("QtOpenGL ES doesn't currently support overlays");
   321         qWarning("QtOpenGL ES doesn't currently support overlays");
   532     }
   322     }
   533 }
   323 }
   534 
   324 
   543 
   333 
   544 void QGLWidget::setColormap(const QGLColormap &)
   334 void QGLWidget::setColormap(const QGLColormap &)
   545 {
   335 {
   546 }
   336 }
   547 
   337 
   548 // Re-creates the EGL surface if the window ID has changed or if force is true
   338 // Re-creates the EGL surface if the window ID has changed or if there isn't a surface
   549 void QGLWidgetPrivate::recreateEglSurface(bool force)
   339 void QGLWidgetPrivate::recreateEglSurface()
   550 {
   340 {
   551     Q_Q(QGLWidget);
   341     Q_Q(QGLWidget);
   552 
   342 
   553     Window currentId = q->winId();
   343     Window currentId = q->winId();
   554 
   344 
   555     if ( force || (currentId != eglSurfaceWindowId) ) {
   345     // If the window ID has changed since the surface was created, we need to delete the
   556         // The window id has changed so we need to re-create the EGL surface
   346     // old surface before re-creating a new one. Note: This should not be the case as the
   557         QEglContext *ctx = glcx->d_func()->eglContext;
   347     // surface should be deleted before the old window id.
   558         EGLSurface surface = glcx->d_func()->eglSurface;
   348     if (glcx->d_func()->eglSurface != EGL_NO_SURFACE && (currentId != eglSurfaceWindowId)) {
   559         if (surface != EGL_NO_SURFACE)
   349         qWarning("EGL surface for deleted window %x was not destroyed", eglSurfaceWindowId);
   560             ctx->destroySurface(surface); // Will force doneCurrent() if nec.
   350         glcx->d_func()->destroyEglSurfaceForDevice();
   561         surface = ctx->createSurface(q);
   351     }
   562         if (surface == EGL_NO_SURFACE)
   352 
   563             qWarning("Error creating EGL window surface: 0x%x", eglGetError());
   353     if (glcx->d_func()->eglSurface == EGL_NO_SURFACE) {
   564         glcx->d_func()->eglSurface = surface;
   354         glcx->d_func()->eglSurface = glcx->d_func()->eglContext->createSurface(q);
   565 
       
   566         eglSurfaceWindowId = currentId;
   355         eglSurfaceWindowId = currentId;
   567     }
   356     }
   568 }
   357 }
   569 
   358 
   570 // Selects which configs should be used
   359 
   571 EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly)
   360 QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
   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,
       
   680                                                            QGLContext::BindOptions options)
   361                                                            QGLContext::BindOptions options)
   681 {
   362 {
   682     Q_Q(QGLContext);
   363     Q_Q(QGLContext);
   683 
   364 
   684     // The EGL texture_from_pixmap has no facility to invert the y coordinate
   365     // The EGL texture_from_pixmap has no facility to invert the y coordinate
   685     if (!(options & QGLContext::CanFlipNativePixmapBindOption))
   366     if (!(options & QGLContext::CanFlipNativePixmapBindOption))
   686         return 0;
   367         return 0;
   687 
   368 
   688     Q_ASSERT(pd->classId() == QPixmapData::X11Class);
       
   689 
   369 
   690     static bool checkedForTFP = false;
   370     static bool checkedForTFP = false;
   691     static bool haveTFP = false;
   371     static bool haveTFP = false;
       
   372     static bool checkedForEglImageTFP = false;
       
   373     static bool haveEglImageTFP = false;
       
   374 
       
   375 
       
   376     if (!checkedForEglImageTFP) {
       
   377         checkedForEglImageTFP = true;
       
   378 
       
   379         // We need to be able to create an EGLImage from a native pixmap, which was split
       
   380         // into a seperate EGL extension, EGL_KHR_image_pixmap. It is possible to have
       
   381         // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must
       
   382         // check we have the EGLImage from pixmap functionality.
       
   383         if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) {
       
   384 
       
   385             // Being able to create an EGLImage from a native pixmap is also pretty useless
       
   386             // without the ability to bind that EGLImage as a texture, which is provided by
       
   387             // the GL_OES_EGL_image extension, which we try to resolve here:
       
   388             haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q);
       
   389 
       
   390             if (haveEglImageTFP)
       
   391                 qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!");
       
   392         }
       
   393     }
   692 
   394 
   693     if (!checkedForTFP) {
   395     if (!checkedForTFP) {
   694         // Check for texture_from_pixmap egl extension
   396         // Check for texture_from_pixmap egl extension
   695         checkedForTFP = true;
   397         checkedForTFP = true;
   696         if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
   398         if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") ||
   697             eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
   399             QEgl::hasExtension("EGL_EXT_texture_from_pixmap"))
   698         {
   400         {
   699             qDebug("Found texture_from_pixmap EGL extension!");
   401             qDebug("Found texture_from_pixmap EGL extension!");
   700             haveTFP = true;
   402             haveTFP = true;
   701         }
   403         }
   702     }
   404     }
   703 
   405 
   704     if (!haveTFP)
   406     if (!haveTFP && !haveEglImageTFP)
   705         return 0;
   407         return 0;
   706 
   408 
   707     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
   409 
   708 
   410     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
       
   411     Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
   709     bool hasAlpha = pixmapData->hasAlphaChannel();
   412     bool hasAlpha = pixmapData->hasAlphaChannel();
   710 
   413     bool pixmapHasValidSurface = false;
   711     // Check to see if the surface is still valid
   414     bool textureIsBound = false;
   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 
       
   729     GLuint textureId;
   415     GLuint textureId;
   730     glGenTextures(1, &textureId);
   416     glGenTextures(1, &textureId);
   731     glBindTexture(GL_TEXTURE_2D, textureId);
   417     glBindTexture(GL_TEXTURE_2D, textureId);
   732 
   418 
   733     // bind the egl pixmap surface to a texture
   419     if (haveTFP && pixmapData->gl_surface &&
   734     EGLBoolean success;
   420         hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
   735     success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
   421     {
   736     if (success == EGL_FALSE) {
   422         pixmapHasValidSurface = true;
   737         qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
   423     }
   738         eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
   424 
   739         pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
   425     // If we already have a valid EGL surface for the pixmap, we should use it
   740         haveTFP = false;
   426     if (pixmapHasValidSurface) {
   741         return 0;
   427         EGLBoolean success;
   742     }
   428         success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
   743 
   429         if (success == EGL_FALSE) {
   744     QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
   430             qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
   745     pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
   431             eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
   746 
   432             pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
   747     // We assume the cost of bound pixmaps is zero
   433         } else
   748     QGLTextureCache::instance()->insert(q, key, texture, 0);
   434             textureIsBound = true;
   749 
   435     }
   750     glBindTexture(GL_TEXTURE_2D, textureId);
   436 
       
   437     // If the pixmap doesn't already have a valid surface, try binding it via EGLImage
       
   438     // first, as going through EGLImage should be faster and better supported:
       
   439     if (!textureIsBound && haveEglImageTFP) {
       
   440         EGLImageKHR eglImage;
       
   441 
       
   442         EGLint attribs[] = {
       
   443             EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
       
   444             EGL_NONE
       
   445         };
       
   446         eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
       
   447                                      (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs);
       
   448 
       
   449         QGLContext* ctx = q;
       
   450         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);
       
   451 
       
   452         GLint err = glGetError();
       
   453         if (err == GL_NO_ERROR)
       
   454             textureIsBound = true;
       
   455 
       
   456         // Once the egl image is bound, the texture becomes a new sibling image and we can safely
       
   457         // destroy the EGLImage we created for the pixmap:
       
   458         if (eglImage != EGL_NO_IMAGE_KHR)
       
   459             QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
       
   460     }
       
   461 
       
   462     if (!textureIsBound && haveTFP) {
       
   463         // Check to see if the surface is still valid
       
   464         if (pixmapData->gl_surface &&
       
   465             hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
       
   466         {
       
   467             // Surface is invalid!
       
   468             destroyGlSurfaceForPixmap(pixmapData);
       
   469         }
       
   470 
       
   471         if (pixmapData->gl_surface == 0) {
       
   472             EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
       
   473                                                    QEgl::OpenGL,
       
   474                                                    hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
       
   475 
       
   476             pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config);
       
   477             if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE)
       
   478                 return false;
       
   479         }
       
   480 
       
   481         EGLBoolean success;
       
   482         success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
       
   483         if (success == EGL_FALSE) {
       
   484             qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
       
   485             eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
       
   486             pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
       
   487             haveTFP = false; // If TFP isn't working, disable it's use
       
   488         } else
       
   489             textureIsBound = true;
       
   490     }
       
   491 
       
   492     QGLTexture *texture = 0;
       
   493 
       
   494     if (textureIsBound) {
       
   495         texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
       
   496         pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
       
   497 
       
   498         // We assume the cost of bound pixmaps is zero
       
   499         QGLTextureCache::instance()->insert(q, key, texture, 0);
       
   500 
       
   501         glBindTexture(GL_TEXTURE_2D, textureId);
       
   502     } else
       
   503         glDeleteTextures(1, &textureId);
       
   504 
   751     return texture;
   505     return texture;
   752 }
   506 }
       
   507 
   753 
   508 
   754 void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
   509 void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
   755 {
   510 {
   756     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
   511     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
   757     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
   512     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
   758     if (pixmapData->gl_surface) {
   513     if (pixmapData->gl_surface) {
   759         EGLBoolean success;
   514         EGLBoolean success;
   760         success = eglDestroySurface(QEglContext::display(), (EGLSurface)pixmapData->gl_surface);
   515         success = eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
   761         if (success == EGL_FALSE) {
   516         if (success == EGL_FALSE) {
   762             qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
   517             qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
   763                        << QEglContext::errorString(eglGetError());
   518                        << QEgl::errorString();
   764         }
   519         }
   765         pixmapData->gl_surface = 0;
   520         pixmapData->gl_surface = 0;
   766     }
   521     }
   767 }
   522 }
   768 
   523 
   770 {
   525 {
   771     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
   526     Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
   772     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
   527     QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
   773     if (pixmapData->gl_surface) {
   528     if (pixmapData->gl_surface) {
   774         EGLBoolean success;
   529         EGLBoolean success;
   775         success = eglReleaseTexImage(QEglContext::display(),
   530         success = eglReleaseTexImage(QEgl::display(),
   776                                      (EGLSurface)pixmapData->gl_surface,
   531                                      (EGLSurface)pixmapData->gl_surface,
   777                                      EGL_BACK_BUFFER);
   532                                      EGL_BACK_BUFFER);
   778         if (success == EGL_FALSE) {
   533         if (success == EGL_FALSE) {
   779             qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
   534             qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
   780                        << QEglContext::errorString(eglGetError());
   535                        << QEgl::errorString();
   781         }
   536         }
   782     }
   537     }
   783 }
   538 }
   784 
   539 
   785 QT_END_NAMESPACE
   540 QT_END_NAMESPACE