diff -r 93b982ccede2 -r 5daf16870df6 src/opengl/qgl.cpp --- a/src/opengl/qgl.cpp Mon Jun 21 22:38:13 2010 +0100 +++ b/src/opengl/qgl.cpp Thu Jul 22 16:41:55 2010 +0100 @@ -49,7 +49,7 @@ #include "private/qpixmap_x11_p.h" #define INT32 dummy_INT32 #define INT8 dummy_INT8 -#if !defined(QT_OPENGL_ES) +#ifdef QT_NO_EGL # include #endif #undef INT32 @@ -67,7 +67,7 @@ #include "qimage.h" #include "qgl_p.h" -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#if !defined(QT_OPENGL_ES_1) #include "gl2paintengineex/qpaintengineex_opengl2_p.h" #endif @@ -95,11 +95,6 @@ QT_BEGIN_NAMESPACE -#ifdef QT_OPENGL_ES_1_CL -#include "qgl_cl_p.h" -#endif - - #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs; #endif @@ -226,6 +221,9 @@ \value DirectRendering Specifies that the context is used for direct rendering to a display. \value HasOverlay Enables the use of an overlay. \value SampleBuffers Enables the use of sample buffers. + \value DeprecatedFunctions Enables the use of deprecated functionality for OpenGL 3.x + contexts. A context with deprecated functionality enabled is + called a full context in the OpenGL specification. \value SingleBuffer Specifies the use of a single buffer, as opposed to double buffers. \value NoDepthBuffer Disables the use of a depth buffer. \value ColorIndex Specifies that the context should use a color index as its pixel format. @@ -236,6 +234,9 @@ \value IndirectRendering Specifies that the context is used for indirect rendering to a buffer. \value NoOverlay Disables the use of an overlay. \value NoSampleBuffers Disables the use of sample buffers. + \value NoDeprecatedFunctions Disables the use of deprecated functionality for OpenGL 3.x + contexts. A context with deprecated functionality disabled is + called a forward compatible context in the OpenGL specification. \sa {Sample Buffers Example} */ @@ -765,6 +766,7 @@ return; } d->numSamples = numSamples; + setSampleBuffers(numSamples > 0); } /*! @@ -903,6 +905,7 @@ return; } d->depthSize = size; + setDepth(size > 0); } /*! @@ -1016,7 +1019,7 @@ return; } d->alphaSize = size; - setOption(QGL::AlphaChannel); + setAlpha(size > 0); } /*! @@ -1043,6 +1046,7 @@ return; } d->accumSize = size; + setAccum(size > 0); } /*! @@ -1068,6 +1072,7 @@ return; } d->stencilSize = size; + setStencil(size > 0); } /*! @@ -1081,6 +1086,90 @@ } /*! + \since 4.7 + + Set the OpenGL version to the \a major and \a minor numbers. If a + context compatible with the requested OpenGL version cannot be + created, a context compatible with version 1.x is created instead. + + \sa majorVersion(), minorVersion() +*/ +void QGLFormat::setVersion(int major, int minor) +{ + if (major < 1 || minor < 0) { + qWarning("QGLFormat::setVersion: Cannot set zero or negative version number %d.%d", major, minor); + return; + } + detach(); + d->majorVersion = major; + d->minorVersion = minor; +} + +/*! + \since 4.7 + + Returns the OpenGL major version. + + \sa setVersion(), minorVersion() +*/ +int QGLFormat::majorVersion() const +{ + return d->majorVersion; +} + +/*! + \since 4.7 + + Returns the OpenGL minor version. + + \sa setVersion(), majorVersion() +*/ +int QGLFormat::minorVersion() const +{ + return d->minorVersion; +} + +/*! + \enum QGLFormat::OpenGLContextProfile + \since 4.7 + + This enum describes the OpenGL context profiles that can be + specified for contexts implementing OpenGL version 3.2 or + higher. These profiles are different from OpenGL ES profiles. + + \value NoProfile OpenGL version is lower than 3.2. + \value CoreProfile Functionality deprecated in OpenGL version 3.0 is not available. + \value CompatibilityProfile Functionality from earlier OpenGL versions is available. +*/ + +/*! + \since 4.7 + + Set the OpenGL context profile to \a profile. The \a profile is + ignored if the requested OpenGL version is less than 3.2. + + \sa profile() +*/ +void QGLFormat::setProfile(OpenGLContextProfile profile) +{ + detach(); + d->profile = profile; +} + +/*! + \since 4.7 + + Returns the OpenGL context profile. + + \sa setProfile() +*/ +QGLFormat::OpenGLContextProfile QGLFormat::profile() const +{ + return d->profile; +} + + +/*! \fn bool QGLFormat::hasOpenGL() Returns true if the window system has any OpenGL support; @@ -1116,25 +1205,21 @@ if (parts[2].startsWith(QLatin1String("1.1"))) versionFlags |= QGLFormat::OpenGL_ES_Common_Version_1_1 | QGLFormat::OpenGL_ES_CommonLite_Version_1_1; - } - else { + } else { // Not -CM, must be CL, CommonLite versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_0; if (parts[2].startsWith(QLatin1String("1.1"))) versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_1; } - } - else { + } else { // OpenGL ES version 2.0 or higher versionFlags |= QGLFormat::OpenGL_ES_Version_2_0; } - } - else { + } else { // if < 3 parts to the name, it is an unrecognised OpenGL ES qWarning("Unrecognised OpenGL ES version"); } - } - else { + } else { // not ES, regular OpenGL, the version numbers are first in the string if (versionString.startsWith(QLatin1String("1."))) { switch (versionString[2].toAscii()) { @@ -1151,30 +1236,48 @@ default: break; } - } - else if (versionString.startsWith(QLatin1String("2."))) { + } else if (versionString.startsWith(QLatin1String("2."))) { 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; - QString minorVersion = versionString.section(QLatin1Char(' '), 0, 0).section(QLatin1Char('.'), 1, 1); - if (minorVersion == QChar(QLatin1Char('1'))) + if (versionString[2].toAscii() == '1') versionFlags |= QGLFormat::OpenGL_Version_2_1; + } else if (versionString.startsWith(QLatin1String("3."))) { + 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; + switch (versionString[2].toAscii()) { + case '2': + versionFlags |= QGLFormat::OpenGL_Version_3_2; + case '1': + versionFlags |= QGLFormat::OpenGL_Version_3_1; + case '0': + break; + default: + versionFlags |= QGLFormat::OpenGL_Version_3_1 | + QGLFormat::OpenGL_Version_3_2; + break; + } + } else { + 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; } - else if (versionString.startsWith(QLatin1String("3."))) { - 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; - } - else - qWarning("Unrecognised OpenGL version"); } return versionFlags; } @@ -1206,6 +1309,12 @@ \value OpenGL_Version_3_0 OpenGL version 3.0 or higher is present. + \value OpenGL_Version_3_1 OpenGL version 3.1 or higher is present. + Note that OpenGL version 3.1 or higher does not necessarily support all the features of + version 3.0 and lower. + + \value OpenGL_Version_3_2 OpenGL version 3.2 or higher is present. + \value OpenGL_ES_CommonLite_Version_1_0 OpenGL ES version 1.0 Common Lite or higher is present. \value OpenGL_ES_Common_Version_1_0 OpenGL ES version 1.0 Common or higher is present. @@ -1377,14 +1486,20 @@ bool operator==(const QGLFormat& a, const QGLFormat& b) { - return (int) a.d->opts == (int) b.d->opts && a.d->pln == b.d->pln && a.d->alphaSize == b.d->alphaSize - && a.d->accumSize == b.d->accumSize && a.d->stencilSize == b.d->stencilSize + return (a.d == b.d) || ((int) a.d->opts == (int) b.d->opts + && a.d->pln == b.d->pln + && a.d->alphaSize == b.d->alphaSize + && a.d->accumSize == b.d->accumSize + && a.d->stencilSize == b.d->stencilSize && a.d->depthSize == b.d->depthSize && a.d->redSize == b.d->redSize && a.d->greenSize == b.d->greenSize && a.d->blueSize == b.d->blueSize && a.d->numSamples == b.d->numSamples - && a.d->swapInterval == b.d->swapInterval; + && a.d->swapInterval == b.d->swapInterval + && a.d->majorVersion == b.d->majorVersion + && a.d->minorVersion == b.d->minorVersion + && a.d->profile == b.d->profile); } @@ -1480,7 +1595,8 @@ # endif vi = 0; #endif -#if defined(QT_OPENGL_ES) +#ifndef QT_NO_EGL + ownsEglContext = false; eglContext = 0; eglSurface = EGL_NO_SURFACE; #endif @@ -1496,6 +1612,9 @@ current_fbo = 0; default_fbo = 0; active_engine = 0; + workaround_needsFullClearOnEveryFrame = false; + workaround_brokenFBOReadBack = false; + workaroundsCached = false; for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) vertexAttributeArraysEnabledState[i] = false; } @@ -1534,7 +1653,14 @@ uint *q = (uint*)img.scanLine(y); for (int x=0; x < w; ++x) { const uint pixel = *q; - *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00); + if (alpha_format && include_alpha) { + *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) + | (pixel & 0xff00ff00); + } else { + *q = 0xff000000 | ((pixel << 16) & 0xff0000) + | ((pixel >> 16) & 0xff) | (pixel & 0x00ff00); + } + q++; } } @@ -1545,7 +1671,8 @@ QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) { - QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32); + QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32 + : QImage::Format_RGB32); int w = size.width(); int h = size.height(); glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); @@ -1558,7 +1685,7 @@ QImage img(size, alpha_format ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32); int w = size.width(); int h = size.height(); -#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_1) //### glGetTexImage not in GL ES 2.0, need to do something else here! glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); #endif @@ -1586,14 +1713,12 @@ extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64; extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64; -static QGLTextureCache *qt_gl_texture_cache = 0; + +Q_GLOBAL_STATIC(QGLTextureCache, qt_gl_texture_cache) QGLTextureCache::QGLTextureCache() : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though { - Q_ASSERT(qt_gl_texture_cache == 0); - qt_gl_texture_cache = this; - QImagePixmapCleanupHooks::instance()->addPixmapDataModificationHook(cleanupTexturesForPixampData); QImagePixmapCleanupHooks::instance()->addPixmapDataDestructionHook(cleanupBeforePixmapDestruction); QImagePixmapCleanupHooks::instance()->addImageHook(cleanupTexturesForCacheKey); @@ -1601,8 +1726,6 @@ QGLTextureCache::~QGLTextureCache() { - qt_gl_texture_cache = 0; - QImagePixmapCleanupHooks::instance()->removePixmapDataModificationHook(cleanupTexturesForPixampData); QImagePixmapCleanupHooks::instance()->removePixmapDataDestructionHook(cleanupBeforePixmapDestruction); QImagePixmapCleanupHooks::instance()->removeImageHook(cleanupTexturesForCacheKey); @@ -1610,6 +1733,7 @@ void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost) { + QWriteLocker locker(&m_lock); if (m_cache.totalCost() + cost > m_cache.maxCost()) { // the cache is full - make an attempt to remove something const QList keys = m_cache.keys(); @@ -1627,6 +1751,7 @@ bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) { + QWriteLocker locker(&m_lock); QList keys = m_cache.keys(); for (int i = 0; i < keys.size(); ++i) { QGLTexture *tex = m_cache.object(keys.at(i)); @@ -1641,6 +1766,7 @@ void QGLTextureCache::removeContextTextures(QGLContext* ctx) { + QWriteLocker locker(&m_lock); QList keys = m_cache.keys(); for (int i = 0; i < keys.size(); ++i) { const qint64 &key = keys.at(i); @@ -1649,25 +1775,14 @@ } } -QGLTextureCache* QGLTextureCache::instance() -{ - if (!qt_gl_texture_cache) - qt_gl_texture_cache = new QGLTextureCache; - - return qt_gl_texture_cache; -} - /* a hook that removes textures from the cache when a pixmap/image is deref'ed */ void QGLTextureCache::cleanupTexturesForCacheKey(qint64 cacheKey) { - // ### remove when the GL texture cache becomes thread-safe - if (qApp->thread() == QThread::currentThread()) { - instance()->remove(cacheKey); - Q_ASSERT(instance()->getTexture(cacheKey) == 0); - } + qt_gl_texture_cache()->remove(cacheKey); + Q_ASSERT(qt_gl_texture_cache()->getTexture(cacheKey) == 0); } @@ -1689,10 +1804,9 @@ #endif } -void QGLTextureCache::deleteIfEmpty() -{ - if (instance()->size() == 0) - delete instance(); +QGLTextureCache *QGLTextureCache::instance() +{ + return qt_gl_texture_cache(); } // DDS format structure @@ -1858,7 +1972,6 @@ { // remove any textures cached in this context QGLTextureCache::instance()->removeContextTextures(this); - QGLTextureCache::deleteIfEmpty(); // ### thread safety d_ptr->group->cleanupResources(this); @@ -2118,8 +2231,8 @@ Q_Q(QGLContext); #ifdef QGL_BIND_TEXTURE_DEBUG - printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), internalFormat =0x%x, options=%x\n", - image.width(), image.height(), internalFormat, int(options)); + printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), internalFormat =0x%x, options=%x, key=%llx\n", + image.width(), image.height(), internalFormat, int(options), key); QTime time; time.start(); #endif @@ -2290,7 +2403,7 @@ #ifndef QT_NO_DEBUG GLenum error = glGetError(); if (error != GL_NO_ERROR) { - qWarning(" - texture upload failed, error code 0x%x\n", error); + qWarning(" - texture upload failed, error code 0x%x, enum: %d (%x)\n", error, target, target); } #endif @@ -2327,7 +2440,7 @@ { Q_Q(QGLContext); QPixmapData *pd = pixmap.pixmapData(); -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#if !defined(QT_OPENGL_ES_1) if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) { const QGLPixmapData *data = static_cast(pd); @@ -2352,9 +2465,10 @@ // Try to use texture_from_pixmap const QX11Info *xinfo = qt_x11Info(paintDevice); if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType - && xinfo && xinfo->screen() == pixmap.x11Info().screen()) + && xinfo && xinfo->screen() == pixmap.x11Info().screen() + && target == GL_TEXTURE_2D) { - texture = bindTextureFromNativePixmap(pd, key, options); + texture = bindTextureFromNativePixmap(const_cast(&pixmap), key, options); if (texture) { texture->options |= QGLContext::MemoryManagedBindOption; texture->boundPixmap = pd; @@ -2363,8 +2477,15 @@ } #endif - if (!texture) - texture = bindTexture(pixmap.toImage(), target, format, key, options); + if (!texture) { + QImage image = pixmap.toImage(); + // If the system depth is 16 and the pixmap doesn't have an alpha channel + // then we convert it to RGB16 in the hope that it gets uploaded as a 16 + // bit texture which is much faster to access than a 32-bit one. + if (pixmap.depth() == 16 && !image.hasAlphaChannel() ) + image = image.convertToFormat(QImage::Format_RGB16); + texture = bindTexture(image, target, format, key, options); + } // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null Q_ASSERT(texture); @@ -2457,7 +2578,7 @@ return 0; Q_D(QGLContext); - QGLTexture *texture = d->bindTexture(image, target, format, false, options); + QGLTexture *texture = d->bindTexture(image, target, format, options); return texture->id; } @@ -2469,7 +2590,7 @@ return 0; Q_D(QGLContext); - QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption); + QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), DefaultBindOption); return texture->id; } @@ -2481,7 +2602,7 @@ return 0; Q_D(QGLContext); - QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options); + QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), options); return texture->id; } #endif @@ -2579,41 +2700,41 @@ } #endif -void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) +void qt_add_rect_to_array(const QRectF &r, GLfloat *array) { qreal left = r.left(); qreal right = r.right(); qreal top = r.top(); qreal bottom = r.bottom(); - array[0] = f2vt(left); - array[1] = f2vt(top); - array[2] = f2vt(right); - array[3] = f2vt(top); - array[4] = f2vt(right); - array[5] = f2vt(bottom); - array[6] = f2vt(left); - array[7] = f2vt(bottom); -} - -void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array) -{ - array[0] = f2vt(x1); - array[1] = f2vt(y1); - array[2] = f2vt(x2); - array[3] = f2vt(y1); - array[4] = f2vt(x2); - array[5] = f2vt(y2); - array[6] = f2vt(x1); - array[7] = f2vt(y2); + array[0] = left; + array[1] = top; + array[2] = right; + array[3] = top; + array[4] = right; + array[5] = bottom; + array[6] = left; + array[7] = bottom; +} + +void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, GLfloat *array) +{ + array[0] = x1; + array[1] = y1; + array[2] = x2; + array[3] = y1; + array[4] = x2; + array[5] = y2; + array[6] = x1; + array[7] = y2; } #if !defined(QT_OPENGL_ES_2) static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget) { - q_vertexType tx = f2vt(1); - q_vertexType ty = f2vt(1); + GLfloat tx = 1.0f; + GLfloat ty = 1.0f; #ifdef QT_OPENGL_ES Q_UNUSED(textureWidth); @@ -2626,20 +2747,20 @@ glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight); } - tx = f2vt(textureWidth); - ty = f2vt(textureHeight); + tx = GLfloat(textureWidth); + ty = GLfloat(textureHeight); } #endif - q_vertexType texCoordArray[4*2] = { + GLfloat texCoordArray[4*2] = { 0, ty, tx, ty, tx, 0, 0, 0 }; - q_vertexType vertexArray[4*2]; + GLfloat vertexArray[4*2]; qt_add_rect_to_array(target, vertexArray); - glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray); - glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray); + glVertexPointer(2, GL_FLOAT, 0, vertexArray); + glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -2654,14 +2775,38 @@ /*! \since 4.4 - Draws the given texture, \a textureId, to the given target rectangle, - \a target, in OpenGL model space. The \a textureTarget should be a 2D - texture target. - - \note This function is not supported under OpenGL/ES 2.0. + This function supports the following use cases: + + \list + \i On OpenGL and OpenGL ES 1.x it draws the given texture, \a textureId, + to the given target rectangle, \a target, in OpenGL model space. The + \a textureTarget should be a 2D texture target. + \i On OpenGL and OpenGL ES 2.x, if a painter is active, not inside a + beginNativePainting / endNativePainting block, and uses the + engine with type QPaintEngine::OpenGL2, the function will draw the given + texture, \a textureId, to the given target rectangle, \a target, + respecting the current painter state. This will let you draw a texture + with the clip, transform, render hints, and composition mode set by the + painter. Note that the texture target needs to be GL_TEXTURE_2D for this + use case, and that this is the only supported use case under OpenGL ES 2.x. + \endlist + */ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) { +#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2) + if (d_ptr->active_engine && + d_ptr->active_engine->type() == QPaintEngine::OpenGL2) { + QGL2PaintEngineEx *eng = static_cast(d_ptr->active_engine); + if (!eng->isNativePaintingActive()) { + QRectF src(0, 0, target.width(), target.height()); + QSize size(target.width(), target.height()); + if (eng->drawTexture(target, textureId, size, src)) + return; + } + } +#endif + #ifndef QT_OPENGL_ES_2 #ifdef QT_OPENGL_ES if (textureTarget != GL_TEXTURE_2D) { @@ -2690,7 +2835,7 @@ Q_UNUSED(target); Q_UNUSED(textureId); Q_UNUSED(textureTarget); - qWarning("drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES/2.0"); + qWarning("drawTexture() with OpenGL ES 2.0 requires an active OpenGL2 paint engine"); #endif } @@ -2705,20 +2850,33 @@ /*! \since 4.4 - Draws the given texture at the given \a point in OpenGL model - space. The \a textureTarget should be a 2D texture target. - - \note This function is not supported under OpenGL/ES. + This function supports the following use cases: + + \list + \i By default it draws the given texture, \a textureId, + at the given \a point in OpenGL model space. The + \a textureTarget should be a 2D texture target. + \i If a painter is active, not inside a + beginNativePainting / endNativePainting block, and uses the + engine with type QPaintEngine::OpenGL2, the function will draw the given + texture, \a textureId, at the given \a point, + respecting the current painter state. This will let you draw a texture + with the clip, transform, render hints, and composition mode set by the + painter. Note that the texture target needs to be GL_TEXTURE_2D for this + use case. + \endlist + + \note This function is not supported under any version of OpenGL ES. */ void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) { - // this would be ok on OpenGL ES 2.0, but currently we don't have a define for that #ifdef QT_OPENGL_ES Q_UNUSED(point); Q_UNUSED(textureId); Q_UNUSED(textureTarget); qWarning("drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES, use rect version instead"); #else + const bool wasEnabled = glIsEnabled(GL_TEXTURE_2D); GLint oldTexture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture); @@ -2732,6 +2890,18 @@ glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth); glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight); + if (d_ptr->active_engine && + d_ptr->active_engine->type() == QPaintEngine::OpenGL2) { + QGL2PaintEngineEx *eng = static_cast(d_ptr->active_engine); + if (!eng->isNativePaintingActive()) { + QRectF dest(point, QSizeF(textureWidth, textureHeight)); + QRectF src(0, 0, textureWidth, textureHeight); + QSize size(textureWidth, textureHeight); + if (eng->drawTexture(dest, textureId, size, src)) + return; + } + } + qDrawTextureRect(QRectF(point, QSizeF(textureWidth, textureHeight)), textureWidth, textureHeight, textureTarget); if (!wasEnabled) @@ -3192,6 +3362,7 @@ */ + /***************************************************************************** QGLWidget implementation *****************************************************************************/ @@ -3312,6 +3483,15 @@ One approach to doing this is shown in the \l{Overpainting Example}{Overpainting} example. + \section1 Threading + + It is possible to render into a QGLWidget from another thread, but it + requires that all access to the GL context is safe guarded. The Qt GUI + thread will try to use the context in resizeEvent and paintEvent, so in + order for threaded rendering using a GL widget to work, these functions + need to be intercepted in the GUI thread and handled accordingly in the + application. + \e{OpenGL is a trademark of Silicon Graphics, Inc. in the United States and other countries.} @@ -3842,7 +4022,7 @@ } } -#if defined(QT_OPENGL_ES) +#ifndef QT_NO_EGL // A re-parent is likely to destroy the X11 window and re-create it. It is important // that we free the EGL surface _before_ the winID changes - otherwise we can leak. if (e->type() == QEvent::ParentAboutToChange) @@ -3851,7 +4031,7 @@ if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) { // The window may have been re-created during re-parent or state change - if so, the EGL // surface will need to be re-created. - d->recreateEglSurface(false); + d->recreateEglSurface(); } #endif #elif defined(Q_WS_WIN) @@ -4757,11 +4937,8 @@ /*! \since 4.4 - Draws the given texture, \a textureId to the given target rectangle, - \a target, in OpenGL model space. The \a textureTarget should be a 2D - texture target. - - Equivalent to the corresponding QGLContext::drawTexture(). + Calls the corresponding QGLContext::drawTexture() on + this widget's context. */ void QGLWidget::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) { @@ -4781,10 +4958,8 @@ /*! \since 4.4 - Draws the given texture, \a textureId, at the given \a point in OpenGL - model space. The \a textureTarget should be a 2D texture target. - - Equivalent to the corresponding QGLContext::drawTexture(). + Calls the corresponding QGLContext::drawTexture() on + this widget's context. */ void QGLWidget::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) { @@ -4801,7 +4976,7 @@ } #endif -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#ifndef QT_OPENGL_ES_1 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine) #endif @@ -4811,7 +4986,7 @@ Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine() { -#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) +#if defined(QT_OPENGL_ES_1) return qt_gl_engine(); #elif defined(QT_OPENGL_ES_2) return qt_gl_2_engine(); @@ -4934,7 +5109,7 @@ glExtensions |= GenerateMipmap; glExtensions |= FragmentShader; #endif -#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) +#if defined(QT_OPENGL_ES_1) if (extensions.match("GL_OES_framebuffer_object")) glExtensions |= FramebufferObject; #endif @@ -4960,6 +5135,20 @@ return glExtensions; } + +class QGLDefaultExtensions +{ +public: + QGLDefaultExtensions() { + QGLTemporaryContext tempContext; + extensions = QGLExtensions::currentContextExtensions(); + } + + QGLExtensions::Extensions extensions; +}; + +Q_GLOBAL_STATIC(QGLDefaultExtensions, qtDefaultExtensions) + /* Returns the GL extensions for the current QGLContext. If there is no current QGLContext, a default context will be created and the extensions @@ -4967,34 +5156,19 @@ */ QGLExtensions::Extensions QGLExtensions::glExtensions() { - QGLTemporaryContext *tmpContext = 0; - static bool cachedDefault = false; - static Extensions defaultExtensions = 0; + Extensions extensionFlags = 0; QGLContext *currentCtx = const_cast(QGLContext::currentContext()); if (currentCtx && currentCtx->d_func()->extension_flags_cached) return currentCtx->d_func()->extension_flags; if (!currentCtx) { - if (cachedDefault) { - return defaultExtensions; - } else { - tmpContext = new QGLTemporaryContext; - cachedDefault = true; - } - } - - Extensions extensionFlags = currentContextExtensions(); - if (currentCtx) { + extensionFlags = qtDefaultExtensions()->extensions; + } else { + extensionFlags = currentContextExtensions(); currentCtx->d_func()->extension_flags_cached = true; currentCtx->d_func()->extension_flags = extensionFlags; - } else { - defaultExtensions = extensionFlags; } - - if (tmpContext) - delete tmpContext; - return extensionFlags; } @@ -5029,11 +5203,17 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name() { if (qt_gl_lib_name()->isNull()) { -#if defined(Q_WS_X11) || defined(Q_WS_QWS) +#ifdef Q_WS_MAC + return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"); +#else +# if defined(QT_OPENGL_ES_1) + return QLatin1String("GLES_CM"); +# elif defined(QT_OPENGL_ES_2) + return QLatin1String("GLESv2"); +# else return QLatin1String("GL"); -#else // Q_WS_MAC - return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"); -#endif +# endif +#endif // defined Q_WS_MAC } return *qt_gl_lib_name(); }