EGLSurface QMeeGoLivePixmapData::getSurfaceForBackingPixmap()
{
    initializeThroughEGLImage();

    // This code is a crative remix of the stuff that can be found in the
    // Qt's TFP implementation in /src/opengl/qgl_x11egl.cpp ::bindiTextureFromNativePixmap
    QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(backingX11Pixmap->data_ptr().data());
    Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
    bool hasAlpha = pixmapData->hasAlphaChannel();

    if (pixmapData->gl_surface &&
        hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
        return pixmapData->gl_surface;

    // Check to see if the surface is still valid
    if (pixmapData->gl_surface &&
        hasAlpha != ((pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha) > 0)) {
        // Surface is invalid!
        destroySurfaceForPixmapData(pixmapData);
    }

    if (pixmapData->gl_surface == 0) {
        EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
                                               QEgl::OpenGL,
                                               hasAlpha ? QEgl::Translucent : QEgl::NoOptions);

        pixmapData->gl_surface = (void*)QEgl::createSurface(backingX11Pixmap, config);

        if (hasAlpha)
            pixmapData->flags |= QX11PixmapData::GlSurfaceCreatedWithAlpha;
        else
            pixmapData->flags &= ~QX11PixmapData::GlSurfaceCreatedWithAlpha;

        if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE)
            return NULL;
    }

    return pixmapData->gl_surface;
}
Example #2
0
QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
                                                           QGLContext::BindOptions options)
{
    Q_Q(QGLContext);

    // The EGL texture_from_pixmap has no facility to invert the y coordinate
    if (!(options & QGLContext::CanFlipNativePixmapBindOption))
        return 0;


    static bool checkedForTFP = false;
    static bool haveTFP = false;
    static bool checkedForEglImageTFP = false;
    static bool haveEglImageTFP = false;


    if (!checkedForEglImageTFP) {
        checkedForEglImageTFP = true;

        // We need to be able to create an EGLImage from a native pixmap, which was split
        // into a separate EGL extension, EGL_KHR_image_pixmap. It is possible to have
        // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must
        // check we have the EGLImage from pixmap functionality.
        if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) {

            // Being able to create an EGLImage from a native pixmap is also pretty useless
            // without the ability to bind that EGLImage as a texture, which is provided by
            // the GL_OES_EGL_image extension, which we try to resolve here:
            haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q);

            if (haveEglImageTFP)
                qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!");
        }
    }

    if (!checkedForTFP) {
        // Check for texture_from_pixmap egl extension
        checkedForTFP = true;
        if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") ||
            QEgl::hasExtension("EGL_EXT_texture_from_pixmap"))
        {
            qDebug("Found texture_from_pixmap EGL extension!");
            haveTFP = true;
        }
    }

    if (!haveTFP && !haveEglImageTFP)
        return 0;


    QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
    Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
    bool hasAlpha = pixmapData->hasAlphaChannel();
    bool pixmapHasValidSurface = false;
    bool textureIsBound = false;
    GLuint textureId;
    glGenTextures(1, &textureId);
    glBindTexture(GL_TEXTURE_2D, textureId);

    if (haveTFP && pixmapData->gl_surface &&
        hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
    {
        pixmapHasValidSurface = true;
    }

    // If we already have a valid EGL surface for the pixmap, we should use it
    if (pixmapHasValidSurface) {
        EGLBoolean success;
        success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
        if (success == EGL_FALSE) {
            qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
            eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
            pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
        } else
            textureIsBound = true;
    }

    // If the pixmap doesn't already have a valid surface, try binding it via EGLImage
    // first, as going through EGLImage should be faster and better supported:
    if (!textureIsBound && haveEglImageTFP) {
        EGLImageKHR eglImage;

        EGLint attribs[] = {
            EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
            EGL_NONE
        };
        eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
                                     (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs);

        QGLContext* ctx = q;
        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);

        GLint err = glGetError();
        if (err == GL_NO_ERROR)
            textureIsBound = true;

        // Once the egl image is bound, the texture becomes a new sibling image and we can safely
        // destroy the EGLImage we created for the pixmap:
        if (eglImage != EGL_NO_IMAGE_KHR)
            QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
    }

    if (!textureIsBound && haveTFP) {
        // Check to see if the surface is still valid
        if (pixmapData->gl_surface &&
            hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
        {
            // Surface is invalid!
            destroyGlSurfaceForPixmap(pixmapData);
        }

        if (pixmapData->gl_surface == 0) {
            EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
                                                   QEgl::OpenGL,
                                                   hasAlpha ? QEgl::Translucent : QEgl::NoOptions);

            pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config);
            if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE)
                return false;
        }

        EGLBoolean success;
        success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
        if (success == EGL_FALSE) {
            qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
            eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
            pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
            haveTFP = false; // If TFP isn't working, disable it's use
        } else
            textureIsBound = true;
    }

    QGLTexture *texture = 0;

    if (textureIsBound) {
        texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
        pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;

        // We assume the cost of bound pixmaps is zero
        QGLTextureCache::instance()->insert(q, key, texture, 0);

        glBindTexture(GL_TEXTURE_2D, textureId);
    } else
        glDeleteTextures(1, &textureId);

    return texture;
}