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; }
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; }