summaryrefslogtreecommitdiffstats
path: root/src/opengl/qgl_x11egl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/qgl_x11egl.cpp')
-rw-r--r--src/opengl/qgl_x11egl.cpp147
1 files changed, 110 insertions, 37 deletions
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index 0954e69..af0100b 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -354,7 +354,7 @@ void QGLWidgetPrivate::recreateEglSurface(bool force)
}
-QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key,
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
QGLContext::BindOptions options)
{
Q_Q(QGLContext);
@@ -363,10 +363,33 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, cons
if (!(options & QGLContext::CanFlipNativePixmapBindOption))
return 0;
- Q_ASSERT(pd->classId() == QPixmapData::X11Class);
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 +402,111 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, cons
}
}
- if (!haveTFP)
+ if (!haveTFP && !haveEglImageTFP)
return 0;
- QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
+ 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);
- // 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 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 (pixmapData->gl_surface == 0) {
- EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
- QEgl::OpenGL,
- hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
+ // 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);
- QPixmap tmpPixmap(pixmapData); //###
- pixmapData->gl_surface = (void*)QEgl::createSurface(&tmpPixmap, config);
- if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) {
- haveTFP = false;
- return 0;
- }
+ EGLImageKHR eglImage;
+
+ EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE
+ };
+ eglImage = 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)
+ 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;
+ 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 = 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);