summaryrefslogtreecommitdiffstats
path: root/src/opengl/qgl_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/qgl_x11.cpp')
-rw-r--r--src/opengl/qgl_x11.cpp199
1 files changed, 125 insertions, 74 deletions
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index cf70991..4509a64 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -58,11 +58,16 @@
#include <private/qglpixelbuffer_p.h>
#endif
+// We always define GLX_EXT_texture_from_pixmap ourselves because
+// we can't trust system headers to do it properly
+#define GLX_EXT_texture_from_pixmap 1
+
#define INT8 dummy_INT8
#define INT32 dummy_INT32
#include <GL/glx.h>
#undef INT8
#undef INT32
+
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
@@ -90,7 +95,7 @@ extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
#define GLX_SAMPLES_ARB 100001
#endif
-#ifndef GLX_EXT_texture_from_pixmap
+#ifndef GLX_TEXTURE_2D_BIT_EXT
#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
@@ -1548,38 +1553,26 @@ void QGLExtensions::init()
}
}
-#if !defined(glXBindTexImageEXT)
+// Solaris defines glXBindTexImageEXT as part of the GL library
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*);
-static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
-#endif
-#if !defined(glXReleaseTexImageEXT)
typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int);
+static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0;
-#endif
-static bool qt_resolved_texture_from_pixmap = false;
-QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert)
+bool qt_resolveTextureFromPixmap()
{
-#if !defined(Q_OS_LINUX)
- return 0;
-#else
- Q_Q(QGLContext);
-
- if (pm->data_ptr()->classId() != QPixmapData::X11Class)
- return 0;
- QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pm->data_ptr());
- const QX11Info *x11Info = qt_x11Info(pm);
+ static bool resolvedTextureFromPixmap = false;
+ if (!resolvedTextureFromPixmap) {
+ resolvedTextureFromPixmap = true;
- // Check to see if we have NPOT texture support
- // TODO: Use GLX_TEXTURE_RECTANGLE_EXT texture target on systems without npot textures
- if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) &&
- !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
- return 0;
-
-
- if (!qt_resolved_texture_from_pixmap) {
- qt_resolved_texture_from_pixmap = true;
+ // Check to see if we have NPOT texture support
+ if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) &&
+ !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
+ {
+ return false; // Can't use TFP without NPOT
+ }
QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
if (glxExt.contains(QLatin1String("GLX_EXT_texture_from_pixmap"))) {
@@ -1601,81 +1594,139 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qi
}
}
- if (!glXBindTexImageEXT)
- return 0;
+ return glXBindTexImageEXT && glXReleaseTexImageEXT;
+}
+#endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key, bool canInvert)
+{
#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
return 0;
#else
- GLXFBConfig *configList = 0;
- GLXFBConfig glxPixmapConfig;
- int configCount = 0;
- bool hasAlpha = pixmapData->hasAlphaChannel();
-
- int configAttribs[] = {
- hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
- GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
- GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
- // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
- GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False,
- XNone
-// GLX_BIND_TO_MIPMAP_TEXTURE_EXT, False,
-// GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_1D_BIT_EXT or GLX_TEXTURE_2D_BIT_EXT or GLX_TEXTURE_RECTANGLE_BIT_EXT
- };
- configList = glXChooseFBConfig(x11Info->display(), x11Info->screen(), configAttribs, &configCount);
- if (!configList)
- return 0;
- glxPixmapConfig = configList[0];
- XFree(configList);
-
- GLXPixmap glxPixmap;
- int pixmapAttribs[] = {
- GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
- GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
- GLX_MIPMAP_TEXTURE_EXT, False,
- XNone
-// GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT or GLX_TEXTURE_FORMAT_RGB_EXT or GLX_TEXTURE_FORMAT_NONE_EXT,
-// GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT or GLX_TEXTURE_RECTANGLE_EXT,
-// GLX_MIPMAP_TEXTURE_EXT, True or False,
- };
+ Q_Q(QGLContext);
- // Wrap the X Pixmap into a GLXPixmap:
- glxPixmap = glXCreatePixmap(x11Info->display(), glxPixmapConfig, pixmapData->handle(), pixmapAttribs);
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
- if (!glxPixmap)
+ if (!qt_resolveTextureFromPixmap())
return 0;
- int yInverted;
- glXGetFBConfigAttrib(x11Info->display(), glxPixmapConfig, GLX_Y_INVERTED_EXT, &yInverted);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ const QX11Info &x11Info = pixmapData->xinfo;
+
+ // Store the configs (Can be static because configs aren't dependent on current context)
+ static GLXFBConfig glxRGBPixmapConfig = 0;
+ static bool RGBConfigInverted = false;
+ static GLXFBConfig glxRGBAPixmapConfig = 0;
+ static bool RGBAConfigInverted = false;
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ // Check to see if we need a config
+ if ( (hasAlpha && !glxRGBAPixmapConfig) || (!hasAlpha && !glxRGBPixmapConfig) ) {
+ GLXFBConfig *configList = 0;
+ int configCount = 0;
+
+ int configAttribs[] = {
+ hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
+ GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False,
+ XNone
+ };
+ configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount);
+ if (!configList)
+ return 0;
+
+ int yInv;
+ glXGetFBConfigAttrib(x11Info.display(), configList[0], GLX_Y_INVERTED_EXT, &yInv);
+
+ if (hasAlpha) {
+ glxRGBAPixmapConfig = configList[0];
+ RGBAConfigInverted = yInv;
+ }
+ else {
+ glxRGBPixmapConfig = configList[0];
+ RGBConfigInverted = yInv;
+ }
+
+ XFree(configList);
+ }
+
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ // Check to see if we need a surface
+ if (!pixmapData->gl_surface) {
+ GLXPixmap glxPixmap;
+ int pixmapAttribs[] = {
+ GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_MIPMAP_TEXTURE_EXT, False, // Maybe needs to be don't care
+ XNone
+ };
+
+ // Wrap the X Pixmap into a GLXPixmap:
+ glxPixmap = glXCreatePixmap(x11Info.display(),
+ hasAlpha ? glxRGBAPixmapConfig : glxRGBPixmapConfig,
+ pixmapData->handle(), pixmapAttribs);
+
+ if (!glxPixmap)
+ return 0;
+
+ pixmapData->gl_surface = (Qt::HANDLE)glxPixmap;
+
+ // Make sure the cleanup hook gets called so we can delete the glx pixmap
+ pixmapData->is_cached = true;
+ }
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
- glXBindTexImageEXT(x11Info->display(), glxPixmap, GLX_FRONT_LEFT_EXT, 0);
+ glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0);
glBindTexture(GL_TEXTURE_2D, textureId);
- QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, yInverted);
- texture->boundPixmap = glxPixmap;
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, false);
+ texture->yInverted = (hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted);
+ if (texture->yInverted)
+ pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
// We assume the cost of bound pixmaps is zero
QGLTextureCache::instance()->insert(q, key, texture, 0);
return texture;
#endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
-#endif //!defined(Q_OS_LINUX
}
-void QGLTexture::deleteBoundPixmap()
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
{
-#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) && defined(Q_OS_LINUX)
- if (boundPixmap) {
- glXReleaseTexImageEXT(QX11Info::display(), boundPixmap, GLX_FRONT_LEFT_EXT);
- glXDestroyPixmap(QX11Info::display(), boundPixmap);
- boundPixmap = 0;
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ glXDestroyPixmap(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface);
+ pixmapData->gl_surface = 0;
}
#endif
}
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
+{
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ Q_ASSERT(QGLContext::currentContext());
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface)
+ glXReleaseTexImageEXT(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT);
+#endif
+}
QT_END_NAMESPACE