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