src/gui/egl/qegl_x11.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    39 **
    39 **
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include <QtCore/qdebug.h>
    42 #include <QtCore/qdebug.h>
    43 
    43 
    44 #include <private/qt_x11_p.h>
    44 #include <QtGui/private/qt_x11_p.h>
    45 #include <QtGui/qx11info_x11.h>
    45 #include <QtGui/qx11info_x11.h>
    46 #include <private/qpixmapdata_p.h>
    46 #include <QtGui/private/qpixmapdata_p.h>
    47 #include <private/qpixmap_x11_p.h>
    47 #include <QtGui/private/qpixmap_x11_p.h>
       
    48 #include <QtGui/private/qimagepixmapcleanuphooks_p.h>
    48 
    49 
    49 #include <QtGui/qpaintdevice.h>
    50 #include <QtGui/qpaintdevice.h>
    50 #include <QtGui/qpixmap.h>
    51 #include <QtGui/qpixmap.h>
    51 #include <QtGui/qwidget.h>
    52 #include <QtGui/qwidget.h>
    52 #include "qegl_p.h"
    53 #include <QtGui/qcolormap.h>
    53 
    54 
       
    55 #include "QtGui/private/qegl_p.h"
       
    56 #include "QtGui/private/qeglcontext_p.h"
    54 
    57 
    55 QT_BEGIN_NAMESPACE
    58 QT_BEGIN_NAMESPACE
    56 
    59 
    57 EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties)
    60 
    58 {
    61 EGLNativeDisplayType QEgl::nativeDisplay()
    59     // Create the native drawable for the paint device.
       
    60     int devType = device->devType();
       
    61     EGLNativePixmapType pixmapDrawable = 0;
       
    62     EGLNativeWindowType windowDrawable = 0;
       
    63     bool ok;
       
    64     if (devType == QInternal::Pixmap) {
       
    65         pixmapDrawable = (EGLNativePixmapType)(static_cast<QPixmap *>(device))->handle();
       
    66         ok = (pixmapDrawable != 0);
       
    67     } else if (devType == QInternal::Widget) {
       
    68         windowDrawable = (EGLNativeWindowType)(static_cast<QWidget *>(device))->winId();
       
    69         ok = (windowDrawable != 0);
       
    70     } else {
       
    71         ok = false;
       
    72     }
       
    73     if (!ok) {
       
    74         qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable");
       
    75         return EGL_NO_SURFACE;
       
    76     }
       
    77 
       
    78     // Create the EGL surface to draw into, based on the native drawable.
       
    79     const int *props;
       
    80     if (properties)
       
    81         props = properties->properties();
       
    82     else
       
    83         props = 0;
       
    84     EGLSurface surf;
       
    85     if (devType == QInternal::Widget)
       
    86         surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props);
       
    87     else
       
    88         surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props);
       
    89     if (surf == EGL_NO_SURFACE) {
       
    90         qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:"
       
    91                    << errorString(eglGetError());
       
    92     }
       
    93     return surf;
       
    94 }
       
    95 
       
    96 EGLNativeDisplayType QEglContext::nativeDisplay()
       
    97 {
    62 {
    98     Display *xdpy = QX11Info::display();
    63     Display *xdpy = QX11Info::display();
    99     if (!xdpy) {
    64     if (!xdpy) {
   100         qWarning("QEglContext::getDisplay(): X11 display is not open");
    65         qWarning("QEglContext::getDisplay(): X11 display is not open");
   101         return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY);
    66         return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY);
   102     }
    67     }
   103     return EGLNativeDisplayType(xdpy);
    68     return EGLNativeDisplayType(xdpy);
       
    69 }
       
    70 
       
    71 EGLNativeWindowType QEgl::nativeWindow(QWidget* widget)
       
    72 {
       
    73     return (EGLNativeWindowType)(widget->winId());
       
    74 }
       
    75 
       
    76 EGLNativePixmapType QEgl::nativePixmap(QPixmap* pixmap)
       
    77 {
       
    78     return (EGLNativePixmapType)(pixmap->handle());
   104 }
    79 }
   105 
    80 
   106 static int countBits(unsigned long mask)
    81 static int countBits(unsigned long mask)
   107 {
    82 {
   108     int count = 0;
    83     int count = 0;
   151         setPixelFormat(static_cast<QImage *>(dev)->format());
   126         setPixelFormat(static_cast<QImage *>(dev)->format());
   152     else
   127     else
   153         setVisualFormat(qt_x11Info(dev));
   128         setVisualFormat(qt_x11Info(dev));
   154 }
   129 }
   155 
   130 
       
   131 //#define QT_DEBUG_X11_VISUAL_SELECTION 1
       
   132 
       
   133 VisualID QEgl::getCompatibleVisualId(EGLConfig config)
       
   134 {
       
   135     VisualID    visualId = 0;
       
   136     EGLint      eglValue = 0;
       
   137 
       
   138     EGLint configRedSize = 0;
       
   139     eglGetConfigAttrib(display(), config, EGL_RED_SIZE, &configRedSize);
       
   140 
       
   141     EGLint configGreenSize = 0;
       
   142     eglGetConfigAttrib(display(), config, EGL_GREEN_SIZE, &configGreenSize);
       
   143 
       
   144     EGLint configBlueSize = 0;
       
   145     eglGetConfigAttrib(display(), config, EGL_BLUE_SIZE, &configBlueSize);
       
   146 
       
   147     EGLint configAlphaSize = 0;
       
   148     eglGetConfigAttrib(display(), config, EGL_ALPHA_SIZE, &configAlphaSize);
       
   149 
       
   150     eglGetConfigAttrib(display(), config, EGL_CONFIG_ID, &eglValue);
       
   151     int configId = eglValue;
       
   152 
       
   153     // See if EGL provided a valid VisualID:
       
   154     eglGetConfigAttrib(display(), config, EGL_NATIVE_VISUAL_ID, &eglValue);
       
   155     visualId = (VisualID)eglValue;
       
   156     if (visualId) {
       
   157         // EGL has suggested a visual id, so get the rest of the visual info for that id:
       
   158         XVisualInfo visualInfoTemplate;
       
   159         memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
       
   160         visualInfoTemplate.visualid = visualId;
       
   161 
       
   162         XVisualInfo *chosenVisualInfo;
       
   163         int matchingCount = 0;
       
   164         chosenVisualInfo = XGetVisualInfo(X11->display, VisualIDMask, &visualInfoTemplate, &matchingCount);
       
   165         if (chosenVisualInfo) {
       
   166             // Skip size checks if implementation supports non-matching visual
       
   167             // and config (http://bugreports.qt.nokia.com/browse/QTBUG-9444).
       
   168             if (QEgl::hasExtension("EGL_NV_post_convert_replication"))
       
   169                 return visualId;
       
   170 
       
   171             int visualRedSize = countBits(chosenVisualInfo->red_mask);
       
   172             int visualGreenSize = countBits(chosenVisualInfo->green_mask);
       
   173             int visualBlueSize = countBits(chosenVisualInfo->blue_mask);
       
   174             int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size
       
   175 
       
   176 #if !defined(QT_NO_XRENDER)
       
   177             if (X11->use_xrender) {
       
   178                 // If we have XRender, actually check the visual supplied by EGL is ARGB
       
   179                 XRenderPictFormat *format;
       
   180                 format = XRenderFindVisualFormat(X11->display, chosenVisualInfo->visual);
       
   181                 if (format && (format->type == PictTypeDirect))
       
   182                     visualAlphaSize = countBits(format->direct.alphaMask);
       
   183             }
       
   184 #endif
       
   185 
       
   186             bool visualMatchesConfig = false;
       
   187             if ( visualRedSize == configRedSize &&
       
   188                  visualGreenSize == configGreenSize &&
       
   189                  visualBlueSize == configBlueSize )
       
   190             {
       
   191                 // We need XRender to check the alpha channel size of the visual. If we don't have
       
   192                 // the alpha size, we don't check it against the EGL config's alpha size.
       
   193                 if (visualAlphaSize >= 0)
       
   194                     visualMatchesConfig = visualAlphaSize == configAlphaSize;
       
   195                 else
       
   196                     visualMatchesConfig = true;
       
   197             }
       
   198 
       
   199             if (!visualMatchesConfig) {
       
   200                 if (visualAlphaSize >= 0) {
       
   201                     qWarning("Warning: EGL suggested using X Visual ID %d (ARGB%d%d%d%d) for EGL config %d (ARGB%d%d%d%d), but this is incompatable",
       
   202                              (int)visualId, visualAlphaSize, visualRedSize, visualGreenSize, visualBlueSize,
       
   203                              configId, configAlphaSize, configRedSize, configGreenSize, configBlueSize);
       
   204                 } else {
       
   205                     qWarning("Warning: EGL suggested using X Visual ID %d (RGB%d%d%d) for EGL config %d (RGB%d%d%d), but this is incompatable",
       
   206                              (int)visualId, visualRedSize, visualGreenSize, visualBlueSize,
       
   207                              configId, configRedSize, configGreenSize, configBlueSize);
       
   208                 }
       
   209                 visualId = 0;
       
   210             }
       
   211         } else {
       
   212             qWarning("Warning: EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID",
       
   213                      (int)visualId, configId);
       
   214             visualId = 0;
       
   215         }
       
   216         XFree(chosenVisualInfo);
       
   217     }
       
   218 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
       
   219     else
       
   220         qDebug("EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId);
       
   221 #endif
       
   222 
       
   223     if (visualId) {
       
   224 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
       
   225         if (configAlphaSize > 0)
       
   226             qDebug("Using ARGB Visual ID %d provided by EGL for config %d", (int)visualId, configId);
       
   227         else
       
   228             qDebug("Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId);
       
   229 #endif
       
   230         return visualId;
       
   231     }
       
   232 
       
   233 
       
   234     // If EGL didn't give us a valid visual ID, try XRender
       
   235 #if !defined(QT_NO_XRENDER)
       
   236     if (!visualId && X11->use_xrender) {
       
   237         XVisualInfo visualInfoTemplate;
       
   238         memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
       
   239 
       
   240         visualInfoTemplate.c_class = TrueColor;
       
   241 
       
   242         XVisualInfo *matchingVisuals;
       
   243         int matchingCount = 0;
       
   244         matchingVisuals = XGetVisualInfo(X11->display,
       
   245                                          VisualClassMask,
       
   246                                          &visualInfoTemplate,
       
   247                                          &matchingCount);
       
   248 
       
   249         for (int i = 0; i < matchingCount; ++i) {
       
   250             XRenderPictFormat *format;
       
   251             format = XRenderFindVisualFormat(X11->display, matchingVisuals[i].visual);
       
   252 
       
   253             // Check the format for the visual matches the EGL config
       
   254             if ( (countBits(format->direct.redMask) == configRedSize) &&
       
   255                  (countBits(format->direct.greenMask) == configGreenSize) &&
       
   256                  (countBits(format->direct.blueMask) == configBlueSize) &&
       
   257                  (countBits(format->direct.alphaMask) == configAlphaSize) )
       
   258             {
       
   259                 visualId = matchingVisuals[i].visualid;
       
   260                 break;
       
   261             }
       
   262         }
       
   263         if (matchingVisuals)
       
   264             XFree(matchingVisuals);
       
   265 
       
   266     }
       
   267     if (visualId) {
       
   268 # ifdef QT_DEBUG_X11_VISUAL_SELECTION
       
   269         if (configAlphaSize > 0)
       
   270             qDebug("Using ARGB Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId);
       
   271         else
       
   272             qDebug("Using Opaque Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId);
       
   273 # endif // QT_DEBUG_X11_VISUAL_SELECTION
       
   274         return visualId;
       
   275     }
       
   276 # ifdef QT_DEBUG_X11_VISUAL_SELECTION
       
   277     else
       
   278         qDebug("Failed to find an XVisual which matches EGL config %d using XRender", configId);
       
   279 # endif // QT_DEBUG_X11_VISUAL_SELECTION
       
   280 
       
   281 #endif //!defined(QT_NO_XRENDER)
       
   282 
       
   283 
       
   284     // Finally, if XRender also failed to find a visual (or isn't present), try to
       
   285     // use XGetVisualInfo and only use the bit depths to match on:
       
   286     if (!visualId) {
       
   287         XVisualInfo visualInfoTemplate;
       
   288         memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
       
   289         XVisualInfo *matchingVisuals;
       
   290         int matchingCount = 0;
       
   291 
       
   292         visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize;
       
   293         matchingVisuals = XGetVisualInfo(X11->display,
       
   294                                          VisualDepthMask,
       
   295                                          &visualInfoTemplate,
       
   296                                          &matchingCount);
       
   297         if (!matchingVisuals) {
       
   298             // Try again without taking the alpha channel into account:
       
   299             visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize;
       
   300             matchingVisuals = XGetVisualInfo(X11->display,
       
   301                                              VisualDepthMask,
       
   302                                              &visualInfoTemplate,
       
   303                                              &matchingCount);
       
   304         }
       
   305 
       
   306         if (matchingVisuals) {
       
   307             visualId = matchingVisuals[0].visualid;
       
   308             XFree(matchingVisuals);
       
   309         }
       
   310     }
       
   311 
       
   312     if (visualId) {
       
   313 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
       
   314         qDebug("Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId);
       
   315 #endif
       
   316         return visualId;
       
   317     }
       
   318 
       
   319     qWarning("Unable to find an X11 visual which matches EGL config %d", configId);
       
   320     return (VisualID)0;
       
   321 }
       
   322 
       
   323 void qt_set_winid_on_widget(QWidget* w, Qt::HANDLE id)
       
   324 {
       
   325     w->create(id);
       
   326 }
       
   327 
       
   328 
       
   329 // NOTE: The X11 version of createSurface will re-create the native drawable if it's visual doesn't
       
   330 // match the one for the passed in EGLConfig
       
   331 EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *unusedProperties)
       
   332 {
       
   333     Q_UNUSED(unusedProperties);
       
   334 
       
   335     int devType = device->devType();
       
   336 
       
   337     if (devType == QInternal::Pbuffer) {
       
   338         // TODO
       
   339         return EGL_NO_SURFACE;
       
   340     }
       
   341 
       
   342     QX11PixmapData *x11PixmapData = 0;
       
   343     if (devType == QInternal::Pixmap) {
       
   344         QPixmapData *pmd = static_cast<QPixmap*>(device)->data_ptr().data();
       
   345         if (pmd->classId() == QPixmapData::X11Class)
       
   346             x11PixmapData = static_cast<QX11PixmapData*>(pmd);
       
   347         else {
       
   348             // TODO: Replace the pixmap's data with a new QX11PixmapData
       
   349             qWarning("WARNING: Creating an EGL surface on a QPixmap is only supported for QX11PixmapData");
       
   350             return EGL_NO_SURFACE;
       
   351         }
       
   352     } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
       
   353         qWarning("WARNING: Creating an EGLSurface for device type %d isn't supported", devType);
       
   354         return EGL_NO_SURFACE;
       
   355     }
       
   356 
       
   357     VisualID visualId = QEgl::getCompatibleVisualId(config);
       
   358     EGLint alphaSize;
       
   359     eglGetConfigAttrib(QEgl::display(), config, EGL_ALPHA_SIZE, &alphaSize);
       
   360 
       
   361     if (devType == QInternal::Widget) {
       
   362         QWidget *widget = static_cast<QWidget*>(device);
       
   363 
       
   364         VisualID currentVisualId = 0;
       
   365         if (widget->testAttribute(Qt::WA_WState_Created))
       
   366             currentVisualId = XVisualIDFromVisual((Visual*)widget->x11Info().visual());
       
   367 
       
   368         if (currentVisualId != visualId) {
       
   369             // The window is either not created or has the wrong visual. Either way, we need
       
   370             // to create a window with the correct visual and call create() on the widget:
       
   371 
       
   372             bool visible = widget->isVisible();
       
   373             if (visible)
       
   374                 widget->hide();
       
   375 
       
   376             XVisualInfo visualInfo;
       
   377             visualInfo.visualid = visualId;
       
   378             {
       
   379                 XVisualInfo *visualInfoPtr;
       
   380                 int matchingCount = 0;
       
   381                 visualInfoPtr = XGetVisualInfo(widget->x11Info().display(), VisualIDMask,
       
   382                                                &visualInfo, &matchingCount);
       
   383                 Q_ASSERT(visualInfoPtr); // visualId really should be valid!
       
   384                 visualInfo = *visualInfoPtr;
       
   385                 XFree(visualInfoPtr);
       
   386             }
       
   387 
       
   388             Window parentWindow = RootWindow(widget->x11Info().display(), widget->x11Info().screen());
       
   389             if (widget->parentWidget())
       
   390                 parentWindow = widget->parentWidget()->winId();
       
   391 
       
   392             XSetWindowAttributes windowAttribs;
       
   393             QColormap colmap = QColormap::instance(widget->x11Info().screen());
       
   394             windowAttribs.background_pixel = colmap.pixel(widget->palette().color(widget->backgroundRole()));
       
   395             windowAttribs.border_pixel = colmap.pixel(Qt::black);
       
   396 
       
   397             unsigned int valueMask = CWBackPixel|CWBorderPixel;
       
   398             if (alphaSize > 0) {
       
   399                 windowAttribs.colormap = XCreateColormap(widget->x11Info().display(), parentWindow,
       
   400                                                          visualInfo.visual, AllocNone);
       
   401                 valueMask |= CWColormap;
       
   402             }
       
   403 
       
   404             Window window = XCreateWindow(widget->x11Info().display(), parentWindow,
       
   405                                           widget->x(), widget->y(), widget->width(), widget->height(),
       
   406                                           0, visualInfo.depth, InputOutput, visualInfo.visual,
       
   407                                           valueMask, &windowAttribs);
       
   408 
       
   409             // This is a nasty hack to get round the fact that we can't be a friend of QWidget:
       
   410             qt_set_winid_on_widget(widget, window);
       
   411 
       
   412             if (visible)
       
   413                 widget->show();
       
   414         }
       
   415 
       
   416         // At this point, the widget's window should be created and have the correct visual. Now we
       
   417         // just need to create the EGL surface for it:
       
   418         return eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), 0);
       
   419     }
       
   420 
       
   421     if (x11PixmapData) {
       
   422         // X11 Pixmaps are only created with a depth, so that's all we need to check
       
   423         EGLint configDepth;
       
   424         eglGetConfigAttrib(QEgl::display(), config, EGL_BUFFER_SIZE , &configDepth);
       
   425         if (x11PixmapData->depth() != configDepth) {
       
   426             // The bit depths are wrong which means the EGLConfig isn't compatable with
       
   427             // this pixmap. So we need to replace the pixmap's existing data with a new
       
   428             // one which is created with the correct depth:
       
   429 
       
   430 #ifndef QT_NO_XRENDER
       
   431             if (configDepth == 32) {
       
   432                 qWarning("Warning: EGLConfig's depth (32) != pixmap's depth (%d), converting to ARGB32",
       
   433                          x11PixmapData->depth());
       
   434                 x11PixmapData->convertToARGB32(true);
       
   435             } else
       
   436 #endif
       
   437             {
       
   438                 qWarning("Warning: EGLConfig's depth (%d) != pixmap's depth (%d)",
       
   439                          configDepth, x11PixmapData->depth());
       
   440             }
       
   441         }
       
   442 
       
   443         QEglProperties surfaceAttribs;
       
   444 
       
   445         // If the pixmap can't be bound to a texture, it's pretty useless
       
   446         surfaceAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
       
   447         if (alphaSize > 0)
       
   448             surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
       
   449         else
       
   450             surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
       
   451 
       
   452         EGLSurface surf = eglCreatePixmapSurface(QEgl::display(), config,
       
   453                                                  (EGLNativePixmapType) x11PixmapData->handle(),
       
   454                                                  surfaceAttribs.properties());
       
   455         x11PixmapData->gl_surface = (void*)surf;
       
   456         QImagePixmapCleanupHooks::enableCleanupHooks(x11PixmapData);
       
   457         return surf;
       
   458     }
       
   459 
       
   460     return EGL_NO_SURFACE;
       
   461 }
       
   462 
   156 QT_END_NAMESPACE
   463 QT_END_NAMESPACE