From e9222e199d587f48bd1d0e597aa295ebbe0531e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 9 Dec 2014 16:50:05 +0100 Subject: GL2PaintEngine: Prevent fillInPendingGlyphs from breaking gradients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The glyph cache internally uses the image texture unit when blitting, but doesn't always activate the unit before binding its texture, resulting in sometimes binding the glyph cache texture to the wrong unit. The image texture unit is also the same as the brush texture unit, so any time we fill in pending glyphs we need to re-bind the brush texture, otherwise drawing text with eg. gradients will fail after the new glyphs have been filled. The new hasPendingGlyphs() member function of the glyph cache is an optimization so that we don't need to activate and rebind unless there are glyphs that need to be filled. Change-Id: Iac74130145d2d6d7bf95206b5e8a2fc760743cb5 Reviewed-by: Laszlo Agocs Reviewed-by: Tor Arne Vestbø --- src/gui/opengl/qopenglpaintengine.cpp | 20 +++++++++++++++++++- src/gui/painting/qtextureglyphcache.cpp | 2 +- src/gui/painting/qtextureglyphcache_p.h | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 834aed9142..ff1a26c914 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -1639,7 +1639,25 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly cache->populate(fe, staticTextItem->numGlyphs, staticTextItem->glyphs, staticTextItem->glyphPositions); } - cache->fillInPendingGlyphs(); + + if (cache->hasPendingGlyphs()) { + // Filling in the glyphs binds and sets parameters, so we need to + // ensure that the glyph cache doesn't mess with whatever unit + // is currently active. Note that the glyph cache internally + // uses the image texture unit for blitting to the cache, while + // we switch between image and mask units when drawing. + static const GLenum glypchCacheTextureUnit = QT_IMAGE_TEXTURE_UNIT; + funcs.glActiveTexture(GL_TEXTURE0 + glypchCacheTextureUnit); + + cache->fillInPendingGlyphs(); + + // We assume the cache can be trusted on which texture was bound + lastTextureUsed = cache->texture(); + + // But since the brush and image texture units are possibly shared + // we may have to re-bind brush textures after filling in the cache. + brushTextureDirty = (QT_BRUSH_TEXTURE_UNIT == glypchCacheTextureUnit); + } } if (cache->width() == 0 || cache->height() == 0) diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index e12d61bbf4..be46a0fba3 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -222,7 +222,7 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const void QTextureGlyphCache::fillInPendingGlyphs() { - if (m_pendingGlyphs.isEmpty()) + if (!hasPendingGlyphs()) return; int requiredHeight = m_h; diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index 50c2c9dcc6..2d2fcdfc93 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -104,6 +104,7 @@ public: bool populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions); + bool hasPendingGlyphs() const { return !m_pendingGlyphs.isEmpty(); }; void fillInPendingGlyphs(); virtual void createTextureData(int width, int height) = 0; -- cgit v1.2.3 From 47326b9c5c38fea39f8539f50f32667d2c391b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 2 Dec 2014 20:16:23 +0100 Subject: GL2PaintEngine: centralize logic for updating/preparing textures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite of updateTextureFilter to include activating and binding as well, so that we can maintain a single view of which texture was the last one to be used from within the engine itself. The behavior should be the same as before. Change-Id: I41781d00458b0176c614266f4360db3c68b120a1 Reviewed-by: Laszlo Agocs Reviewed-by: Tor Arne Vestbø --- src/gui/opengl/qopenglpaintengine.cpp | 121 ++++++++++++++++++++-------------- src/gui/opengl/qopenglpaintengine_p.h | 7 +- 2 files changed, 78 insertions(+), 50 deletions(-) (limited to 'src/gui') diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index ff1a26c914..6570d49279 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -107,29 +107,6 @@ QOpenGL2PaintEngineExPrivate::~QOpenGL2PaintEngineExPrivate() } } -void QOpenGL2PaintEngineExPrivate::updateTextureFilter(GLenum wrapMode, bool smoothPixmapTransform, GLuint id) -{ -// funcs.glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit? - if (id != GLuint(-1) && id == lastTextureUsed) - return; - - lastTextureUsed = id; - - static const GLenum target = GL_TEXTURE_2D; - - if (smoothPixmapTransform) { - funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode); - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode); -} - - inline QColor qt_premultiplyColor(QColor c, GLfloat opacity) { qreal alpha = c.alphaF() * opacity; @@ -176,19 +153,74 @@ void QOpenGL2PaintEngineExPrivate::useSimpleShader() updateMatrix(); } +template +void QOpenGL2PaintEngineExPrivate::updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode) +{ + static const GLenum target = GL_TEXTURE_2D; + + funcs.glActiveTexture(GL_TEXTURE0 + textureUnit); + + GLuint textureId = bindTexture(texture); + + if (updateMode == UpdateIfNeeded && textureId == lastTextureUsed) + return; + + lastTextureUsed = textureId; + + funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode); + funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode); + + funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filterMode); + funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filterMode); +} + +template<> +GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const GLuint &textureId) +{ + if (textureId != lastTextureUsed) + funcs.glBindTexture(GL_TEXTURE_2D, textureId); + + return textureId; +} + +template<> +GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QImage &image) +{ + return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, image); +} + +template<> +GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QPixmap &pixmap) +{ + return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap); +} + +struct ImageWithBindOptions +{ + const QImage ℑ + QOpenGLTextureCache::BindOptions options; +}; + +template<> +GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const ImageWithBindOptions &imageWithOptions) +{ + return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, imageWithOptions.image, imageWithOptions.options); +} + void QOpenGL2PaintEngineExPrivate::updateBrushTexture() { Q_Q(QOpenGL2PaintEngineEx); // qDebug("QOpenGL2PaintEngineExPrivate::updateBrushTexture()"); Qt::BrushStyle style = currentBrush.style(); + bool smoothPixmapTransform = q->state()->renderHints & QPainter::SmoothPixmapTransform; + GLenum filterMode = smoothPixmapTransform ? GL_LINEAR : GL_NEAREST; + if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) { // Get the image data for the pattern - QImage texImage = qt_imageForBrush(style, false); + QImage textureImage = qt_imageForBrush(style, false); - funcs.glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); - QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, texImage); - updateTextureFilter(GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); + updateTexture(QT_BRUSH_TEXTURE_UNIT, textureImage, GL_REPEAT, filterMode, ForceUpdate); } else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { // Gradiant brush: All the gradiants use the same texture @@ -197,7 +229,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture() // We apply global opacity in the fragment shaders, so we always pass 1.0 // for opacity to the cache. - GLuint texId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); + GLuint textureId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); GLenum wrapMode = GL_CLAMP_TO_EDGE; if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient) @@ -205,9 +237,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture() else if (g->spread() == QGradient::ReflectSpread) wrapMode = GL_MIRRORED_REPEAT; - funcs.glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); - funcs.glBindTexture(GL_TEXTURE_2D, texId); - updateTextureFilter(wrapMode, q->state()->renderHints & QPainter::SmoothPixmapTransform); + updateTexture(QT_BRUSH_TEXTURE_UNIT, textureId, wrapMode, filterMode, ForceUpdate); } else if (style == Qt::TexturePattern) { currentBrushImage = currentBrush.textureImage(); @@ -224,9 +254,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture() wrapMode = GL_CLAMP_TO_EDGE; } - funcs.glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); - QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, currentBrushImage); - updateTextureFilter(wrapMode, q->state()->renderHints & QPainter::SmoothPixmapTransform); + updateTexture(QT_BRUSH_TEXTURE_UNIT, currentBrushImage, wrapMode, filterMode, ForceUpdate); textureInvertedY = false; } @@ -1382,9 +1410,8 @@ void QOpenGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixma ensureActive(); d->transferMode(ImageDrawingMode); - d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap); - d->updateTextureFilter(GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, id); + GLenum filterMode = state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; + d->updateTexture(QT_IMAGE_TEXTURE_UNIT, pixmap, GL_CLAMP_TO_EDGE, filterMode); bool isBitmap = pixmap.isQBitmap(); bool isOpaque = !isBitmap && !pixmap.hasAlpha(); @@ -1428,9 +1455,9 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c break; } - d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, image, bindOption); - d->updateTextureFilter(GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, id); + ImageWithBindOptions imageWithOptions = { image, bindOption }; + GLenum filterMode = state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; + d->updateTexture(QT_IMAGE_TEXTURE_UNIT, imageWithOptions, GL_CLAMP_TO_EDGE, filterMode); d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); } @@ -1471,9 +1498,8 @@ bool QOpenGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, co ensureActive(); d->transferMode(ImageDrawingMode); - d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - d->funcs.glBindTexture(GL_TEXTURE_2D, textureId); - d->updateTextureFilter(GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, textureId); + GLenum filterMode = state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; + d->updateTexture(QT_IMAGE_TEXTURE_UNIT, textureId, GL_CLAMP_TO_EDGE, filterMode); d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); @@ -1823,9 +1849,7 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly funcs.glEnable(GL_BLEND); funcs.glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); - funcs.glBindTexture(GL_TEXTURE_2D, cache->texture()); - updateTextureFilter(GL_REPEAT, false); + updateTexture(QT_MASK_TEXTURE_UNIT, cache->texture(), GL_REPEAT, GL_NEAREST, ForceUpdate); #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); @@ -1970,9 +1994,8 @@ void QOpenGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFra transferMode(ImageOpacityArrayDrawingMode); - funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap); - updateTextureFilter(GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform, id); + GLenum filterMode = q->state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; + updateTexture(QT_IMAGE_TEXTURE_UNIT, pixmap, GL_CLAMP_TO_EDGE, filterMode); bool isBitmap = pixmap.isQBitmap(); bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque; diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h index a5f3cc2894..209cd3d7b5 100644 --- a/src/gui/opengl/qopenglpaintengine_p.h +++ b/src/gui/opengl/qopenglpaintengine_p.h @@ -193,7 +193,12 @@ public: void updateBrushUniforms(); void updateMatrix(); void updateCompositionMode(); - void updateTextureFilter(GLenum wrapMode, bool smoothPixmapTransform, GLuint id = GLuint(-1)); + + enum TextureUpdateMode { UpdateIfNeeded, ForceUpdate }; + template + void updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode = UpdateIfNeeded); + template + GLuint bindTexture(const T &texture); void resetGLState(); -- cgit v1.2.3 From dc583a0576343cfcd5544a21b8625af61e299e6f Mon Sep 17 00:00:00 2001 From: MihailNaydenov Date: Fri, 26 Sep 2014 12:23:55 +0300 Subject: Fix incorrect QImage transformation when its devicePixelRatio != 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QImage::transformed compensates for unwanted translation. This compensation is performed in "pixel space". However, a possible code path to perform the transformation uses QPainter which is devicePixelRatio-aware and expects the transformation matrix to be in logical coordinates. For example, image.transformed(QTransform().rotate(45)) will result in cropped out image if devicePixelRatio == 2. Change-Id: I830ff3ffa25531d842dc9c77f1d0e8d4bd502c9d Reviewed-by: Tor Arne Vestbø --- src/gui/image/qimage.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 4e10b4cb4b..ea23954a49 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4480,7 +4480,6 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode dImage.d->dpmx = dotsPerMeterX(); dImage.d->dpmy = dotsPerMeterY(); - dImage.d->devicePixelRatio = devicePixelRatio(); switch (bpp) { // initizialize the data @@ -4502,13 +4501,19 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode } if (target_format >= QImage::Format_RGB32) { + // Prevent QPainter from applying devicePixelRatio corrections + const QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this; + + Q_ASSERT(sImage.devicePixelRatio() == 1); + Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio()); + QPainter p(&dImage); if (mode == Qt::SmoothTransformation) { p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); } p.setTransform(mat); - p.drawImage(QPoint(0, 0), *this); + p.drawImage(QPoint(0, 0), sImage); } else { bool invertible; mat = mat.inverted(&invertible); // invert matrix @@ -4520,6 +4525,8 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode int dbpl = dImage.bytesPerLine(); qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs); } + + dImage.d->devicePixelRatio = devicePixelRatio(); return dImage; } -- cgit v1.2.3 From 37490d465b203ac109f422b482eda9704f4e8593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 8 Dec 2014 15:31:37 +0100 Subject: GL: Make updateTexture invalidate texture on change of texture unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switching texture units means the value of lastTextureUsed could be invalid, meaning we need to unconditionally re-bind and update parameters. A future optimization would be to keep a per-texture-unit cache, so that we wouldn't have to re-bind and set parameters when switching units back and forth, but this complicates the current code somewhat, so it's left for another patch. Change-Id: Icb2a5d03457a907f3c25bbb437feeb7c5f155716 Reviewed-by: Laszlo Agocs Reviewed-by: Tor Arne Vestbø --- src/gui/opengl/qopenglpaintengine.cpp | 52 ++++++++++++++++++++++++++++++++--- src/gui/opengl/qopenglpaintengine_p.h | 5 ++++ 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'src/gui') diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 6570d49279..48a2ceaa55 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -153,12 +153,26 @@ void QOpenGL2PaintEngineExPrivate::useSimpleShader() updateMatrix(); } +/* + Single entry-point for activating, binding, and setting properties. + + Allows keeping track of (caching) the latest texture unit and bound + texture in a central place, so that we can skip re-binding unless + needed. + + \note Any code or Qt API that internally activates or binds will + not affect the cache used by this function, which means they will + lead to inconsisent state. QPainter::beginNativePainting() takes + care of resetting the cache, so for user–code this is fine, but + internally in the paint engine care must be taken to not call + functions that may activate or bind under our feet. +*/ template void QOpenGL2PaintEngineExPrivate::updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode) { static const GLenum target = GL_TEXTURE_2D; - funcs.glActiveTexture(GL_TEXTURE0 + textureUnit); + activateTextureUnit(textureUnit); GLuint textureId = bindTexture(texture); @@ -174,6 +188,20 @@ void QOpenGL2PaintEngineExPrivate::updateTexture(GLenum textureUnit, const T &te funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filterMode); } +void QOpenGL2PaintEngineExPrivate::activateTextureUnit(GLenum textureUnit) +{ + if (textureUnit != lastTextureUnitUsed) { + funcs.glActiveTexture(GL_TEXTURE0 + textureUnit); + lastTextureUnitUsed = textureUnit; + + // We simplify things by keeping a single cached value of the last + // texture that was bound, instead of one per texture unit. This + // means that switching texture units could potentially mean we + // need a re-bind and corresponding parameter updates. + lastTextureUsed = GLuint(-1); + } +} + template<> GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const GLuint &textureId) { @@ -597,9 +625,15 @@ void QOpenGL2PaintEngineEx::beginNativePainting() } #endif // QT_OPENGL_ES_2 + d->resetGLState(); + + // We don't know what texture units and textures the native painting + // will activate and bind, so we can't assume anything when we return + // from the native painting. + d->lastTextureUnitUsed = QT_UNKNOWN_TEXTURE_UNIT; d->lastTextureUsed = GLuint(-1); + d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); - d->resetGLState(); d->shaderManager->setDirty(); @@ -608,8 +642,9 @@ void QOpenGL2PaintEngineEx::beginNativePainting() void QOpenGL2PaintEngineExPrivate::resetGLState() { + activateTextureUnit(QT_DEFAULT_TEXTURE_UNIT); + funcs.glDisable(GL_BLEND); - funcs.glActiveTexture(GL_TEXTURE0); funcs.glDisable(GL_STENCIL_TEST); funcs.glDisable(GL_DEPTH_TEST); funcs.glDisable(GL_SCISSOR_TEST); @@ -1368,7 +1403,12 @@ void QOpenGL2PaintEngineEx::renderHintsChanged() #endif // QT_OPENGL_ES_2 Q_D(QOpenGL2PaintEngineEx); + + // This is a somewhat sneaky way of conceptually making the next call to + // updateTexture() use FoceUpdate for the TextureUpdateMode. We need this + // as new render hints may require updating the filter mode. d->lastTextureUsed = GLuint(-1); + d->brushTextureDirty = true; // qDebug("QOpenGL2PaintEngineEx::renderHintsChanged() not implemented!"); } @@ -1673,7 +1713,7 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly // uses the image texture unit for blitting to the cache, while // we switch between image and mask units when drawing. static const GLenum glypchCacheTextureUnit = QT_IMAGE_TEXTURE_UNIT; - funcs.glActiveTexture(GL_TEXTURE0 + glypchCacheTextureUnit); + activateTextureUnit(glypchCacheTextureUnit); cache->fillInPendingGlyphs(); @@ -1892,6 +1932,10 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly else funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); + // Need to reset the unit here, until we've made drawCachedGlyphs + // use the shared code-path for activating and binding. + lastTextureUnitUsed = QT_UNKNOWN_TEXTURE_UNIT; + if (lastMaskTextureUsed != cache->texture()) { funcs.glBindTexture(GL_TEXTURE_2D, cache->texture()); lastMaskTextureUsed = cache->texture(); diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h index 209cd3d7b5..297ac54640 100644 --- a/src/gui/opengl/qopenglpaintengine_p.h +++ b/src/gui/opengl/qopenglpaintengine_p.h @@ -69,6 +69,8 @@ enum EngineMode { QT_BEGIN_NAMESPACE #define GL_STENCIL_HIGH_BIT GLuint(0x80) +#define QT_UNKNOWN_TEXTURE_UNIT GLuint(-1) +#define QT_DEFAULT_TEXTURE_UNIT GLuint(0) #define QT_BRUSH_TEXTURE_UNIT GLuint(0) #define QT_IMAGE_TEXTURE_UNIT GLuint(0) //Can be the same as brush texture unit #define QT_MASK_TEXTURE_UNIT GLuint(1) @@ -184,6 +186,7 @@ public: snapToPixelGrid(false), nativePaintingActive(false), inverseScale(1), + lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT), lastMaskTextureUsed(0) { } @@ -199,6 +202,7 @@ public: void updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode = UpdateIfNeeded); template GLuint bindTexture(const T &texture); + void activateTextureUnit(GLenum textureUnit); void resetGLState(); @@ -300,6 +304,7 @@ public: GLfloat pmvMatrix[3][3]; GLfloat inverseScale; + GLenum lastTextureUnitUsed; GLuint lastTextureUsed; GLuint lastMaskTextureUsed; -- cgit v1.2.3 From 384388f2cd739fd1416e4016588c79fd9788e898 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Fri, 21 Nov 2014 10:34:22 +0400 Subject: Make QRawFont usage safer in a multi-threaded environment QFontEngine must be accessed amd deleted only in a thread in which it was instantiated, so we remember that thread and check if it hasn't been changed every time we access the engine. Change-Id: I28bc0394ced9cbd437dc950d35ffcbd99cfa7152 Reviewed-by: Pierre Rossi Reviewed-by: Lars Knoll --- src/gui/text/qrawfont.cpp | 31 +++++-------------------------- src/gui/text/qrawfont_p.h | 37 ++++++++++++++++++++++++++++++++----- src/gui/text/qtextlayout.cpp | 5 ++--- 3 files changed, 39 insertions(+), 34 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 0c3c9bb493..d21138e7ac 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -247,7 +247,6 @@ void QRawFont::loadFromData(const QByteArray &fontData, d.detach(); d->cleanUp(); d->hintingPreference = hintingPreference; - d->thread = QThread::currentThread(); d->loadFromData(fontData, pixelSize, hintingPreference); } @@ -700,8 +699,7 @@ QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writ } if (fe != 0) { - rawFont.d.data()->fontEngine = fe; - rawFont.d.data()->fontEngine->ref.ref(); + rawFont.d.data()->setFontEngine(fe); rawFont.d.data()->hintingPreference = font.hintingPreference(); } return rawFont; @@ -712,42 +710,23 @@ QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writ */ void QRawFont::setPixelSize(qreal pixelSize) { - if (d->fontEngine == 0 || qFuzzyCompare(d->fontEngine->fontDef.pixelSize, pixelSize)) + if (!d->isValid() || qFuzzyCompare(d->fontEngine->fontDef.pixelSize, pixelSize)) return; d.detach(); - QFontEngine *oldFontEngine = d->fontEngine; - - d->fontEngine = d->fontEngine->cloneWithSize(pixelSize); - if (d->fontEngine != 0) - d->fontEngine->ref.ref(); - - if (!oldFontEngine->ref.deref()) - delete oldFontEngine; + d->setFontEngine(d->fontEngine->cloneWithSize(pixelSize)); } /*! \internal */ -void QRawFontPrivate::cleanUp() -{ - if (fontEngine != 0) { - if (!fontEngine->ref.deref()) - delete fontEngine; - fontEngine = 0; - } - hintingPreference = QFont::PreferDefaultHinting; -} - void QRawFontPrivate::loadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { Q_ASSERT(fontEngine == 0); QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); - fontEngine = pfdb->fontEngine(fontData, pixelSize, hintingPreference); - if (fontEngine != 0) - fontEngine->ref.ref(); + setFontEngine(pfdb->fontEngine(fontData, pixelSize, hintingPreference)); } /*! @@ -757,7 +736,7 @@ void QRawFontPrivate::loadFromData(const QByteArray &fontData, qreal pixelSize, */ QRectF QRawFont::boundingRect(quint32 glyphIndex) const { - if (!isValid()) + if (!d->isValid()) return QRectF(); glyph_metrics_t gm = d->fontEngine->boundingBox(glyphIndex); diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h index f7a951ec59..9b0846de9a 100644 --- a/src/gui/text/qrawfont_p.h +++ b/src/gui/text/qrawfont_p.h @@ -66,10 +66,11 @@ public: {} QRawFontPrivate(const QRawFontPrivate &other) - : hintingPreference(other.hintingPreference) + : fontEngine(other.fontEngine) + , hintingPreference(other.hintingPreference) , thread(other.thread) { - fontEngine = other.fontEngine; + Q_ASSERT(fontEngine == 0 || thread == QThread::currentThread()); if (fontEngine != 0) fontEngine->ref.ref(); } @@ -80,13 +81,38 @@ public: cleanUp(); } + inline void cleanUp() + { + setFontEngine(0); + hintingPreference = QFont::PreferDefaultHinting; + } + inline bool isValid() const { - Q_ASSERT(thread == 0 || thread == QThread::currentThread()); + Q_ASSERT(fontEngine == 0 || thread == QThread::currentThread()); return fontEngine != 0; } - void cleanUp(); + inline void setFontEngine(QFontEngine *engine) + { + Q_ASSERT(fontEngine == 0 || thread == QThread::currentThread()); + if (fontEngine == engine) + return; + + if (fontEngine != 0) { + if (!fontEngine->ref.deref()) + delete fontEngine; + thread = 0; + } + + fontEngine = engine; + + if (fontEngine != 0) { + fontEngine->ref.ref(); + Q_ASSERT(thread = QThread::currentThread()); // set only if assertions enabled + } + } + void loadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); @@ -95,9 +121,10 @@ public: QFontEngine *fontEngine; QFont::HintingPreference hintingPreference; - QThread *thread; QAtomicInt ref; +private: + QThread *thread; }; QT_END_NAMESPACE diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 1ac50d3e5c..733bb57928 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2063,9 +2063,8 @@ static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, // Make a font for this particular engine QRawFont font; QRawFontPrivate *fontD = QRawFontPrivate::get(font); - fontD->fontEngine = fontEngine; - fontD->thread = QThread::currentThread(); - fontD->fontEngine->ref.ref(); + fontD->setFontEngine(fontEngine); + QVarLengthArray glyphsArray; QVarLengthArray positionsArray; -- cgit v1.2.3 From dfccd78aa671364346bc9c4d1203dcb54d008a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 8 Dec 2014 16:41:33 +0100 Subject: Ensure that GL::updateBrushTexture() activates and binds properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling QOpenGL2GradientCache::getBuffer() will generate the texture the first time, calling glBindTexture in the process. We did this without first ensuring that the right texture unit was active, resulting in the generated gradient texture binding onto the glyph cache mask unit. We now provide a specialization of bindTexture for a QGradient, which ensures that the right unit is active before calling getBuffer(). Unfortunately we have no way of knowing if the result of getBuffer() was a texture that was already bound, or if we need to bind the result, which means we have to do an unconditional bindTexture of the resulting texture ID. This means double-bind for the initial texture generation, but this was already an issue in the original code. Task-number: QTBUG-43039 Task-number: QTBUG-41244 Change-Id: I20c9b795c8c14f8d58be2b60a284c5a060705ec0 Reviewed-by: Laszlo Agocs Reviewed-by: Tor Arne Vestbø --- src/gui/opengl/qopenglpaintengine.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'src/gui') diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 48a2ceaa55..a854715f70 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -223,6 +223,20 @@ GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QPixmap &pixmap) return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap); } +template<> +GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QGradient &gradient) +{ + // We apply global opacity in the fragment shaders, so we always pass 1.0 + // for opacity to the cache. + GLuint textureId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(gradient, 1.0); + + // QOpenGL2GradientCache::getBuffer() may bind and generate a new texture if it + // hasn't been cached yet, but will otherwise return an unbound texture id. To + // be sure that the texture is bound, we unfortunately have to bind again, + // which results in the initial generation of the texture doing two binds. + return bindTexture(textureId); +} + struct ImageWithBindOptions { const QImage ℑ @@ -253,19 +267,15 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture() else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { // Gradiant brush: All the gradiants use the same texture - const QGradient* g = currentBrush.gradient(); - - // We apply global opacity in the fragment shaders, so we always pass 1.0 - // for opacity to the cache. - GLuint textureId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); + const QGradient *gradient = currentBrush.gradient(); GLenum wrapMode = GL_CLAMP_TO_EDGE; - if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient) + if (gradient->spread() == QGradient::RepeatSpread || gradient->type() == QGradient::ConicalGradient) wrapMode = GL_REPEAT; - else if (g->spread() == QGradient::ReflectSpread) + else if (gradient->spread() == QGradient::ReflectSpread) wrapMode = GL_MIRRORED_REPEAT; - updateTexture(QT_BRUSH_TEXTURE_UNIT, textureId, wrapMode, filterMode, ForceUpdate); + updateTexture(QT_BRUSH_TEXTURE_UNIT, *gradient, wrapMode, filterMode, ForceUpdate); } else if (style == Qt::TexturePattern) { currentBrushImage = currentBrush.textureImage(); -- cgit v1.2.3 From 1cc83b575d2a79b771b4b536a554cd4869c3687c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 10 Dec 2014 15:26:36 +0100 Subject: Make GL2PaintEngine::drawCachedGlyphs use updateTexture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensures that we have a consistent view of what the last used texture was, which is critical when deciding whether or not we need to re-bind the texture or update texture properties. Change-Id: Ib47eb00abde98d148fc6e569ce3e359b340328fb Reviewed-by: Laszlo Agocs Reviewed-by: Tor Arne Vestbø --- src/gui/opengl/qopenglpaintengine.cpp | 41 ++++++++++------------------------- src/gui/opengl/qopenglpaintengine_p.h | 4 +--- 2 files changed, 13 insertions(+), 32 deletions(-) (limited to 'src/gui') diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index a854715f70..8eeaa316d0 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -697,10 +697,6 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode) if (newMode == mode) return; - if (mode != BrushDrawingMode) { - lastTextureUsed = GLuint(-1); - } - if (newMode == TextDrawingMode) { shaderManager->setHasComplexGeometry(true); } else { @@ -1934,35 +1930,23 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly prepareForCachedGlyphDraw(*cache); } - QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QOpenGLTextureGlyphCache::Linear:QOpenGLTextureGlyphCache::Nearest; - if (lastMaskTextureUsed != cache->texture() || cache->filterMode() != filterMode) { + GLenum textureUnit = QT_MASK_TEXTURE_UNIT; + if (glyphFormat == QFontEngine::Format_ARGB) + textureUnit = QT_IMAGE_TEXTURE_UNIT; - if (glyphFormat == QFontEngine::Format_ARGB) - funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - else - funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); + QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate) ? + QOpenGLTextureGlyphCache::Linear : QOpenGLTextureGlyphCache::Nearest; - // Need to reset the unit here, until we've made drawCachedGlyphs - // use the shared code-path for activating and binding. - lastTextureUnitUsed = QT_UNKNOWN_TEXTURE_UNIT; + GLenum glFilterMode = filterMode == QOpenGLTextureGlyphCache::Linear ? GL_LINEAR : GL_NEAREST; - if (lastMaskTextureUsed != cache->texture()) { - funcs.glBindTexture(GL_TEXTURE_2D, cache->texture()); - lastMaskTextureUsed = cache->texture(); - } - - if (cache->filterMode() != filterMode) { - if (filterMode == QOpenGLTextureGlyphCache::Linear) { - funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - cache->setFilterMode(filterMode); - } + TextureUpdateMode updateMode = UpdateIfNeeded; + if (cache->filterMode() != filterMode) { + updateMode = ForceUpdate; + cache->setFilterMode(filterMode); } + updateTexture(textureUnit, cache->texture(), GL_REPEAT, glFilterMode, updateMode); + #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -2185,7 +2169,6 @@ void QOpenGL2PaintEngineEx::ensureActive() d->transferMode(BrushDrawingMode); d->funcs.glViewport(0, 0, d->width, d->height); d->needsSync = false; - d->lastMaskTextureUsed = 0; d->shaderManager->setDirty(); d->syncGlState(); for (int i = 0; i < 3; ++i) diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h index 297ac54640..9722ea3196 100644 --- a/src/gui/opengl/qopenglpaintengine_p.h +++ b/src/gui/opengl/qopenglpaintengine_p.h @@ -186,8 +186,7 @@ public: snapToPixelGrid(false), nativePaintingActive(false), inverseScale(1), - lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT), - lastMaskTextureUsed(0) + lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT) { } ~QOpenGL2PaintEngineExPrivate(); @@ -306,7 +305,6 @@ public: GLenum lastTextureUnitUsed; GLuint lastTextureUsed; - GLuint lastMaskTextureUsed; bool needsSync; bool multisamplingAlwaysEnabled; -- cgit v1.2.3 From 19bb9aa9e51e48043544fd7edf5abfda67955a4b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 15 Dec 2014 13:50:11 +0100 Subject: Fix possibly corrupted log clusters when using custom tab stops The calculateTabWidth() can trigger shaping of the item, which can cause the layout data to be reallocated, so we need to update the local pointers to it, like we do when we explicitly invoke the shaper. [ChangeLog][Text] Fixed problems with text layout when using custom tab stops. Task-number: QTBUG-43126 Change-Id: Ifaeeeb4bfb1a55e6638b12b444f53d2679d3d1e6 Reviewed-by: Konstantin Ritt --- src/gui/text/qtextlayout.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/gui') diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 733bb57928..52d2ba0d54 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1776,6 +1776,11 @@ void QTextLine::layout_helper(int maxGlyphs) QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth; QFixed tabWidth = eng->calculateTabWidth(item, x); + attributes = eng->attributes(); + if (!attributes) + return; + lbh.logClusters = eng->layoutData->logClustersPtr; + lbh.glyphs = eng->shapedGlyphs(¤t); lbh.spaceData.textWidth += tabWidth; lbh.spaceData.length++; -- cgit v1.2.3 From c07559bf5b352932dc4972a61c2c5f9b4ddc3c99 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 17 Dec 2014 08:54:11 +0100 Subject: QOpenGLContext: Use static invocation of QGuiApplication::platformNativeInterface(). Fix MSVC warning (release build): qopenglcontext.cpp(1116) : warning C4189: 'app' : local variable is initialized but not referenced Change-Id: I00fa5237bbac4c0e3bb63ea9d3e5096e05dbe1be Reviewed-by: Laszlo Agocs --- src/gui/kernel/qopenglcontext.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 1a8a534e11..c01e1c95dd 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -1113,9 +1113,9 @@ void QOpenGLContext::deleteQGLContext() void *QOpenGLContext::openGLModuleHandle() { #ifdef QT_OPENGL_DYNAMIC - QGuiApplication *app = qGuiApp; - Q_ASSERT(app); - return app->platformNativeInterface()->nativeResourceForIntegration(QByteArrayLiteral("glhandle")); + QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface(); + Q_ASSERT(ni); + return ni->nativeResourceForIntegration(QByteArrayLiteral("glhandle")); #else return 0; #endif -- cgit v1.2.3 From 6c2da36c22e25e626a9812419332ad379e854133 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 12 Dec 2014 12:59:43 +0100 Subject: Prevent continuous painting with viewport QOpenGLWidget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the source widget to the texture list (may be null for custom compositor implementations that add textures not belonging to actual widgets). This allows us to do proper checks with the dirtyRenderToTextureWidgets list. As a result paint events are only sent to a QOpenGLWidget if (1) there was an update() for it or (2) it was actually marked dirty. (2) was previously behaving differently: the widget got a paint event when anything in the window has changed. This is fine for naive animating OpenGL code but less ideal for QGraphicsView. Bool properties like stacksOnTop are now stored in a flags value to prevent future explosion of texture list fields and parameters. Task-number: QTBUG-43178 Change-Id: I48cbcf93df72ac682c9b5d64982a8b648fe21ef3 Reviewed-by: Jørgen Lind Reviewed-by: Paul Olav Tvete --- src/gui/painting/qplatformbackingstore.cpp | 22 +++++++++++++++------- src/gui/painting/qplatformbackingstore.h | 11 +++++++++-- 2 files changed, 24 insertions(+), 9 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index e87f796888..76269f6e65 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -82,9 +82,10 @@ public: struct QBackingstoreTextureInfo { + QWidget *widget; // may be null GLuint textureId; QRect rect; - bool stacksOnTop; + QPlatformTextureList::Flags flags; }; Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE); @@ -122,10 +123,16 @@ GLuint QPlatformTextureList::textureId(int index) const return d->textures.at(index).textureId; } -bool QPlatformTextureList::stacksOnTop(int index) const +QWidget *QPlatformTextureList::widget(int index) { Q_D(const QPlatformTextureList); - return d->textures.at(index).stacksOnTop; + return d->textures.at(index).widget; +} + +QPlatformTextureList::Flags QPlatformTextureList::flags(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).flags; } QRect QPlatformTextureList::geometry(int index) const @@ -149,13 +156,14 @@ bool QPlatformTextureList::isLocked() const return d->locked; } -void QPlatformTextureList::appendTexture(GLuint textureId, const QRect &geometry, bool stacksOnTop) +void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags) { Q_D(QPlatformTextureList); QBackingstoreTextureInfo bi; + bi.widget = widget; bi.textureId = textureId; bi.rect = geometry; - bi.stacksOnTop = stacksOnTop; + bi.flags = flags; d->textures.append(bi); } @@ -245,7 +253,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { - if (!textures->stacksOnTop(i)) { + if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QRect targetRect = deviceRect(textures->geometry(i), window); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); @@ -272,7 +280,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { - if (textures->stacksOnTop(i)) { + if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QRect targetRect = deviceRect(textures->geometry(i), window); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index 52c263f05d..c69612ca44 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -69,6 +69,11 @@ class Q_GUI_EXPORT QPlatformTextureList : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QPlatformTextureList) public: + enum Flag { + StacksOnTop = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + explicit QPlatformTextureList(QObject *parent = 0); ~QPlatformTextureList(); @@ -76,16 +81,18 @@ public: bool isEmpty() const { return count() == 0; } GLuint textureId(int index) const; QRect geometry(int index) const; - bool stacksOnTop(int index) const; + QWidget *widget(int index); + Flags flags(int index) const; void lock(bool on); bool isLocked() const; - void appendTexture(GLuint textureId, const QRect &geometry, bool stacksOnTop = false); + void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags = 0); void clear(); Q_SIGNALS: void locked(bool); }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformTextureList::Flags) #endif class Q_GUI_EXPORT QPlatformBackingStore -- cgit v1.2.3