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

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

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/egl/qegl_x11.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4242#include <QtCore/qdebug.h>
    4343
    44 #include <private/qt_x11_p.h>
     44#include <QtGui/private/qt_x11_p.h>
    4545#include <QtGui/qx11info_x11.h>
    46 #include <private/qpixmapdata_p.h>
    47 #include <private/qpixmap_x11_p.h>
     46#include <QtGui/private/qpixmapdata_p.h>
     47#include <QtGui/private/qpixmap_x11_p.h>
     48#include <QtGui/private/qimagepixmapcleanuphooks_p.h>
    4849
    4950#include <QtGui/qpaintdevice.h>
    5051#include <QtGui/qpixmap.h>
    5152#include <QtGui/qwidget.h>
    52 #include "qegl_p.h"
    53 
     53#include <QtGui/qcolormap.h>
     54
     55#include "QtGui/private/qegl_p.h"
     56#include "QtGui/private/qeglcontext_p.h"
    5457
    5558QT_BEGIN_NAMESPACE
    5659
    57 EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties)
    58 {
    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()
     60
     61EGLNativeDisplayType QEgl::nativeDisplay()
    9762{
    9863    Display *xdpy = QX11Info::display();
     
    10267    }
    10368    return EGLNativeDisplayType(xdpy);
     69}
     70
     71EGLNativeWindowType QEgl::nativeWindow(QWidget* widget)
     72{
     73    return (EGLNativeWindowType)(widget->winId());
     74}
     75
     76EGLNativePixmapType QEgl::nativePixmap(QPixmap* pixmap)
     77{
     78    return (EGLNativePixmapType)(pixmap->handle());
    10479}
    10580
     
    154129}
    155130
     131//#define QT_DEBUG_X11_VISUAL_SELECTION 1
     132
     133VisualID 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_rounding")) {
     169                XFree(chosenVisualInfo);
     170                return visualId;
     171            }
     172
     173            int visualRedSize = countBits(chosenVisualInfo->red_mask);
     174            int visualGreenSize = countBits(chosenVisualInfo->green_mask);
     175            int visualBlueSize = countBits(chosenVisualInfo->blue_mask);
     176            int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size
     177
     178#if !defined(QT_NO_XRENDER)
     179            if (X11->use_xrender) {
     180                // If we have XRender, actually check the visual supplied by EGL is ARGB
     181                XRenderPictFormat *format;
     182                format = XRenderFindVisualFormat(X11->display, chosenVisualInfo->visual);
     183                if (format && (format->type == PictTypeDirect))
     184                    visualAlphaSize = countBits(format->direct.alphaMask);
     185            }
     186#endif
     187
     188            bool visualMatchesConfig = false;
     189            if ( visualRedSize == configRedSize &&
     190                 visualGreenSize == configGreenSize &&
     191                 visualBlueSize == configBlueSize )
     192            {
     193                // We need XRender to check the alpha channel size of the visual. If we don't have
     194                // the alpha size, we don't check it against the EGL config's alpha size.
     195                if (visualAlphaSize >= 0)
     196                    visualMatchesConfig = visualAlphaSize == configAlphaSize;
     197                else
     198                    visualMatchesConfig = true;
     199            }
     200
     201            if (!visualMatchesConfig) {
     202                if (visualAlphaSize >= 0) {
     203                    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",
     204                             (int)visualId, visualAlphaSize, visualRedSize, visualGreenSize, visualBlueSize,
     205                             configId, configAlphaSize, configRedSize, configGreenSize, configBlueSize);
     206                } else {
     207                    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",
     208                             (int)visualId, visualRedSize, visualGreenSize, visualBlueSize,
     209                             configId, configRedSize, configGreenSize, configBlueSize);
     210                }
     211                visualId = 0;
     212            }
     213        } else {
     214            qWarning("Warning: EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID",
     215                     (int)visualId, configId);
     216            visualId = 0;
     217        }
     218        XFree(chosenVisualInfo);
     219    }
     220#ifdef QT_DEBUG_X11_VISUAL_SELECTION
     221    else
     222        qDebug("EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId);
     223#endif
     224
     225    if (visualId) {
     226#ifdef QT_DEBUG_X11_VISUAL_SELECTION
     227        if (configAlphaSize > 0)
     228            qDebug("Using ARGB Visual ID %d provided by EGL for config %d", (int)visualId, configId);
     229        else
     230            qDebug("Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId);
     231#endif
     232        return visualId;
     233    }
     234
     235
     236    // If EGL didn't give us a valid visual ID, try XRender
     237#if !defined(QT_NO_XRENDER)
     238    if (!visualId && X11->use_xrender) {
     239        XVisualInfo visualInfoTemplate;
     240        memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
     241
     242        visualInfoTemplate.c_class = TrueColor;
     243
     244        XVisualInfo *matchingVisuals;
     245        int matchingCount = 0;
     246        matchingVisuals = XGetVisualInfo(X11->display,
     247                                         VisualClassMask,
     248                                         &visualInfoTemplate,
     249                                         &matchingCount);
     250
     251        for (int i = 0; i < matchingCount; ++i) {
     252            XRenderPictFormat *format;
     253            format = XRenderFindVisualFormat(X11->display, matchingVisuals[i].visual);
     254
     255            // Check the format for the visual matches the EGL config
     256            if ( (countBits(format->direct.redMask) == configRedSize) &&
     257                 (countBits(format->direct.greenMask) == configGreenSize) &&
     258                 (countBits(format->direct.blueMask) == configBlueSize) &&
     259                 (countBits(format->direct.alphaMask) == configAlphaSize) )
     260            {
     261                visualId = matchingVisuals[i].visualid;
     262                break;
     263            }
     264        }
     265        if (matchingVisuals)
     266            XFree(matchingVisuals);
     267
     268    }
     269    if (visualId) {
     270# ifdef QT_DEBUG_X11_VISUAL_SELECTION
     271        if (configAlphaSize > 0)
     272            qDebug("Using ARGB Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId);
     273        else
     274            qDebug("Using Opaque Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId);
     275# endif // QT_DEBUG_X11_VISUAL_SELECTION
     276        return visualId;
     277    }
     278# ifdef QT_DEBUG_X11_VISUAL_SELECTION
     279    else
     280        qDebug("Failed to find an XVisual which matches EGL config %d using XRender", configId);
     281# endif // QT_DEBUG_X11_VISUAL_SELECTION
     282
     283#endif //!defined(QT_NO_XRENDER)
     284
     285
     286    // Finally, if XRender also failed to find a visual (or isn't present), try to
     287    // use XGetVisualInfo and only use the bit depths to match on:
     288    if (!visualId) {
     289        XVisualInfo visualInfoTemplate;
     290        memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
     291        XVisualInfo *matchingVisuals;
     292        int matchingCount = 0;
     293
     294        visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize;
     295        matchingVisuals = XGetVisualInfo(X11->display,
     296                                         VisualDepthMask,
     297                                         &visualInfoTemplate,
     298                                         &matchingCount);
     299        if (!matchingVisuals) {
     300            // Try again without taking the alpha channel into account:
     301            visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize;
     302            matchingVisuals = XGetVisualInfo(X11->display,
     303                                             VisualDepthMask,
     304                                             &visualInfoTemplate,
     305                                             &matchingCount);
     306        }
     307
     308        if (matchingVisuals) {
     309            visualId = matchingVisuals[0].visualid;
     310            XFree(matchingVisuals);
     311        }
     312    }
     313
     314    if (visualId) {
     315#ifdef QT_DEBUG_X11_VISUAL_SELECTION
     316        qDebug("Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId);
     317#endif
     318        return visualId;
     319    }
     320
     321    qWarning("Unable to find an X11 visual which matches EGL config %d", configId);
     322    return (VisualID)0;
     323}
     324
     325void qt_set_winid_on_widget(QWidget* w, Qt::HANDLE id)
     326{
     327    w->create(id);
     328}
     329
     330
     331// NOTE: The X11 version of createSurface will re-create the native drawable if it's visual doesn't
     332// match the one for the passed in EGLConfig
     333EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *unusedProperties)
     334{
     335    Q_UNUSED(unusedProperties);
     336
     337    int devType = device->devType();
     338
     339    if (devType == QInternal::Pbuffer) {
     340        // TODO
     341        return EGL_NO_SURFACE;
     342    }
     343
     344    QX11PixmapData *x11PixmapData = 0;
     345    if (devType == QInternal::Pixmap) {
     346        QPixmapData *pmd = static_cast<QPixmap*>(device)->data_ptr().data();
     347        if (pmd->classId() == QPixmapData::X11Class)
     348            x11PixmapData = static_cast<QX11PixmapData*>(pmd);
     349        else {
     350            // TODO: Replace the pixmap's data with a new QX11PixmapData
     351            qWarning("WARNING: Creating an EGL surface on a QPixmap is only supported for QX11PixmapData");
     352            return EGL_NO_SURFACE;
     353        }
     354    } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
     355        qWarning("WARNING: Creating an EGLSurface for device type %d isn't supported", devType);
     356        return EGL_NO_SURFACE;
     357    }
     358
     359    VisualID visualId = QEgl::getCompatibleVisualId(config);
     360    EGLint alphaSize;
     361    eglGetConfigAttrib(QEgl::display(), config, EGL_ALPHA_SIZE, &alphaSize);
     362
     363    if (devType == QInternal::Widget) {
     364        QWidget *widget = static_cast<QWidget*>(device);
     365
     366        VisualID currentVisualId = 0;
     367        if (widget->testAttribute(Qt::WA_WState_Created))
     368            currentVisualId = XVisualIDFromVisual((Visual*)widget->x11Info().visual());
     369
     370        if (currentVisualId != visualId) {
     371            // The window is either not created or has the wrong visual. Either way, we need
     372            // to create a window with the correct visual and call create() on the widget:
     373
     374            bool visible = widget->isVisible();
     375            if (visible)
     376                widget->hide();
     377
     378            XVisualInfo visualInfo;
     379            visualInfo.visualid = visualId;
     380            {
     381                XVisualInfo *visualInfoPtr;
     382                int matchingCount = 0;
     383                visualInfoPtr = XGetVisualInfo(widget->x11Info().display(), VisualIDMask,
     384                                               &visualInfo, &matchingCount);
     385                Q_ASSERT(visualInfoPtr); // visualId really should be valid!
     386                visualInfo = *visualInfoPtr;
     387                XFree(visualInfoPtr);
     388            }
     389
     390            Window parentWindow = RootWindow(widget->x11Info().display(), widget->x11Info().screen());
     391            if (widget->parentWidget())
     392                parentWindow = widget->parentWidget()->winId();
     393
     394            XSetWindowAttributes windowAttribs;
     395            QColormap colmap = QColormap::instance(widget->x11Info().screen());
     396            windowAttribs.background_pixel = colmap.pixel(widget->palette().color(widget->backgroundRole()));
     397            windowAttribs.border_pixel = colmap.pixel(Qt::black);
     398
     399            unsigned int valueMask = CWBackPixel|CWBorderPixel;
     400            if (alphaSize > 0) {
     401                windowAttribs.colormap = XCreateColormap(widget->x11Info().display(), parentWindow,
     402                                                         visualInfo.visual, AllocNone);
     403                valueMask |= CWColormap;
     404            }
     405
     406            Window window = XCreateWindow(widget->x11Info().display(), parentWindow,
     407                                          widget->x(), widget->y(), widget->width(), widget->height(),
     408                                          0, visualInfo.depth, InputOutput, visualInfo.visual,
     409                                          valueMask, &windowAttribs);
     410
     411            // This is a nasty hack to get round the fact that we can't be a friend of QWidget:
     412            qt_set_winid_on_widget(widget, window);
     413
     414            if (visible)
     415                widget->show();
     416        }
     417
     418        // At this point, the widget's window should be created and have the correct visual. Now we
     419        // just need to create the EGL surface for it:
     420        EGLSurface surf = eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), 0);
     421        if (surf == EGL_NO_SURFACE)
     422            qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
     423        return surf;
     424    }
     425
     426    if (x11PixmapData) {
     427        // X11 Pixmaps are only created with a depth, so that's all we need to check
     428        EGLint configDepth;
     429        eglGetConfigAttrib(QEgl::display(), config, EGL_BUFFER_SIZE , &configDepth);
     430        if (x11PixmapData->depth() != configDepth) {
     431            // The bit depths are wrong which means the EGLConfig isn't compatable with
     432            // this pixmap. So we need to replace the pixmap's existing data with a new
     433            // one which is created with the correct depth:
     434
     435#ifndef QT_NO_XRENDER
     436            if (configDepth == 32) {
     437                qWarning("Warning: EGLConfig's depth (32) != pixmap's depth (%d), converting to ARGB32",
     438                         x11PixmapData->depth());
     439                x11PixmapData->convertToARGB32(true);
     440            } else
     441#endif
     442            {
     443                qWarning("Warning: EGLConfig's depth (%d) != pixmap's depth (%d)",
     444                         configDepth, x11PixmapData->depth());
     445            }
     446        }
     447
     448        QEglProperties surfaceAttribs;
     449
     450        // If the pixmap can't be bound to a texture, it's pretty useless
     451        surfaceAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
     452        if (alphaSize > 0)
     453            surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
     454        else
     455            surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
     456
     457        EGLSurface surf = eglCreatePixmapSurface(QEgl::display(), config,
     458                                                 (EGLNativePixmapType) x11PixmapData->handle(),
     459                                                 surfaceAttribs.properties());
     460        x11PixmapData->gl_surface = (void*)surf;
     461        QImagePixmapCleanupHooks::enableCleanupHooks(x11PixmapData);
     462        return surf;
     463    }
     464
     465    return EGL_NO_SURFACE;
     466}
     467
    156468QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.