void QGLPixmapData::ensureCreated() const
{
    if (!m_dirty)
        return;

    m_dirty = false;

    if (nativeImageHandleProvider && !nativeImageHandle)
        const_cast<QGLPixmapData *>(this)->createFromNativeImageHandleProvider();

    QGLShareContextScope ctx(qt_gl_share_widget()->context());
    m_ctx = ctx;

#ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE
    if (m_sgImage) {
        qt_resolve_eglimage_gl_extensions(ctx); // ensure initialized

        bool textureIsBound = false;
        GLuint newTextureId;

        EGLint imgAttr[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
        EGLImageKHR image = QEgl::eglCreateImageKHR(QEgl::display()
                                                , EGL_NO_CONTEXT
                                                , EGL_NATIVE_PIXMAP_KHR
                                                , (EGLClientBuffer)m_sgImage
                                                , imgAttr);

        glGenTextures(1, &newTextureId);
        glBindTexture( GL_TEXTURE_2D, newTextureId);

        if (image != EGL_NO_IMAGE_KHR) {
            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
            GLint err = glGetError();
            if (err == GL_NO_ERROR)
                textureIsBound = true;

            QEgl::eglDestroyImageKHR(QEgl::display(), image);
        }

        if (textureIsBound) {
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

            m_texture.id = newTextureId;
            m_texture.boundPixmap = const_cast<QGLPixmapData*>(this);
            QGLSgImageTextureCleanup::cleanupForContext(m_ctx)->insert(m_texture.id, const_cast<QGLPixmapData*>(this));
        } else {
            qWarning("QGLPixmapData: Failed to create texture from a SgImage image of size %dx%d", w, h);
            glDeleteTextures(1, &newTextureId);
        }
    }
#endif
}
Пример #2
0
void QMeeGoExtensions::initialize()
{
    QGLContext *ctx = (QGLContext *) QGLContext::currentContext();
    qt_resolve_eglimage_gl_extensions(ctx);

    if (QEgl::hasExtension("EGL_NOK_image_shared")) {
        qDebug("MeegoGraphics: found EGL_NOK_image_shared");
        _eglQueryImageNOK = (eglQueryImageNOKFunc) eglGetProcAddress("eglQueryImageNOK");
        _eglCreateSharedImageNOK = (eglCreateSharedImageNOKFunc) eglGetProcAddress("eglCreateSharedImageNOK");
        _eglDestroySharedImageNOK = (eglDestroySharedImageNOKFunc) eglGetProcAddress("eglDestroySharedImageNOK");
        _eglLockSurfaceKHR = (eglLockSurfaceKHRFunc) eglGetProcAddress("eglLockSurfaceKHR");
        _eglUnlockSurfaceKHR = (eglUnlockSurfaceKHRFunc) eglGetProcAddress("eglUnlockSurfaceKHR");

        Q_ASSERT(_eglQueryImageNOK && _eglCreateSharedImageNOK && _eglDestroySharedImageNOK);
        hasImageShared = true;
    }

    if (QEgl::hasExtension("EGL_NOK_surface_scaling")) {
        qDebug("MeegoGraphics: found EGL_NOK_surface_scaling");
        _eglSetSurfaceScalingNOK = (eglSetSurfaceScalingNOKFunc) eglGetProcAddress("eglSetSurfaceScalingNOK");

        Q_ASSERT(_eglSetSurfaceScalingNOK);
        hasSurfaceScaling = true;
    }

    if (QEgl::hasExtension("EGL_KHR_lock_surface2")) {
        qDebug("MeegoGraphics: found EGL_KHR_lock_surface2");
        _eglLockSurfaceKHR = (eglLockSurfaceKHRFunc) eglGetProcAddress("eglLockSurfaceKHR");
        _eglUnlockSurfaceKHR = (eglUnlockSurfaceKHRFunc) eglGetProcAddress("eglUnlockSurfaceKHR");

        Q_ASSERT(_eglLockSurfaceKHR && _eglUnlockSurfaceKHR);
        hasLockSurface = true;
    }

    if (QEgl::hasExtension("EGL_KHR_fence_sync")) {
        qDebug("MeegoGraphics: found EGL_KHR_fence_sync");
        _eglCreateSyncKHR = (eglCreateSyncKHRFunc) eglGetProcAddress("eglCreateSyncKHR");
        _eglDestroySyncKHR = (eglDestroySyncKHRFunc) eglGetProcAddress("eglDestroySyncKHR");
        _eglClientWaitSyncKHR = (eglClientWaitSyncKHRFunc) eglGetProcAddress("eglClientWaitSyncKHR");
        _eglGetSyncAttribKHR = (eglGetSyncAttribKHRFunc) eglGetProcAddress("eglGetSyncAttribKHR");

        Q_ASSERT(_eglCreateSyncKHR && _eglDestroySyncKHR && _eglClientWaitSyncKHR && _eglGetSyncAttribKHR);
        hasFenceSync = true;
    }
}
Пример #3
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;
}