summaryrefslogtreecommitdiffstats
path: root/src/opengl/qgl_x11egl.cpp
diff options
context:
space:
mode:
authorTom Cooksey <thomas.cooksey@nokia.com>2010-03-22 09:48:39 (GMT)
committerTom Cooksey <thomas.cooksey@nokia.com>2010-03-26 12:32:53 (GMT)
commit75bb84ac0e6f17446d87a34ae8a644abff6009af (patch)
tree0aff2d7bd0d9f11042db103323ee72537cc41ae7 /src/opengl/qgl_x11egl.cpp
parentfa40e6fd8b719e2edfdbde94ac70431c68e92449 (diff)
downloadQt-75bb84ac0e6f17446d87a34ae8a644abff6009af.zip
Qt-75bb84ac0e6f17446d87a34ae8a644abff6009af.tar.gz
Qt-75bb84ac0e6f17446d87a34ae8a644abff6009af.tar.bz2
Implement Texture-From-Pixmap using EGLImage extensions on X11/EGL
There's lots of EGLImage extensions, split between EGL and client rendering APIs like OpenGL ES & OpenVG. To implement texture-from- pixmap using EGLImage, both EGL extensions and OpenGL ES extensions are needed. This patch resolves the EGL extension function pointers after the display is initialized in QEgl::display(). These are then exported from QtGui so they can be used in QtOpenGL. The OpenGL ES extension function pointers are resolved using the usual qglextensions.cpp mechanism. Using EGLImage seems to remove a fixed ~10 millisecond overhead per pixmap bind when compared to using EGLSurface. Exact results per bind for 100 QPixmaps are: 8x8 Pixmap: 12 -> 1.71 msecs (EGLSurface -> EGLImage) 64x64 Pixmap: 11.6 -> 1.83 msecs (EGLSurface -> EGLImage) 128x128 Pixmap: 12.8 -> 2.74 msecs (EGLSurface -> EGLImage) 256x256 Pixmap: 16 -> 6.20 msecs (EGLSurface -> EGLImage) Reviewed-By: Trond
Diffstat (limited to 'src/opengl/qgl_x11egl.cpp')
-rw-r--r--src/opengl/qgl_x11egl.cpp146
1 files changed, 111 insertions, 35 deletions
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index 0954e69..6980281 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -367,6 +367,30 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, cons
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 seperate 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")) {
+ Q_ASSERT(eglCreateImageKHR);
+ Q_ASSERT(eglDestroyImageKHR);
+
+ // 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
@@ -379,61 +403,113 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, cons
}
}
- if (!haveTFP)
+ if (!haveTFP && !haveEglImageTFP)
return 0;
- QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
+
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
bool hasAlpha = pixmapData->hasAlphaChannel();
+ bool pixmapHasValidSurface = false;
+ bool textureIsBound = false;
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
- // Check to see if the surface is still valid
- if (pixmapData->gl_surface &&
- hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ if (haveTFP && pixmapData->gl_surface &&
+ hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
{
- // Surface is invalid!
- destroyGlSurfaceForPixmap(pixmapData);
+ pixmapHasValidSurface = true;
}
- if (pixmapData->gl_surface == 0) {
- EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
- QEgl::OpenGL,
- hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
+ // 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;
+ }
- QPixmap tmpPixmap(pixmapData); //###
- pixmapData->gl_surface = (void*)QEgl::createSurface(&tmpPixmap, config);
- if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) {
- haveTFP = false;
- return 0;
- }
+ // 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) {
+ Q_ASSERT(eglCreateImageKHR);
+
+ EGLImageKHR eglImage;
+ QPixmap tmpPixmap(pd);
+
+ EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE
+ };
+ eglImage = eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
+ (EGLClientBuffer)QEgl::nativePixmap(&tmpPixmap), 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)
+ eglDestroyImageKHR(QEgl::display(), eglImage);
}
- Q_ASSERT(pixmapData->gl_surface);
+ 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);
+ }
- GLuint textureId;
- glGenTextures(1, &textureId);
- glBindTexture(GL_TEXTURE_2D, textureId);
+ if (pixmapData->gl_surface == 0) {
+ EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
+ QEgl::OpenGL,
+ hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
- // bind the egl pixmap surface to a texture
- EGLBoolean success;
- success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
- if (success == EGL_FALSE) {
- qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
- eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
- pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
- haveTFP = false;
- return 0;
+ QPixmap tmpPixmap(pixmapData); //###
+ pixmapData->gl_surface = (void*)QEgl::createSurface(&tmpPixmap, 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 = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
- pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
+ QGLTexture *texture = 0;
- // We assume the cost of bound pixmaps is zero
- QGLTextureCache::instance()->insert(q, key, 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);
- glBindTexture(GL_TEXTURE_2D, textureId);
return texture;
}
+
void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
{
Q_ASSERT(pmd->classId() == QPixmapData::X11Class);