diff options
author | Alan Alpert <alan.alpert@nokia.com> | 2010-06-15 07:50:47 (GMT) |
---|---|---|
committer | Alan Alpert <alan.alpert@nokia.com> | 2010-06-15 07:50:47 (GMT) |
commit | 45d9575a8c680206cdea0519b03996b6b8085294 (patch) | |
tree | d156b7d5c2dc0633c4468dce4cae4f0daf9e0035 /src/opengl | |
parent | 01506a3b212d449d65df1131b49af0e174e45275 (diff) | |
parent | c1e6d97b9476c859abc3927046144b4006fcf735 (diff) | |
download | Qt-45d9575a8c680206cdea0519b03996b6b8085294.zip Qt-45d9575a8c680206cdea0519b03996b6b8085294.tar.gz Qt-45d9575a8c680206cdea0519b03996b6b8085294.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt-qml into 4.7
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 33 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 3 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp | 5 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h | 1 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 75 | ||||
-rw-r--r-- | src/opengl/qgl.h | 4 | ||||
-rw-r--r-- | src/opengl/qgl_egl.cpp | 5 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 40 | ||||
-rw-r--r-- | src/opengl/qgl_x11.cpp | 376 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 30 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.h | 2 |
11 files changed, 383 insertions, 191 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 5758b25..ee49a3d 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1333,8 +1333,16 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) QFontEngineGlyphCache::Type glyphType = textItem->fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat) : d->glyphCacheType; + if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { + if (d->device->alphaRequested() || state()->matrix.type() > QTransform::TxTranslate + || (state()->composition_mode != QPainter::CompositionMode_Source + && state()->composition_mode != QPainter::CompositionMode_SourceOver)) + { + glyphType = QFontEngineGlyphCache::Raster_A8; + } + } - d->drawCachedGlyphs(glyphType, textItem, true); + d->drawCachedGlyphs(glyphType, textItem); } bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) @@ -1408,7 +1416,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem staticTextItem.numGlyphs = glyphs.size(); staticTextItem.glyphPositions = positions.data(); - d->drawCachedGlyphs(glyphType, &staticTextItem, false); + d->drawCachedGlyphs(glyphType, &staticTextItem); } return; } @@ -1439,21 +1447,16 @@ namespace { // #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, - QStaticTextItem *staticTextItem, - bool includeMatrixInCache) + QStaticTextItem *staticTextItem) { Q_Q(QGL2PaintEngineEx); QOpenGL2PaintEngineState *s = q->state(); QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, - includeMatrixInCache - ? s->matrix - : QTransform()); + (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { - cache = new QGLTextureGlyphCache(ctx, glyphType, - includeMatrixInCache ? s->matrix : QTransform()); + cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); staticTextItem->fontEngine->setGlyphCache(ctx, cache); } @@ -1561,13 +1564,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QBrush pensBrush = q->state()->pen.brush(); setBrush(pensBrush); - // When painting a QStaticTextItem, the glyph positions are already in device coordinates, - // therefore we temporarily set an identity matrix on the painter for the draw call to - // avoid transforming the positions twice. - QTransform old = s->matrix; - if (includeMatrixInCache) - s->matrix = QTransform(); - if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { // Subpixel antialiasing without gamma correction @@ -1664,9 +1660,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp #else glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); #endif - - if (includeMatrixInCache) - s->matrix = old; } void QGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 0a046dc..59b90d8 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -202,8 +202,7 @@ public: void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, QPainter::PixmapFragmentHints hints); - void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem, - bool includeMatrixInCache); + void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem); // Calls glVertexAttributePointer if the pointer has changed inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer); diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 410cf21..5371c5e 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -276,6 +276,11 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) } } +int QGLTextureGlyphCache::glyphMargin() const +{ + return 1; +} + int QGLTextureGlyphCache::glyphPadding() const { return 1; diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index 6bcd655..84e9021 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -72,6 +72,7 @@ public: virtual void createTextureData(int width, int height); virtual void resizeTextureData(int width, int height); virtual void fillTexture(const Coord &c, glyph_t glyph); + virtual int glyphMargin() const; virtual int glyphPadding() const; inline GLuint texture() const { return m_texture; } diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 922a96c..b4c85ac 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -91,6 +91,7 @@ #include "qcolormap.h" #include "qfile.h" #include "qlibrary.h" +#include <qmutex.h> QT_BEGIN_NAMESPACE @@ -1255,6 +1256,8 @@ QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(co QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_3_0; switch (versionString[2].toAscii()) { + case '3': + versionFlags |= QGLFormat::OpenGL_Version_3_3; case '2': versionFlags |= QGLFormat::OpenGL_Version_3_2; case '1': @@ -1263,9 +1266,23 @@ QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(co break; default: versionFlags |= QGLFormat::OpenGL_Version_3_1 | - QGLFormat::OpenGL_Version_3_2; + QGLFormat::OpenGL_Version_3_2 | + QGLFormat::OpenGL_Version_3_3; break; } + } else if (versionString.startsWith(QLatin1String("4."))) { + versionFlags |= QGLFormat::OpenGL_Version_1_1 | + QGLFormat::OpenGL_Version_1_2 | + QGLFormat::OpenGL_Version_1_3 | + QGLFormat::OpenGL_Version_1_4 | + QGLFormat::OpenGL_Version_1_5 | + QGLFormat::OpenGL_Version_2_0 | + QGLFormat::OpenGL_Version_2_1 | + QGLFormat::OpenGL_Version_3_0 | + QGLFormat::OpenGL_Version_3_1 | + QGLFormat::OpenGL_Version_3_2 | + QGLFormat::OpenGL_Version_3_3 | + QGLFormat::OpenGL_Version_4_0; } else { versionFlags |= QGLFormat::OpenGL_Version_1_1 | QGLFormat::OpenGL_Version_1_2 | @@ -1276,7 +1293,9 @@ QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(co QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_3_0 | QGLFormat::OpenGL_Version_3_1 | - QGLFormat::OpenGL_Version_3_2; + QGLFormat::OpenGL_Version_3_2 | + QGLFormat::OpenGL_Version_3_3 | + QGLFormat::OpenGL_Version_4_0; } } return versionFlags; @@ -1515,10 +1534,33 @@ bool operator!=(const QGLFormat& a, const QGLFormat& b) return !(a == b); } +struct QGLContextGroupList { + void append(QGLContextGroup *group) { + QMutexLocker locker(&m_mutex); + m_list.append(group); + } + + void remove(QGLContextGroup *group) { + QMutexLocker locker(&m_mutex); + m_list.removeOne(group); + } + + QList<QGLContextGroup *> m_list; + QMutex m_mutex; +}; + +Q_GLOBAL_STATIC(QGLContextGroupList, qt_context_groups) + /***************************************************************************** QGLContext implementation *****************************************************************************/ +QGLContextGroup::QGLContextGroup(const QGLContext *context) + : m_context(context), m_guards(0), m_refs(1) +{ + qt_context_groups()->append(this); +} + QGLContextGroup::~QGLContextGroup() { // Clear any remaining QGLSharedResourceGuard objects on the group. @@ -1528,6 +1570,7 @@ QGLContextGroup::~QGLContextGroup() guard->m_id = 0; guard = guard->m_next; } + qt_context_groups()->remove(this); } void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard) @@ -1736,7 +1779,7 @@ void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, i QWriteLocker locker(&m_lock); if (m_cache.totalCost() + cost > m_cache.maxCost()) { // the cache is full - make an attempt to remove something - const QList<qint64> keys = m_cache.keys(); + const QList<QGLTextureCacheKey> keys = m_cache.keys(); int i = 0; while (i < m_cache.count() && (m_cache.totalCost() + cost > m_cache.maxCost())) { @@ -1746,13 +1789,26 @@ void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, i ++i; } } - m_cache.insert(key, texture, cost); + const QGLTextureCacheKey cacheKey = {key, QGLContextPrivate::contextGroup(ctx)}; + m_cache.insert(cacheKey, texture, cost); +} + +void QGLTextureCache::remove(qint64 key) +{ + QWriteLocker locker(&m_lock); + QMutexLocker groupLocker(&qt_context_groups()->m_mutex); + QList<QGLContextGroup *>::const_iterator it = qt_context_groups()->m_list.constBegin(); + while (it != qt_context_groups()->m_list.constEnd()) { + const QGLTextureCacheKey cacheKey = {key, *it}; + m_cache.remove(cacheKey); + ++it; + } } bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) { QWriteLocker locker(&m_lock); - QList<qint64> keys = m_cache.keys(); + QList<QGLTextureCacheKey> keys = m_cache.keys(); for (int i = 0; i < keys.size(); ++i) { QGLTexture *tex = m_cache.object(keys.at(i)); if (tex->id == textureId && tex->context == ctx) { @@ -1767,9 +1823,9 @@ bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) void QGLTextureCache::removeContextTextures(QGLContext* ctx) { QWriteLocker locker(&m_lock); - QList<qint64> keys = m_cache.keys(); + QList<QGLTextureCacheKey> keys = m_cache.keys(); for (int i = 0; i < keys.size(); ++i) { - const qint64 &key = keys.at(i); + const QGLTextureCacheKey &key = keys.at(i); if (m_cache.object(key)->context == ctx) m_cache.remove(key); } @@ -1782,7 +1838,6 @@ void QGLTextureCache::removeContextTextures(QGLContext* ctx) void QGLTextureCache::cleanupTexturesForCacheKey(qint64 cacheKey) { qt_gl_texture_cache()->remove(cacheKey); - Q_ASSERT(qt_gl_texture_cache()->getTexture(cacheKey) == 0); } @@ -2425,7 +2480,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target) { Q_Q(QGLContext); - QGLTexture *texture = QGLTextureCache::instance()->getTexture(key); + QGLTexture *texture = QGLTextureCache::instance()->getTexture(q, key); if (texture && texture->target == target && (texture->context == q || QGLContext::areSharing(q, texture->context))) { @@ -3619,8 +3674,10 @@ QGLWidget::~QGLWidget() bool doRelease = (glcx && glcx->windowCreated()); #endif delete d->glcx; + d->glcx = 0; #if defined(Q_WGL) delete d->olcx; + d->olcx = 0; #endif #if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT) if (doRelease) diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index f297009..f0b36f7 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -266,7 +266,9 @@ public: OpenGL_ES_Version_2_0 = 0x00000800, OpenGL_Version_3_0 = 0x00001000, OpenGL_Version_3_1 = 0x00002000, - OpenGL_Version_3_2 = 0x00004000 + OpenGL_Version_3_2 = 0x00004000, + OpenGL_Version_3_3 = 0x00008000, + OpenGL_Version_4_0 = 0x00010000 }; Q_DECLARE_FLAGS(OpenGLVersionFlags, OpenGLVersionFlag) diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index 44e8ae9..0a19531 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -190,7 +190,7 @@ void QGLContext::makeCurrent() if (!d->workaroundsCached) { d->workaroundsCached = true; const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); - if (strstr(renderer, "SGX") || strstr(renderer, "MBX")) { + if (renderer && (strstr(renderer, "SGX") || strstr(renderer, "MBX"))) { // PowerVR MBX/SGX chips needs to clear all buffers when starting to render // a new frame, otherwise there will be a performance penalty to pay for // each frame. @@ -200,7 +200,8 @@ void QGLContext::makeCurrent() // bug which prevents glCopyTexSubImage2D() to work with a POT // or GL_ALPHA texture bound to an FBO. The only way to // identify that driver is to check the EGL version number for it. - if (strstr(eglQueryString(d->eglContext->display(), EGL_VERSION), "1.3")) + const char *egl_version = eglQueryString(d->eglContext->display(), EGL_VERSION); + if (egl_version && strstr(egl_version, "1.3")) d->workaround_brokenFBOReadBack = true; } } diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index d92f963..1727a41 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -177,6 +177,10 @@ public: void initContext(QGLContext *context, const QGLWidget* shareWidget); bool renderCxPm(QPixmap *pixmap); void cleanupColormaps(); + void aboutToDestroy() { + if (glcx) + glcx->reset(); + } QGLContext *glcx; QGLWidgetGLPaintDevice glDevice; @@ -230,7 +234,7 @@ public: static void addShare(const QGLContext *context, const QGLContext *share); static void removeShare(const QGLContext *context); private: - QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { } + QGLContextGroup(const QGLContext *context); QGLExtensionFuncs m_extensionFuncs; const QGLContext *m_context; // context group's representative @@ -522,17 +526,33 @@ public: QSize bindCompressedTexturePVR(const char *buf, int len); }; +struct QGLTextureCacheKey { + qint64 key; + QGLContextGroup *group; +}; + +inline bool operator==(const QGLTextureCacheKey &a, const QGLTextureCacheKey &b) +{ + return a.key == b.key && a.group == b.group; +} + +inline uint qHash(const QGLTextureCacheKey &key) +{ + return qHash(key.key) ^ qHash(key.group); +} + + class Q_AUTOTEST_EXPORT QGLTextureCache { public: QGLTextureCache(); ~QGLTextureCache(); void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost); - inline void remove(quint64 key); + void remove(qint64 key); inline int size(); inline void setMaxCost(int newMax); inline int maxCost(); - inline QGLTexture* getTexture(quint64 key); + inline QGLTexture* getTexture(QGLContext *ctx, qint64 key); bool remove(QGLContext *ctx, GLuint textureId); void removeContextTextures(QGLContext *ctx); @@ -542,7 +562,7 @@ public: static void cleanupBeforePixmapDestruction(QPixmapData* pixmap); private: - QCache<qint64, QGLTexture> m_cache; + QCache<QGLTextureCacheKey, QGLTexture> m_cache; QReadWriteLock m_lock; }; @@ -563,19 +583,13 @@ int QGLTextureCache::maxCost() return m_cache.maxCost(); } -QGLTexture* QGLTextureCache::getTexture(quint64 key) +QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key) { QReadLocker locker(&m_lock); - return m_cache.object(key); -} - -void QGLTextureCache::remove(quint64 key) -{ - QWriteLocker locker(&m_lock); - m_cache.remove(key); + const QGLTextureCacheKey cacheKey = {key, QGLContextPrivate::contextGroup(ctx)}; + return m_cache.object(cacheKey); } - extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine(); bool qt_gl_preferGL2Engine(); diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index d203646..bfb232d 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -115,6 +115,20 @@ extern const QX11Info *qt_x11Info(const QPaintDevice *pd); #define GLX_FRONT_LEFT_EXT 0x20DE #endif +#ifndef GLX_ARB_create_context +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#endif + +#ifndef GLX_ARB_create_context_profile +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif + /* The qt_gl_choose_cmap function is internal and used by QGLWidget::setContext() and GLX (not Windows). If the application can't find any sharable @@ -401,6 +415,148 @@ bool QGLFormat::hasOpenGLOverlays() return trans_colors.size() > 0; } +static bool buildSpec(int* spec, const QGLFormat& f, QPaintDevice* paintDevice, + int bufDepth, bool onlyFBConfig = false) +{ + int i = 0; + spec[i++] = GLX_LEVEL; + spec[i++] = f.plane(); + const QX11Info *xinfo = qt_x11Info(paintDevice); + bool useFBConfig = onlyFBConfig; + +#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) && !defined(Q_OS_HPUX) + /* + HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions. + Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented. + */ + QWidget* widget = 0; + if (paintDevice->devType() == QInternal::Widget) + widget = static_cast<QWidget*>(paintDevice); + + // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual + if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender) + useFBConfig = true; +#endif + +#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) + static bool useTranspExt = false; + static bool useTranspExtChecked = false; + if (f.plane() && !useTranspExtChecked && paintDevice) { + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + useTranspExt = extensions.match("GLX_EXT_visual_info"); + //# (A bit simplistic; that could theoretically be a substring) + if (useTranspExt) { + QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR)); + useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround + if (useTranspExt) { + // bug workaround - some systems (eg. FireGL) refuses to return an overlay + // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specified, even if + // the implementation supports transparent overlays + int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT, + f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT, + XNone }; + XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec); + if (!vinf) { + useTranspExt = false; + } + } + } + + useTranspExtChecked = true; + } + if (f.plane() && useTranspExt && !useFBConfig) { + // Required to avoid non-transparent overlay visual(!) on some systems + spec[i++] = GLX_TRANSPARENT_TYPE_EXT; + spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT; + } +#endif + +#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) + // GLX_RENDER_TYPE is only in glx >=1.3 + if (useFBConfig) { + spec[i++] = GLX_RENDER_TYPE; + spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; + } +#endif + + if (f.doubleBuffer()) + spec[i++] = GLX_DOUBLEBUFFER; + if (useFBConfig) + spec[i++] = True; + if (f.depth()) { + spec[i++] = GLX_DEPTH_SIZE; + spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize(); + } + if (f.stereo()) { + spec[i++] = GLX_STEREO; + if (useFBConfig) + spec[i++] = True; + } + if (f.stencil()) { + spec[i++] = GLX_STENCIL_SIZE; + spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize(); + } + if (f.rgba()) { + if (!useFBConfig) + spec[i++] = GLX_RGBA; + spec[i++] = GLX_RED_SIZE; + spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize(); + spec[i++] = GLX_GREEN_SIZE; + spec[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize(); + spec[i++] = GLX_BLUE_SIZE; + spec[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize(); + if (f.alpha()) { + spec[i++] = GLX_ALPHA_SIZE; + spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize(); + } + if (f.accum()) { + spec[i++] = GLX_ACCUM_RED_SIZE; + spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); + spec[i++] = GLX_ACCUM_GREEN_SIZE; + spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); + spec[i++] = GLX_ACCUM_BLUE_SIZE; + spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); + if (f.alpha()) { + spec[i++] = GLX_ACCUM_ALPHA_SIZE; + spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); + } + } + } else { + spec[i++] = GLX_BUFFER_SIZE; + spec[i++] = bufDepth; + } + + if (f.sampleBuffers()) { + spec[i++] = GLX_SAMPLE_BUFFERS_ARB; + spec[i++] = 1; + spec[i++] = GLX_SAMPLES_ARB; + spec[i++] = f.samples() == -1 ? 4 : f.samples(); + } + +#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) + if (useFBConfig) { + spec[i++] = GLX_DRAWABLE_TYPE; + switch(paintDevice->devType()) { + case QInternal::Pixmap: + spec[i++] = GLX_PIXMAP_BIT; + break; + case QInternal::Pbuffer: + spec[i++] = GLX_PBUFFER_BIT; + break; + default: + qWarning("QGLContext: Unknown paint device type %d", paintDevice->devType()); + // Fall-through & assume it's a window + case QInternal::Widget: + spec[i++] = GLX_WINDOW_BIT; + break; + }; + } +#endif + + spec[i] = XNone; + return useFBConfig; +} + /***************************************************************************** QGLContext UNIX/GLX-specific code *****************************************************************************/ @@ -493,21 +649,85 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) shareContext = 0; } + const int major = d->reqFormat.majorVersion(); + const int minor = d->reqFormat.minorVersion(); + const int profile = d->reqFormat.profile() == QGLFormat::CompatibilityProfile + ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB + : GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + d->cx = 0; - if (shareContext) { + +#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) + /* + HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions. + Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented. + */ + if ((major == 3 && minor >= 2) || major > 3) { + QGLTemporaryContext *tmpContext = 0; + if (!QGLContext::currentContext()) + tmpContext = new QGLTemporaryContext; + + int attributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, major, + GLX_CONTEXT_MINOR_VERSION_ARB, minor, + GLX_CONTEXT_PROFILE_MASK_ARB, profile, + 0 }; + + typedef GLXContext ( * Q_PFNGLXCREATECONTEXTATTRIBSARBPROC) + (Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); + + + Q_PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = + (Q_PFNGLXCREATECONTEXTATTRIBSARBPROC) qglx_getProcAddress("glXCreateContextAttribsARB"); + + if (glXCreateContextAttribs) { + int spec[45]; + glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BUFFER_SIZE, &res); + buildSpec(spec, format(), d->paintDevice, res, true); + + GLXFBConfig *configs; + int configCount = 0; + configs = glXChooseFBConfig(disp, xinfo->screen(), spec, &configCount); + + if (configs && configCount > 0) { + d->cx = glXCreateContextAttribs(disp, configs[0], + shareContext ? (GLXContext)shareContext->d_func()->cx : 0, direct, attributes); + if (!d->cx && shareContext) { + shareContext = 0; + d->cx = glXCreateContextAttribs(disp, configs[0], 0, direct, attributes); + } + d->screen = ((XVisualInfo*)d->vi)->screen; + } + XFree(configs); + } else { + qWarning("QGLContext::chooseContext(): OpenGL %d.%d is not supported", major, minor); + } + + if (tmpContext) + delete tmpContext; + } +#else + Q_UNUSED(major); + Q_UNUSED(minor); + Q_UNUSED(profile); +#endif + + if (!d->cx && shareContext) { d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, (GLXContext)shareContext->d_func()->cx, direct); d->screen = ((XVisualInfo*)d->vi)->screen; - if (d->cx) { - QGLContext *share = const_cast<QGLContext *>(shareContext); - d->sharing = true; - share->d_func()->sharing = true; - } } if (!d->cx) { d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct); d->screen = ((XVisualInfo*)d->vi)->screen; + shareContext = 0; + } + + if (shareContext && d->cx) { + QGLContext *share = const_cast<QGLContext *>(shareContext); + d->sharing = true; + share->d_func()->sharing = true; } + if (!d->cx) return false; d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx)); @@ -606,143 +826,8 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) { Q_D(QGLContext); int spec[45]; - int i = 0; - spec[i++] = GLX_LEVEL; - spec[i++] = f.plane(); const QX11Info *xinfo = qt_x11Info(d->paintDevice); - bool useFBConfig = false; - -#if defined(GLX_VERSION_1_3) && !defined(QT_NO_XRENDER) && !defined(Q_OS_HPUX) - /* - HPUX defines GLX_VERSION_1_3 but does not implement the corresponding functions. - Specifically glXChooseFBConfig and glXGetVisualFromFBConfig are not implemented. - */ - QWidget* widget = 0; - if (d->paintDevice->devType() == QInternal::Widget) - widget = static_cast<QWidget*>(d->paintDevice); - - // Only use glXChooseFBConfig for widgets if we're trying to get an ARGB visual - if (widget && widget->testAttribute(Qt::WA_TranslucentBackground) && X11->use_xrender) - useFBConfig = true; -#endif - -#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) - static bool useTranspExt = false; - static bool useTranspExtChecked = false; - if (f.plane() && !useTranspExtChecked && d->paintDevice) { - QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); - useTranspExt = extensions.match("GLX_EXT_visual_info"); - //# (A bit simplistic; that could theoretically be a substring) - if (useTranspExt) { - QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR)); - useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround - if (useTranspExt) { - // bug workaround - some systems (eg. FireGL) refuses to return an overlay - // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specified, even if - // the implementation supports transparent overlays - int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT, - f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT, - XNone }; - XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec); - if (!vinf) { - useTranspExt = false; - } - } - } - - useTranspExtChecked = true; - } - if (f.plane() && useTranspExt && !useFBConfig) { - // Required to avoid non-transparent overlay visual(!) on some systems - spec[i++] = GLX_TRANSPARENT_TYPE_EXT; - spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT; - } -#endif - -#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) - // GLX_RENDER_TYPE is only in glx >=1.3 - if (useFBConfig) { - spec[i++] = GLX_RENDER_TYPE; - spec[i++] = f.rgba() ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; - } -#endif - - if (f.doubleBuffer()) - spec[i++] = GLX_DOUBLEBUFFER; - if (useFBConfig) - spec[i++] = True; - if (f.depth()) { - spec[i++] = GLX_DEPTH_SIZE; - spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize(); - } - if (f.stereo()) { - spec[i++] = GLX_STEREO; - if (useFBConfig) - spec[i++] = True; - } - if (f.stencil()) { - spec[i++] = GLX_STENCIL_SIZE; - spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize(); - } - if (f.rgba()) { - if (!useFBConfig) - spec[i++] = GLX_RGBA; - spec[i++] = GLX_RED_SIZE; - spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize(); - spec[i++] = GLX_GREEN_SIZE; - spec[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize(); - spec[i++] = GLX_BLUE_SIZE; - spec[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize(); - if (f.alpha()) { - spec[i++] = GLX_ALPHA_SIZE; - spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize(); - } - if (f.accum()) { - spec[i++] = GLX_ACCUM_RED_SIZE; - spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); - spec[i++] = GLX_ACCUM_GREEN_SIZE; - spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); - spec[i++] = GLX_ACCUM_BLUE_SIZE; - spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); - if (f.alpha()) { - spec[i++] = GLX_ACCUM_ALPHA_SIZE; - spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); - } - } - } else { - spec[i++] = GLX_BUFFER_SIZE; - spec[i++] = bufDepth; - } - - if (f.sampleBuffers()) { - spec[i++] = GLX_SAMPLE_BUFFERS_ARB; - spec[i++] = 1; - spec[i++] = GLX_SAMPLES_ARB; - spec[i++] = f.samples() == -1 ? 4 : f.samples(); - } - -#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) - if (useFBConfig) { - spec[i++] = GLX_DRAWABLE_TYPE; - switch(d->paintDevice->devType()) { - case QInternal::Pixmap: - spec[i++] = GLX_PIXMAP_BIT; - break; - case QInternal::Pbuffer: - spec[i++] = GLX_PBUFFER_BIT; - break; - default: - qWarning("QGLContext: Unknown paint device type %d", d->paintDevice->devType()); - // Fall-through & assume it's a window - case QInternal::Widget: - spec[i++] = GLX_WINDOW_BIT; - break; - }; - } -#endif - - spec[i] = XNone; - + bool useFBConfig = buildSpec(spec, f, d->paintDevice, bufDepth, false); XVisualInfo* chosenVisualInfo = 0; @@ -755,7 +840,7 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) if (!configs) break; // fallback to trying glXChooseVisual - for (i = 0; i < configCount; ++i) { + for (int i = 0; i < configCount; ++i) { XVisualInfo* vi; vi = glXGetVisualFromFBConfig(xinfo->display(), configs[i]); if (!vi) @@ -843,7 +928,7 @@ void QGLContext::makeCurrent() } else if (d->paintDevice->devType() == QInternal::Pbuffer) { ok = glXMakeCurrent(xinfo->display(), (GLXPbuffer)d->pbuf, (GLXContext)d->cx); } else if (d->paintDevice->devType() == QInternal::Widget) { - ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->winId(), (GLXContext)d->cx); + ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->internalWinId(), (GLXContext)d->cx); } if (!ok) qWarning("QGLContext::makeCurrent(): Failed."); @@ -1773,6 +1858,9 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, cons glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0); glBindTexture(GL_TEXTURE_2D, textureId); + GLuint filtering = (options & QGLContext::LinearFilteringBindOption) ? GL_LINEAR : GL_NEAREST; + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); if (!((hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted))) options &= ~QGLContext::InvertedYBindOption; diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 890b029..deffc20 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -1024,6 +1024,36 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const } /*! + \fn bool QGLFramebufferObject::bindDefault() + \internal + + Switches rendering back to the default, windowing system provided + framebuffer. + Returns true upon success, false otherwise. + + \sa bind(), release() +*/ +bool QGLFramebufferObject::bindDefault() +{ + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); + + if (ctx) { + bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject); + if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx))) + return false; + + ctx->d_ptr->current_fbo = ctx->d_ptr->default_fbo; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->default_fbo); +#ifdef QT_DEBUG + } else { + qWarning("QGLFramebufferObject::bindDefault() called without current context."); +#endif + } + + return ctx != 0; +} + +/*! \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects() Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h index 306b6ff..6ff6645 100644 --- a/src/opengl/qglframebufferobject.h +++ b/src/opengl/qglframebufferobject.h @@ -108,6 +108,8 @@ public: QPaintEngine *paintEngine() const; GLuint handle() const; + static bool bindDefault(); + static bool hasOpenGLFramebufferObjects(); void drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D); |