diff options
author | David Boddie <dboddie@trolltech.com> | 2009-08-27 11:44:36 (GMT) |
---|---|---|
committer | David Boddie <dboddie@trolltech.com> | 2009-08-27 11:44:36 (GMT) |
commit | 6f9e2fb5cb496b826cb41a8127dd57e58d6c5103 (patch) | |
tree | 5cff842e7d7aa639c5a7228af527ac89e4487619 /src/opengl | |
parent | c4279ec239e03c8f23bc73416291ad087cc36c4c (diff) | |
parent | f60fedcb490f31576665194153f871eabaf20617 (diff) | |
download | Qt-6f9e2fb5cb496b826cb41a8127dd57e58d6c5103.zip Qt-6f9e2fb5cb496b826cb41a8127dd57e58d6c5103.tar.gz Qt-6f9e2fb5cb496b826cb41a8127dd57e58d6c5103.tar.bz2 |
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt into 4.6
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 16 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 282 | ||||
-rw-r--r-- | src/opengl/qgl.h | 33 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 33 | ||||
-rw-r--r-- | src/opengl/qgl_x11.cpp | 12 | ||||
-rw-r--r-- | src/opengl/qglextensions_p.h | 8 | ||||
-rw-r--r-- | src/opengl/qglpixmapfilter.cpp | 2 | ||||
-rw-r--r-- | src/opengl/qglshaderprogram.cpp | 86 | ||||
-rw-r--r-- | src/opengl/qglshaderprogram.h | 20 | ||||
-rw-r--r-- | src/opengl/qpaintengine_opengl.cpp | 8 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl.cpp | 2 |
11 files changed, 353 insertions, 149 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 2f565cf..cc9b014 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -385,7 +385,7 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() QImage texImage = qt_imageForBrush(style, false); glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); - ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true); + ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true, QGLContext::InternalBindOption); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); } else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { @@ -411,8 +411,7 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() const QPixmap& texPixmap = currentBrush->texture(); glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); - // TODO: Support y-inverted pixmaps as brushes - ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true); + ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); } brushTextureDirty = false; @@ -668,7 +667,7 @@ void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& s GLfloat dx = 1.0 / textureSize.width(); GLfloat dy = 1.0 / textureSize.height(); - QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); + QGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy); setCoords(staticVertexCoordinateArray, dest); setCoords(staticTextureCoordinateArray, srcTextureRect); @@ -1104,10 +1103,11 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c QGLContext *ctx = d->ctx; glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true, true); + QGLTexture *texture = + ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); - GLfloat top = texture->yInverted ? (pixmap.height() - src.top()) : src.top(); - GLfloat bottom = texture->yInverted ? (pixmap.height() - src.bottom()) : src.bottom(); + GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top(); + GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom(); QGLRect srcRect(src.left(), top, src.right(), bottom); bool isBitmap = pixmap.isQBitmap(); @@ -1127,7 +1127,7 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QGLContext *ctx = d->ctx; glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); + QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); GLuint id = texture->id; d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 57ef70c..02991d9 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1443,7 +1443,7 @@ bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) for (int i = 0; i < keys.size(); ++i) { QGLTexture *tex = m_cache.object(keys.at(i)); if (tex->id == textureId && tex->context == ctx) { - tex->clean = true; // forces a glDeleteTextures() call + tex->options |= QGLContext::MemoryManagedBindOption; // forces a glDeleteTextures() call m_cache.remove(keys.at(i)); return true; } @@ -1479,7 +1479,7 @@ void QGLTextureCache::imageCleanupHook(qint64 cacheKey) if (qApp->thread() != QThread::currentThread()) return; QGLTexture *texture = instance()->getTexture(cacheKey); - if (texture && texture->clean) + if (texture && texture->options & QGLContext::MemoryManagedBindOption) instance()->remove(cacheKey); } @@ -1490,7 +1490,7 @@ void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap) if (qApp->thread() == QThread::currentThread()) { const qint64 cacheKey = pixmap->cacheKey(); QGLTexture *texture = instance()->getTexture(cacheKey); - if (texture && texture->clean) + if (texture && texture->options & QGLContext::MemoryManagedBindOption) instance()->remove(cacheKey); } #if defined(Q_WS_X11) @@ -1578,6 +1578,39 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg() Please note that QGLContext is not thread safe. */ +/*! + \enum QGLContext::BindOption + A set of options to decide how to bind a texture using bindTexture(). + + \value NoBindOption Don't do anything, pass the texture straight + thru. + + \value InvertedYBindOption Specifies that the texture should be flipped + over the X axis so that the texture coordinate 0,0 corresponds to + the top left corner. Inverting the texture implies a deep copy + prior to upload. + + \value MipmapBindOption Specifies that bindTexture should try + to generate mipmaps. If the GL implementation supports the \c + GL_SGIS_generate_mipmap extension, mipmaps will be automatically + generated for the texture. Mipmap generation is only supported for + the \c GL_TEXTURE_2D target. + + \value PremultipliedAlphaBindOption Specifies that the image should be + uploaded with premultiplied alpha and does a conversion accordingly. + + \value LinearFilteringBindOption Specifies that the texture filtering + should be set to GL_LINEAR. Default is GL_NEAREST. If mipmap is + also enabled, filtering will be set to GL_LINEAR_MIPMAP_LINEAR. + + \value DefaultBindOption In Qt 4.5 and earlier, bindTexture() + would mirror the image and automatically generate mipmaps. This + option helps preserve this default behavior. + + \omitvalue MemoryManagedBindOption + + \omitvalue InternalBindOption +*/ /*! \obsolete @@ -1880,7 +1913,8 @@ QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_prem } /*! \internal */ -QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean) +QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, + QGLContext::BindOptions options) { const qint64 key = image.cacheKey(); QGLTexture *texture = textureCacheLookup(key, target); @@ -1890,7 +1924,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G } if (!texture) - texture = bindTexture(image, target, format, key, clean); + texture = bindTexture(image, target, format, key, options); // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null Q_ASSERT(texture); @@ -1900,68 +1934,128 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G return texture; } +// #define QGL_BIND_TEXTURE_DEBUG + QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, - const qint64 key, bool clean) + const qint64 key, QGLContext::BindOptions options) { Q_Q(QGLContext); - QGLContext *ctx = q; - - // the GL_BGRA format is only present in GL version >= 1.2 - GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2) - ? GL_BGRA : GL_RGBA; +#ifdef QGL_BIND_TEXTURE_DEBUG + printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), format=%x, options=%x\n", + image.width(), image.height(), format, int(options)); +#endif // Scale the pixmap if needed. GL textures needs to have the // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL // 2.0 or use the GL_TEXTURE_RECTANGLE texture target int tx_w = qt_next_power_of_two(image.width()); int tx_h = qt_next_power_of_two(image.height()); - bool scale = false; QImage img = image; if (( !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) ) && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height()))) { - scale = true; + img = img.scaled(tx_w, tx_h); +#ifdef QGL_BIND_TEXTURE_DEBUG + printf(" - upscaled to %dx%d\n", tx_w, tx_h); +#endif } + GLuint filtering = options & QGLContext::LinearFilteringBindOption ? GL_LINEAR : GL_NEAREST; + GLuint tx_id; glGenTextures(1, &tx_id); glBindTexture(target, tx_id); - glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, filtering); + if (glFormat.directRendering() && QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap - && target == GL_TEXTURE_2D && !clean) + && target == GL_TEXTURE_2D + && options & QGLContext::MipmapBindOption) { +#ifdef QGL_BIND_TEXTURE_DEBUG + printf(" - generating mipmaps\n"); +#endif glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); #ifndef QT_OPENGL_ES glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); #else glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); #endif - glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, options & QGLContext::LinearFilteringBindOption + ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST); } else { - glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, filtering); } QImage::Format target_format = img.format(); - // Note: the clean param is only true when a texture is bound - // from the QOpenGLPaintEngine - in that case we have to force - // a premultiplied texture format - if (clean || img.format() != QImage::Format_ARGB32) - target_format = QImage::Format_ARGB32_Premultiplied; - if (img.format() != target_format) - img = img.convertToFormat(target_format); + bool premul = options & QGLContext::PremultipliedAlphaBindOption; + GLenum texture_format = QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2 + ? GL_BGRA : GL_RGBA; + GLuint pixel_type = GL_UNSIGNED_BYTE; + + switch (target_format) { + case QImage::Format_ARGB32: + if (premul) { + img = img.convertToFormat(target_format = QImage::Format_ARGB32_Premultiplied); +#ifdef QGL_BIND_TEXTURE_DEBUG + printf(" - converting ARGB32 -> ARGB32_Premultiplied \n"); +#endif + } + break; + case QImage::Format_ARGB32_Premultiplied: + if (!premul) { + img = img.convertToFormat(target_format = QImage::Format_ARGB32); +#ifdef QGL_BIND_TEXTURE_DEBUG + printf(" - converting ARGB32_Premultiplied -> ARGB32\n"); +#endif + } + break; + case QImage::Format_RGB16: + pixel_type = GL_UNSIGNED_SHORT_5_6_5; + texture_format = GL_RGB; + break; + case QImage::Format_RGB32: + if (format == GL_RGBA) + format = GL_RGB; + break; + + default: + if (img.hasAlphaChannel()) { + img = img.convertToFormat(premul + ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_ARGB32); +#ifdef QGL_BIND_TEXTURE_DEBUG + printf(" - converting to 32-bit alpha format\n"); +#endif + } else { + img = img.convertToFormat(QImage::Format_RGB32); +#ifdef QGL_BIND_TEXTURE_DEBUG + printf(" - converting to 32-bit\n"); +#endif + } + } + + if (options & QGLContext::InvertedYBindOption) { + int ipl = img.bytesPerLine() / 4; + int h = img.height(); + for (int y=0; y<h/2; ++y) { + int *a = (int *) img.scanLine(y); + int *b = (int *) img.scanLine(h - y - 1); + for (int x=0; x<ipl; ++x) + qSwap(a[x], b[x]); + } + } - QImage tx(scale ? QSize(tx_w, tx_h) : img.size(), target_format); - convertToGLFormatHelper(tx, img, texture_format); - glTexImage2D(target, 0, format, tx.width(), tx.height(), 0, texture_format, - GL_UNSIGNED_BYTE, tx.bits()); + const QImage &constRef = img; // to avoid detach in bits()... + glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format, + pixel_type, constRef.bits()); // this assumes the size of a texture is always smaller than the max cache size int cost = img.width()*img.height()*4/1024; - QGLTexture *texture = new QGLTexture(q, tx_id, target, clean, false); + QGLTexture *texture = new QGLTexture(q, tx_id, target, options); QGLTextureCache::instance()->insert(q, key, texture, cost); return texture; } @@ -1980,7 +2074,7 @@ QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum targe /*! \internal */ -QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert) +QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options) { Q_Q(QGLContext); QPixmapData *pd = pixmap.pixmapData(); @@ -2005,9 +2099,9 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, #if defined(Q_WS_X11) // Try to use texture_from_pixmap if (pd->classId() == QPixmapData::X11Class) { - texture = bindTextureFromNativePixmap(pd, key, canInvert); + texture = bindTextureFromNativePixmap(pd, key, options); if (texture) { - texture->clean = clean; + texture->options |= QGLContext::MemoryManagedBindOption; texture->boundPixmap = pd; boundPixmaps.insert(pd, QPixmap(pixmap)); } @@ -2015,7 +2109,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, #endif if (!texture) - texture = bindTexture(pixmap.toImage(), target, format, key, clean); + texture = bindTexture(pixmap.toImage(), target, format, key, options); // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null Q_ASSERT(texture); @@ -2061,6 +2155,20 @@ int QGLContextPrivate::maxTextureSize() } /*! + Generates and binds a 2D GL texture to the current context, based + on \a image. The generated texture id is returned and can be used in + later \c glBindTexture() calls. + + \overload +*/ +GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) +{ + Q_D(QGLContext); + QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption); + return texture->id; +} + +/*! Generates and binds a 2D GL texture to the current context, based on \a image. The generated texture id is returned and can be used in later \c glBindTexture() calls. @@ -2069,12 +2177,7 @@ int QGLContextPrivate::maxTextureSize() target is \c GL_TEXTURE_2D. The \a format parameter sets the internal format for the - texture. The default format is \c GL_RGBA8. - - If the GL implementation supports the \c GL_SGIS_generate_mipmap - extension, mipmaps will be automatically generated for the - texture. Mipmap generation is only supported for the \c - GL_TEXTURE_2D target. + texture. The default format is \c GL_RGBA. The texture that is generated is cached, so multiple calls to bindTexture() with the same QImage will return the same texture @@ -2085,10 +2188,10 @@ int QGLContextPrivate::maxTextureSize() \sa deleteTexture() */ -GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) +GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options) { Q_D(QGLContext); - QGLTexture *texture = d->bindTexture(image, target, format, false); + QGLTexture *texture = d->bindTexture(image, target, format, false, options); return texture->id; } @@ -2097,7 +2200,16 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) { Q_D(QGLContext); - QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false); + QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption); + return texture->id; +} + +/*! \internal */ +GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, + BindOptions options) +{ + Q_D(QGLContext); + QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options); return texture->id; } #endif @@ -2109,7 +2221,20 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) { Q_D(QGLContext); - QGLTexture *texture = d->bindTexture(pixmap, target, format, false, false); + QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption); + return texture->id; +} + +/*! + \overload + + Generates and binds a 2D GL texture to the current context, based + on \a image. +*/ +GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options) +{ + Q_D(QGLContext); + QGLTexture *texture = d->bindTexture(pixmap, target, format, options); return texture->id; } @@ -2118,7 +2243,15 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format) { Q_D(QGLContext); - QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), false, false); + QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption); + return texture->id; +} +/*! \internal */ +GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format, + BindOptions options) +{ + Q_D(QGLContext); + QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options); return texture->id; } #endif @@ -4118,15 +4251,31 @@ bool QGLWidget::autoBufferSwap() const GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format) { Q_D(QGLWidget); - return d->glcx->bindTexture(image, target, format); + return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption); } + + +GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options) +{ + Q_D(QGLWidget); + return d->glcx->bindTexture(image, target, format, options); +} + + #ifdef Q_MAC_COMPAT_GL_FUNCTIONS /*! \internal */ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) { Q_D(QGLWidget); - return d->glcx->bindTexture(image, GLenum(target), GLint(format)); + return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption); +} + +GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, + QGLContext::BindOptions options) +{ + Q_D(QGLWidget); + return d->glcx->bindTexture(image, GLenum(target), GLint(format), options); } #endif @@ -4139,7 +4288,14 @@ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMac GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) { Q_D(QGLWidget); - return d->glcx->bindTexture(pixmap, target, format); + return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption); +} + +GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, + QGLContext::BindOptions options) +{ + Q_D(QGLWidget); + return d->glcx->bindTexture(pixmap, target, format, options); } #ifdef Q_MAC_COMPAT_GL_FUNCTIONS @@ -4147,7 +4303,14 @@ GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format) { Q_D(QGLWidget); - return d->glcx->bindTexture(pixmap, target, format); + return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption); +} + +GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format, + QGLContext::BindOptions options) +{ + Q_D(QGLWidget); + return d->glcx->bindTexture(pixmap, target, format, options); } #endif @@ -4568,34 +4731,37 @@ QGLFormat QGLDrawable::format() const return QGLFormat(); } -GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format) +GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format, + QGLContext::BindOptions options) { QGLTexture *texture = 0; + options |= QGLContext::MemoryManagedBindOption; if (widget) - texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true); + texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, options); else if (buffer) - texture = buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true); + texture = buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, options); else if (fbo && QGLContext::currentContext()) - texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true); + texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, options); #if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) else if (wsurf) - texture = wsurf->context()->d_func()->bindTexture(image, target, format, true); + texture = wsurf->context()->d_func()->bindTexture(image, target, format, options); #endif return texture->id; } -GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) +GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, + QGLContext::BindOptions options) { QGLTexture *texture = 0; if (widget) - texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true, true); + texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, options); else if (buffer) - texture = buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true, true); + texture = buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, options); else if (fbo && QGLContext::currentContext()) - texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true, true); + texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, options); #if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) else if (wsurf) - texture = wsurf->context()->d_func()->bindTexture(pixmap, target, format, true, true); + texture = wsurf->context()->d_func()->bindTexture(pixmap, target, format, options); #endif return texture->id; } diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 678bbb7..a928d64 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -288,6 +288,25 @@ public: virtual void swapBuffers() const; + enum BindOption { + NoBindOption = 0x0000, + InvertedYBindOption = 0x0001, + MipmapBindOption = 0x0002, + PremultipliedAlphaBindOption = 0x0004, + LinearFilteringBindOption = 0x0008, + + MemoryManagedBindOption = 0x1000, // internal flag + + DefaultBindOption = LinearFilteringBindOption | InvertedYBindOption | MipmapBindOption, + InternalBindOption = MemoryManagedBindOption | PremultipliedAlphaBindOption + }; + Q_DECLARE_FLAGS(BindOptions, BindOption); + + GLuint bindTexture(const QImage &image, GLenum target, GLint format, + BindOptions options); + GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format, + BindOptions options); + GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, @@ -304,6 +323,10 @@ public: QMacCompatGLint format = GL_RGBA); GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum = GL_TEXTURE_2D, QMacCompatGLint format = GL_RGBA); + GLuint bindTexture(const QImage &image, QMacCompatGLenum, QMacCompatGLint format, + BindOptions); + GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum, QMacCompatGLint format, + BindOptions); void deleteTexture(QMacCompatGLuint tx_id); @@ -446,10 +469,16 @@ public: const QFont & fnt = QFont(), int listBase = 2000); QPaintEngine *paintEngine() const; + GLuint bindTexture(const QImage &image, GLenum target, GLint format, + QGLContext::BindOptions options); + GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format, + QGLContext::BindOptions options); + GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); + GLuint bindTexture(const QString &fileName); void deleteTexture(GLuint tx_id); @@ -462,6 +491,10 @@ public: QMacCompatGLint format = GL_RGBA); GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum = GL_TEXTURE_2D, QMacCompatGLint format = GL_RGBA); + GLuint bindTexture(const QImage &image, QMacCompatGLenum, QMacCompatGLint format, + QGLContext::BindOptions); + GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum, QMacCompatGLint format, + QGLContext::BindOptions); void deleteTexture(QMacCompatGLuint tx_id); diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index ab040ed..6905199 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -208,10 +208,12 @@ class QGLContextPrivate public: explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {groupResources = new QGLContextGroupResources;} ~QGLContextPrivate() {if (!groupResources->refs.deref()) delete groupResources;} - QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, bool clean); + QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, + QGLContext::BindOptions options); QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key, - bool clean = false); - QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert = false); + QGLContext::BindOptions options); + QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format, + QGLContext::BindOptions options); QGLTexture *textureCacheLookup(const qint64 key, GLenum target); void init(QPaintDevice *dev, const QGLFormat &format); QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format); @@ -241,7 +243,8 @@ public: quint32 gpm; int screen; QHash<QPixmapData*, QPixmap> boundPixmaps; - QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key, bool canInvert); + QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key, + QGLContext::BindOptions options); static void destroyGlSurfaceForPixmap(QPixmapData*); static void unbindPixmapFromTexture(QPixmapData*); #endif @@ -319,8 +322,10 @@ public: void doneCurrent(); QSize size() const; QGLFormat format() const; - GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); - GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA); + GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA, + QGLContext::BindOptions = QGLContext::InternalBindOption); + GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA, + QGLContext::BindOptions = QGLContext::InternalBindOption); QColor backgroundColor() const; QGLContext *context() const; bool autoFillBackground() const; @@ -404,15 +409,18 @@ extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg(); class QGLTexture { public: QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D, - bool _clean = false, bool _yInverted = false) - : context(ctx), id(tx_id), target(tx_target), clean(_clean), yInverted(_yInverted) + QGLContext::BindOptions opt = QGLContext::DefaultBindOption) + : context(ctx), + id(tx_id), + target(tx_target), + options(opt) #if defined(Q_WS_X11) - , boundPixmap(0) + , boundPixmap(0) #endif {} ~QGLTexture() { - if (clean) { + if (options & QGLContext::MemoryManagedBindOption) { QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext()); QGLContext *ctx = const_cast<QGLContext *>(context); Q_ASSERT(ctx); @@ -436,8 +444,9 @@ public: QGLContext *context; GLuint id; GLenum target; - bool clean; - bool yInverted; // NOTE: Y-Inverted textures are for internal use only! + + QGLContext::BindOptions options; + #if defined(Q_WS_X11) QPixmapData* boundPixmap; #endif diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index dccdf63..aca60bc 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -1599,7 +1599,8 @@ bool qt_resolveTextureFromPixmap() #endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) -QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key, bool canInvert) +QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key, + QGLContext::BindOptions options) { #if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX) return 0; @@ -1632,7 +1633,7 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, con 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, + GLX_Y_INVERTED_EXT, options & QGLContext::InvertedYBindOption ? GLX_DONT_CARE : False, XNone }; configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount); @@ -1693,9 +1694,10 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, con glBindTexture(GL_TEXTURE_2D, textureId); - QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, false); - texture->yInverted = (hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted); - if (texture->yInverted) + if (!((hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted))); + options &= ~QGLContext::InvertedYBindOption; + QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options); + if (texture->options & QGLContext::InvertedYBindOption) pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; // We assume the cost of bound pixmaps is zero diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index b03fdfa..a5f83a5 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -410,6 +410,14 @@ struct QGLExtensionFuncs #define GL_BGRA 0x80E1 #endif +#ifndef GL_RGB16 +#define GL_RGB16 32852 +#endif + +#ifndef GL_UNSIGNED_SHORT_5_6_5 +#define GL_UNSIGNED_SHORT_5_6_5 33635 +#endif + #ifndef GL_MULTISAMPLE #define GL_MULTISAMPLE 0x809D #endif diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 83fddd1..0913606 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const { - const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true, false); + const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, QGLContext::BindOptions(QGLContext::DefaultBindOption | QGLContext::MemoryManagedBindOption)); } void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF& source) const diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index f8bffd3..8ce50cf 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -104,7 +104,7 @@ QT_BEGIN_NAMESPACE on desktop systems. The programmer should restrict themselves to just features that are present in GLSL/ES, and avoid standard variable names that only work on the desktop. - + \section1 Simple shader example \code @@ -199,8 +199,11 @@ QT_BEGIN_NAMESPACE \value VertexShader Vertex shader written in the OpenGL Shading Language (GLSL). \value FragmentShader Fragment shader written in the OpenGL Shading Language (GLSL). + \value PartialVertexShader Partial vertex shader that will be concatenated with all other partial vertex shaders at link time. \value PartialFragmentShader Partial fragment shader that will be concatenated with all other partial fragment shaders at link time. + + \omitvalue PartialShader */ #ifndef GL_FRAGMENT_SHADER @@ -251,8 +254,7 @@ public: , shader(0) , shaderType(type) , compiled(false) - , isPartial(type == QGLShader::PartialVertexShader || - type == QGLShader::PartialFragmentShader) + , isPartial((type & QGLShader::PartialShader) != 0) , hasPartialSource(false) { } @@ -348,31 +350,6 @@ QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent) } /*! - Constructs a new QGLShader object from the source code in \a fileName - and attaches it to \a parent. If the filename ends in \c{.fsh}, - it is assumed to be a fragment shader, otherwise it is assumed to - be a vertex shader (normally the extension is \c{.vsh} for vertex shaders). - If the shader could not be loaded, then isCompiled() will return false. - - The shader will be associated with the current QGLContext. - - \sa isCompiled() -*/ -QGLShader::QGLShader(const QString& fileName, QObject *parent) - : QObject(parent) -{ - if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive)) - d = new QGLShaderPrivate(QGLShader::FragmentShader, QGLContext::currentContext()); - else - d = new QGLShaderPrivate(QGLShader::VertexShader, QGLContext::currentContext()); - if (d->create() && !compileFile(fileName)) { - if (d->shader) - glDeleteShader(d->shader); - d->shader = 0; - } -} - -/*! Constructs a new QGLShader object of the specified \a type from the source code in \a fileName and attaches it to \a parent. If the shader could not be loaded, then isCompiled() will return false. @@ -413,31 +390,6 @@ QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObj } /*! - Constructs a new QGLShader object from the source code in \a fileName - and attaches it to \a parent. If the filename ends in \c{.fsh}, - it is assumed to be a fragment shader, otherwise it is assumed to - be a vertex shader (normally the extension is \c{.vsh} for vertex shaders). - If the shader could not be loaded, then isCompiled() will return false. - - The shader will be associated with \a context. - - \sa isCompiled() -*/ -QGLShader::QGLShader(const QString& fileName, const QGLContext *context, QObject *parent) - : QObject(parent) -{ - if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive)) - d = new QGLShaderPrivate(QGLShader::FragmentShader, context); - else - d = new QGLShaderPrivate(QGLShader::VertexShader, context); - if (d->create() && !compileFile(fileName)) { - if (d->shader) - glDeleteShader(d->shader); - d->shader = 0; - } -} - -/*! Constructs a new QGLShader object of the specified \a type from the source code in \a fileName and attaches it to \a parent. If the shader could not be loaded, then isCompiled() will return false. @@ -917,6 +869,33 @@ bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QString& sour } /*! + Compiles the contents of \a fileName as a shader of the specified + \a type and adds it to this shader program. Returns true if + compilation was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QGLShader first. + + \sa addShader() +*/ +bool QGLShaderProgram::addShaderFromFile + (QGLShader::ShaderType type, const QString& fileName) +{ + if (!init()) + return false; + QGLShader *shader = new QGLShader(type, this); + if (!shader->compileFile(fileName)) { + d->log = shader->log(); + delete shader; + return false; + } + d->anonShaders.append(shader); + return addShader(shader); +} + +/*! Removes \a shader from this shader program. The object is not deleted. \sa addShader(), link(), removeAllShaders() @@ -2983,6 +2962,7 @@ bool QGLShaderProgram::hasShaderPrograms(const QGLContext *context) #endif } + #endif QT_END_NAMESPACE diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h index c5295eb..4f95ef3 100644 --- a/src/opengl/qglshaderprogram.h +++ b/src/opengl/qglshaderprogram.h @@ -63,19 +63,21 @@ class Q_OPENGL_EXPORT QGLShader : public QObject { Q_OBJECT public: - enum ShaderType + enum ShaderTypeBits { - VertexShader, - FragmentShader, - PartialVertexShader, - PartialFragmentShader + VertexShader = 0x0001, + FragmentShader = 0x0002, + + PartialShader = 0x1000, + + PartialVertexShader = PartialShader | VertexShader, + PartialFragmentShader = PartialShader | FragmentShader }; + Q_DECLARE_FLAGS(ShaderType, ShaderTypeBits); explicit QGLShader(QGLShader::ShaderType type, QObject *parent = 0); - explicit QGLShader(const QString& fileName, QObject *parent = 0); QGLShader(const QString& fileName, QGLShader::ShaderType type, QObject *parent = 0); QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); - QGLShader(const QString& fileName, const QGLContext *context, QObject *parent = 0); QGLShader(const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); virtual ~QGLShader(); @@ -106,6 +108,9 @@ private: Q_DISABLE_COPY(QGLShader) }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QGLShader::ShaderType); + + class QGLShaderProgramPrivate; class Q_OPENGL_EXPORT QGLShaderProgram : public QObject @@ -123,6 +128,7 @@ public: bool addShader(QGLShader::ShaderType type, const char *source); bool addShader(QGLShader::ShaderType type, const QByteArray& source); bool addShader(QGLShader::ShaderType type, const QString& source); + bool addShaderFromFile(QGLShader::ShaderType type, const QString& fileName); void removeAllShaders(); diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 9434adf..ade67d3 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -4433,13 +4433,13 @@ void QOpenGLPaintEngine::drawTextureRect(int tx_width, int tx_height, const QRec if (target == GL_TEXTURE_2D) { x1 = sr.x() / tx_width; x2 = x1 + sr.width() / tx_width; - y1 = 1.0 - (sr.bottom() / tx_height); - y2 = 1.0 - (sr.y() / tx_height); + y1 = 1 - (sr.bottom() / tx_height); + y2 = 1 - (sr.y() / tx_height); } else { x1 = sr.x(); x2 = sr.right(); - y1 = tx_height - sr.bottom(); - y2 = tx_height - sr.y(); + y1 = sr.bottom(); + y2 = sr.y(); } q_vertexType vertexArray[4*2]; diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 80e99a0..c193f12 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -271,7 +271,7 @@ void QGLPixmapData::ensureCreated() const m_source = QImage(); } - m_texture.clean = false; + m_texture.options &= ~QGLContext::MemoryManagedBindOption; } QGLFramebufferObject *QGLPixmapData::fbo() const |