summaryrefslogtreecommitdiff
path: root/src/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp94
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h3
-rw-r--r--src/opengl/opengl.pro1
-rw-r--r--src/opengl/qgl.cpp41
-rw-r--r--src/opengl/qgl_p.h14
-rw-r--r--src/opengl/qgl_x11.cpp211
-rw-r--r--src/opengl/qgl_x11egl.cpp179
-rw-r--r--src/opengl/qglcolormap.cpp24
-rw-r--r--src/opengl/qglpixelbuffer_x11.cpp2
9 files changed, 448 insertions, 121 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 5c85b40068..62090a5719 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1343,10 +1343,30 @@ void QGL2PaintEngineExPrivate::updateDepthScissorTest()
else
glDisable(GL_DEPTH_TEST);
- if (q->state()->scissorTestEnabled)
+ if (q->state()->scissorTestEnabled) {
+ QRect bounds = q->state()->rectangleClip;
+ if (bounds.isNull() || !q->painter()->hasClipping()) {
+ if (use_system_clip)
+ bounds = systemClip.boundingRect();
+ else
+ bounds = QRect(0, 0, width, height);
+ }
+
glEnable(GL_SCISSOR_TEST);
- else
+ setScissor(bounds);
+ } else {
glDisable(GL_SCISSOR_TEST);
+ }
+}
+
+void QGL2PaintEngineExPrivate::setScissor(const QRect &rect)
+{
+ const int left = rect.left();
+ const int width = rect.width();
+ const int bottom = height - (rect.top() + rect.height());
+ const int height = rect.height();
+
+ glScissor(left, bottom, width, height);
}
void QGL2PaintEngineEx::clipEnabledChanged()
@@ -1362,9 +1382,10 @@ void QGL2PaintEngineEx::clipEnabledChanged()
if (d->use_system_clip) {
state()->currentDepth = -0.5f;
} else {
- glDisable(GL_DEPTH_TEST);
state()->depthTestEnabled = false;
}
+
+ d->updateDepthScissorTest();
}
}
@@ -1436,9 +1457,42 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
if ((d->use_system_clip && rect.contains(d->systemClip.boundingRect()))
|| rect.contains(QRect(0, 0, d->width, d->height)))
return;
+
+ if (state()->rectangleClip.isValid()) {
+ state()->rectangleClip = state()->rectangleClip.intersected(rect.toRect());
+
+ state()->hasRectangleClip = true;
+ state()->scissorTestEnabled = true;
+
+ glEnable(GL_SCISSOR_TEST);
+ d->setScissor(state()->rectangleClip);
+
+ return;
+ }
}
}
+ if (!state()->hasRectangleClip)
+ state()->rectangleClip = QRect();
+
+ if (state()->rectangleClip.isValid() && op != Qt::NoClip && op != Qt::ReplaceClip) {
+ QPainterPath path;
+ path.addRect(state()->rectangleClip);
+
+ state()->rectangleClip = QRect();
+ d->updateDepthScissorTest();
+
+ glDepthFunc(GL_ALWAYS);
+
+ state()->maxDepth = 0.5f;
+ d->writeClip(qtVectorPathForPath(path), state()->maxDepth);
+ state()->currentDepth = 0.25f;
+ state()->depthTestEnabled = true;
+
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+ }
+
switch (op) {
case Qt::NoClip:
if (d->use_system_clip) {
@@ -1459,6 +1513,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
break;
case Qt::ReplaceClip:
d->systemStateChanged();
+ state()->rectangleClip = QRect();
state()->maxDepth = 0.5f;
glDepthFunc(GL_ALWAYS);
d->writeClip(path, state()->maxDepth);
@@ -1497,27 +1552,30 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
q->state()->depthTestEnabled = false;
q->state()->scissorTestEnabled = false;
q->state()->needsDepthBufferClear = true;
+ q->state()->hasRectangleClip = false;
glDisable(GL_SCISSOR_TEST);
q->state()->currentDepth = -0.5f;
q->state()->maxDepth = 0.5f;
- if (use_system_clip) {
- QRect bounds = systemClip.boundingRect();
- if (systemClip.numRects() == 1
- && bounds == QRect(0, 0, width, height))
- {
- q->state()->needsDepthBufferClear = true;
- } else {
- glEnable(GL_SCISSOR_TEST);
+ q->state()->rectangleClip = QRect(0, 0, width, height);
- const int left = bounds.left();
- const int width = bounds.width();
- const int bottom = height - (bounds.top() + bounds.height());
- const int height = bounds.height();
+ if (use_system_clip) {
+ if (systemClip.numRects() == 1) {
+ QRect bounds = systemClip.boundingRect();
+ if (bounds == QRect(0, 0, width, height)) {
+ use_system_clip = false;
+ return;
+ }
- glScissor(left, bottom, width, height);
+ q->state()->rectangleClip = bounds;
+ q->state()->scissorTestEnabled = true;
+ updateDepthScissorTest();
+ } else {
+ q->state()->rectangleClip = QRect();
+ q->state()->scissorTestEnabled = true;
+ updateDepthScissorTest();
QTransform transform = q->state()->matrix;
q->state()->matrix = QTransform();
@@ -1539,7 +1597,6 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
glEnable(GL_DEPTH_TEST);
q->state()->depthTestEnabled = true;
- q->state()->scissorTestEnabled = true;
q->state()->matrix = transform;
q->transformChanged();
@@ -1614,6 +1671,8 @@ QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &oth
currentDepth = other.currentDepth;
maxDepth = other.maxDepth;
canRestoreClip = other.canRestoreClip;
+ rectangleClip = other.rectangleClip;
+ hasRectangleClip = other.hasRectangleClip;
}
QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
@@ -1624,6 +1683,7 @@ QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
currentDepth = -0.5f;
maxDepth = 0.5f;
canRestoreClip = true;
+ hasRectangleClip = false;
}
QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index ec447a3e36..906817b5b8 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -86,6 +86,8 @@ public:
qreal maxDepth;
bool canRestoreClip;
+ QRect rectangleClip;
+ bool hasRectangleClip;
};
@@ -217,6 +219,7 @@ public:
void writeClip(const QVectorPath &path, float depth);
void updateDepthScissorTest();
+ void setScissor(const QRect &rect);
void regenerateDepthClip();
void systemStateChanged();
uint use_system_clip : 1;
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index c92b8cf573..868484ee14 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -20,6 +20,7 @@ HEADERS += qgl.h \
qgl_p.h \
qglcolormap.h \
qglpixelbuffer.h \
+ qglpixelbuffer_p.h \
qglframebufferobject.h \
qglextensions_p.h
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 721130929a..e124c2ede3 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -86,6 +86,7 @@
#include <private/qpixmapdata_gl_p.h>
#include <private/qglpixelbuffer_p.h>
#include <private/qwindowsurface_gl_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#include "qcolormap.h"
#include "qfile.h"
#include "qlibrary.h"
@@ -526,7 +527,7 @@ void QGLFormat::setAccum(bool enable)
\fn bool QGLFormat::stencil() const
Returns true if the stencil buffer is enabled; otherwise returns
- false. The stencil buffer is disabled by default.
+ false. The stencil buffer is enabled by default.
\sa setStencil(), setStencilBufferSize()
*/
@@ -535,7 +536,7 @@ void QGLFormat::setAccum(bool enable)
If \a enable is true enables the stencil buffer; otherwise
disables the stencil buffer.
- The stencil buffer is disabled by default.
+ The stencil buffer is enabled by default.
The stencil buffer masks certain parts of the drawing area so that
masked parts are not drawn on.
@@ -1407,15 +1408,17 @@ QGLTextureCache::QGLTextureCache()
{
Q_ASSERT(qt_gl_texture_cache == 0);
qt_gl_texture_cache = this;
- qt_pixmap_cleanup_hook_64 = cleanupHook;
- qt_image_cleanup_hook_64 = cleanupHook;
+
+ QImagePixmapCleanupHooks::instance()->addPixmapHook(pixmapCleanupHook);
+ QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook);
}
QGLTextureCache::~QGLTextureCache()
{
qt_gl_texture_cache = 0;
- qt_pixmap_cleanup_hook_64 = 0;
- qt_image_cleanup_hook_64 = 0;
+
+ QImagePixmapCleanupHooks::instance()->removePixmapHook(pixmapCleanupHook);
+ QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook);
}
void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
@@ -1471,7 +1474,7 @@ QGLTextureCache* QGLTextureCache::instance()
a hook that removes textures from the cache when a pixmap/image
is deref'ed
*/
-void QGLTextureCache::cleanupHook(qint64 cacheKey)
+void QGLTextureCache::imageCleanupHook(qint64 cacheKey)
{
// ### remove when the GL texture cache becomes thread-safe
if (qApp->thread() != QThread::currentThread())
@@ -1481,6 +1484,24 @@ void QGLTextureCache::cleanupHook(qint64 cacheKey)
instance()->remove(cacheKey);
}
+
+void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap)
+{
+ // ### remove when the GL texture cache becomes thread-safe
+ if (qApp->thread() == QThread::currentThread()) {
+ const qint64 cacheKey = pixmap->cacheKey();
+ QGLTexture *texture = instance()->getTexture(cacheKey);
+ if (texture && texture->clean)
+ instance()->remove(cacheKey);
+ }
+#if defined(Q_WS_X11)
+ QPixmapData *pd = pixmap->data_ptr();
+ // Only need to delete the gl surface if the pixmap is about to be deleted
+ if (pd->ref == 0)
+ QGLContextPrivate::destroyGlSurfaceForPixmap(pd);
+#endif
+}
+
void QGLTextureCache::deleteIfEmpty()
{
if (instance()->size() == 0)
@@ -2020,11 +2041,11 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target,
#if defined(Q_WS_X11)
// Try to use texture_from_pixmap
if (pd->classId() == QPixmapData::X11Class) {
- QPixmap *thatPixmap = const_cast<QPixmap*>(&pixmap);
- texture = bindTextureFromNativePixmap(thatPixmap, key, canInvert);
+ texture = bindTextureFromNativePixmap(pd, key, canInvert);
if (texture) {
texture->clean = clean;
- boundPixmaps.insert(thatPixmap->data_ptr(), QPixmap(pixmap));
+ texture->boundPixmap = pd;
+ boundPixmaps.insert(pd, QPixmap(pixmap));
}
}
#endif
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 85dae0ddfa..f21ab93f4e 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -241,7 +241,9 @@ public:
quint32 gpm;
int screen;
QHash<QPixmapData*, QPixmap> boundPixmaps;
- QGLTexture *bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool internal);
+ QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key, bool canInvert);
+ static void destroyGlSurfaceForPixmap(QPixmapData*);
+ static void unbindPixmapFromTexture(QPixmapData*);
#endif
#if defined(Q_WS_MAC)
bool update;
@@ -423,7 +425,8 @@ public:
// is a current context - the context the pixmap was bound to a texture in.
// Otherwise the release doesn't do anything and you get BadDrawable errors
// when you come to delete the context.
- deleteBoundPixmap();
+ if (boundPixmap)
+ QGLContextPrivate::unbindPixmapFromTexture(boundPixmap);
#endif
glDeleteTextures(1, &id);
if (switch_context && current)
@@ -437,9 +440,9 @@ public:
bool clean;
bool yInverted; // NOTE: Y-Inverted textures are for internal use only!
#if defined(Q_WS_X11)
- Qt::HANDLE boundPixmap;
- void deleteBoundPixmap(); // in qgl_x11.cpp/qgl_x11egl.cpp
+ QPixmapData* boundPixmap;
#endif
+
};
class QGLTextureCache {
@@ -458,7 +461,8 @@ public:
static QGLTextureCache *instance();
static void deleteIfEmpty();
- static void cleanupHook(qint64 cacheKey);
+ static void imageCleanupHook(qint64 cacheKey);
+ static void pixmapCleanupHook(QPixmap* pixmap);
private:
QCache<qint64, QGLTexture> m_cache;
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index 6381bc2152..4509a64502 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -58,14 +58,27 @@
#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>
+#ifdef Q_OS_VXWORS
+# ifdef open
+# undef open
+# endif
+# ifdef getpid
+# undef getpid
+# endif
+#endif // Q_OS_VXWORKS
#include <X11/Xatom.h>
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
@@ -82,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
@@ -823,10 +836,12 @@ void QGLContext::swapBuffers() const
if (!glXGetVideoSyncSGI)
#endif
{
+#if !defined(QT_NO_LIBRARY)
extern const QString qt_gl_library_name();
QLibrary lib(qt_gl_library_name());
glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) lib.resolve("glXGetVideoSyncSGI");
glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) lib.resolve("glXWaitVideoSyncSGI");
+#endif
}
}
resolved = true;
@@ -1067,9 +1082,11 @@ void *QGLContext::getProcAddress(const QString &proc) const
if (!glXGetProcAddressARB)
#endif
{
+#if !defined(QT_NO_LIBRARY)
extern const QString qt_gl_library_name();
QLibrary lib(qt_gl_library_name());
glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
+#endif
}
}
resolved = true;
@@ -1536,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);
+ static bool resolvedTextureFromPixmap = false;
- if (pm->data_ptr()->classId() != QPixmapData::X11Class)
- return 0;
- QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pm->data_ptr());
- const QX11Info *x11Info = qt_x11Info(pm);
+ 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"))) {
@@ -1589,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
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index c6904fe8d2..ed9930f8ad 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -41,15 +41,16 @@
#include "qgl.h"
#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
#include <private/qgl_p.h>
#include <private/qpaintengine_opengl_p.h>
#include "qgl_egl_p.h"
#include "qcolormap.h"
+#include <QDebug>
QT_BEGIN_NAMESPACE
-
bool QGLFormat::hasOpenGL()
{
return true;
@@ -298,6 +299,7 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
int matchingCount = 0;
chosenVisualInfo = XGetVisualInfo(x11Info().display(), VisualIDMask, &vi, &matchingCount);
if (chosenVisualInfo) {
+#if !defined(QT_NO_XRENDER)
if (useArgbVisual) {
// Check to make sure the visual provided by EGL is ARGB
XRenderPictFormat *format;
@@ -311,8 +313,9 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
nativeVisualId, (int)qeglCtx->config());
vi.visualid = 0;
}
- }
- else {
+ } else
+#endif
+ {
qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
vi = *chosenVisualInfo;
}
@@ -486,15 +489,175 @@ void QGLWidgetPrivate::recreateEglSurface(bool force)
}
}
-QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert)
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key, bool canInvert)
{
- // TODO
- return 0;
+ Q_Q(QGLContext);
+
+ Q_ASSERT(pd->classId() == QPixmapData::X11Class);
+
+ static bool checkedForTFP = false;
+ static bool haveTFP = false;
+
+ if (!checkedForTFP) {
+ // Check for texture_from_pixmap egl extension
+ checkedForTFP = true;
+ if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
+ eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
+ {
+ qDebug("Found texture_from_pixmap EGL extension!");
+ haveTFP = true;
+ }
+ }
+
+ if (!haveTFP)
+ return 0;
+
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ EGLint pixmapAttribs[] = {
+ EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+ EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
+ EGL_NONE
+ };
+ Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
+ if (pixmapData->gl_surface == 0)
+ pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
+ EGLSurface pixmapSurface = (EGLSurface)pixmapData->gl_surface;
+ static EGLConfig pixmapRGBConfig = 0;
+ static EGLConfig pixmapRGBAConfig = 0;
+
+ // Check to see if we need to find a config
+ if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) {
+ const EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PIXMAP_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_DEPTH_SIZE, 0,
+ hasAlpha ? EGL_BIND_TO_TEXTURE_RGBA : EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
+ EGL_NONE
+ };
+
+ EGLint configCount = 0;
+ eglChooseConfig(eglContext->display(), configAttribs, 0, 256, &configCount);
+ if (configCount == 0) {
+ haveTFP = false;
+ qWarning("bindTextureFromNativePixmap() - Couldn't find a suitable config");
+ return 0;
+ }
+
+ EGLConfig *configList = new EGLConfig[configCount];
+ eglChooseConfig(eglContext->display(), configAttribs, configList, configCount, &configCount);
+ Q_ASSERT(configCount);
+
+ // Try to create a pixmap surface for each config until one works
+ for (int i = 0; i < configCount; ++i) {
+ pixmapSurface = eglCreatePixmapSurface(eglContext->display(), configList[i],
+ (EGLNativePixmapType) pixmapData->handle(),
+ pixmapAttribs);
+ if (pixmapSurface != EGL_NO_SURFACE) {
+ // Got one!
+ qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB")
+ << "config (" << int(configList[i]) << ") to create a pixmap surface";
+ if (hasAlpha)
+ pixmapRGBAConfig = configList[i];
+ else
+ pixmapRGBConfig = configList[i];
+ pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
+ break;
+ }
+ }
+ delete configList;
+
+ if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) {
+ qDebug("Couldn't create a pixmap surface with any of the provided configs");
+ haveTFP = false;
+ return 0;
+ }
+ }
+
+ if (pixmapSurface == EGL_NO_SURFACE) {
+ pixmapSurface = eglCreatePixmapSurface(eglContext->display(),
+ hasAlpha? pixmapRGBAConfig : pixmapRGBConfig,
+ (EGLNativePixmapType) pixmapData->handle(),
+ pixmapAttribs);
+ if (pixmapSurface == EGL_NO_SURFACE) {
+ qWarning("Failed to create a pixmap surface using config %d",
+ (int)(hasAlpha? pixmapRGBAConfig : pixmapRGBConfig));
+ haveTFP = false;
+ return 0;
+ }
+ pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
+ }
+
+ // Make sure the cleanup hook gets called so we can delete the glx pixmap
+ pixmapData->is_cached = true;
+ Q_ASSERT(pixmapData->gl_surface);
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ // bind the egl pixmap surface to a texture
+ EGLBoolean success;
+ success = eglBindTexImage(eglContext->display(), pixmapSurface, EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
+ eglDestroySurface(eglContext->display(), pixmapSurface);
+ pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
+ haveTFP = false;
+ return 0;
+ }
+
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, true);
+ 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);
+ return texture;
+}
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglDestroySurface(QEglContext::defaultDisplay(0), (EGLSurface)pixmapData->gl_surface);
+ if (success == EGL_FALSE) {
+ qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
+ << QEglContext::errorString(eglGetError());
+ }
+ pixmapData->gl_surface = 0;
+ }
}
-void QGLTexture::deleteBoundPixmap()
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
{
- //TODO
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglReleaseTexImage(QEglContext::defaultDisplay(0),
+ (EGLSurface)pixmapData->gl_surface,
+ EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
+ << QEglContext::errorString(eglGetError());
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/opengl/qglcolormap.cpp b/src/opengl/qglcolormap.cpp
index 426e090eb1..481089a61a 100644
--- a/src/opengl/qglcolormap.cpp
+++ b/src/opengl/qglcolormap.cpp
@@ -174,13 +174,14 @@ void QGLColormap::setEntry(int idx, QRgb color)
detach();
if (!d->cells)
d->cells = new QVector<QRgb>(256);
- d->cells->insert(idx, color);
+ d->cells->replace(idx, color);
}
/*!
Set an array of cells in this colormap. \a count is the number of
colors that should be set, \a colors is the array of colors, and
- \a base is the starting index.
+ \a base is the starting index. The first element in \a colors
+ is set at \a base in the colormap.
*/
void QGLColormap::setEntries(int count, const QRgb *colors, int base)
{
@@ -188,10 +189,10 @@ void QGLColormap::setEntries(int count, const QRgb *colors, int base)
if (!d->cells)
d->cells = new QVector<QRgb>(256);
- Q_ASSERT_X(!colors || base >= 0 || base + count < d->cells->size(), "QGLColormap::setEntries",
+ Q_ASSERT_X(colors && base >= 0 && (base + count) <= d->cells->size(), "QGLColormap::setEntries",
"preconditions not met");
- for (int i = base; i < base + count; ++i)
- setEntry(i, colors[i]);
+ for (int i = 0; i < count; ++i)
+ setEntry(base + i, colors[i]);
}
/*!
@@ -227,8 +228,17 @@ QColor QGLColormap::entryColor(int idx) const
}
/*!
- Returns true if the colormap is empty; otherwise returns false. A
- colormap with no color values set is considered to be empty.
+ Returns true if the colormap is empty or it is not in use
+ by a QGLWidget; otherwise returns false.
+
+ A colormap with no color values set is considered to be empty.
+ For historical reasons, a colormap that has color values set
+ but which is not in use by a QGLWidget is also considered empty.
+
+ Compare size() with zero to determine if the colormap is empty
+ regardless of whether it is in use by a QGLWidget or not.
+
+ \sa size()
*/
bool QGLColormap::isEmpty() const
{
diff --git a/src/opengl/qglpixelbuffer_x11.cpp b/src/opengl/qglpixelbuffer_x11.cpp
index 9e1f85d328..ac2e705d26 100644
--- a/src/opengl/qglpixelbuffer_x11.cpp
+++ b/src/opengl/qglpixelbuffer_x11.cpp
@@ -115,6 +115,7 @@ static bool qt_resolve_pbuffer_extensions()
if (!qt_glXChooseFBConfig)
#endif
{
+#if !defined(QT_NO_LIBRARY)
extern const QString qt_gl_library_name();
QLibrary gl(qt_gl_library_name());
qt_glXChooseFBConfig = (_glXChooseFBConfig) gl.resolve("glXChooseFBConfig");
@@ -123,6 +124,7 @@ static bool qt_resolve_pbuffer_extensions()
qt_glXDestroyPbuffer = (_glXDestroyPbuffer) gl.resolve("glXDestroyPbuffer");
qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) gl.resolve("glXGetFBConfigAttrib");
qt_glXMakeContextCurrent = (_glXMakeContextCurrent) gl.resolve("glXMakeContextCurrent");
+#endif
}
resolved = qt_glXMakeContextCurrent ? true : false;