diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2014-12-20 06:36:17 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-12-20 07:59:07 +0100 |
commit | 86d04cfe2bdceca401cab228bd63245f16e65731 (patch) | |
tree | 4273b2f5879371d130cce0d6a97a7eb75175c980 /src/gui | |
parent | 0dd38014b307f12368888c089195b084158f94a3 (diff) | |
parent | e281537f2049af0b96fd87158f2b7212afe8ab5f (diff) |
Merge "Merge remote-tracking branch 'origin/5.4' into dev" into refs/staging/dev
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/image/qimage.cpp | 11 | ||||
-rw-r--r-- | src/gui/kernel/qopenglcontext.cpp | 6 | ||||
-rw-r--r-- | src/gui/opengl/qopenglpaintengine.cpp | 244 | ||||
-rw-r--r-- | src/gui/opengl/qopenglpaintengine_p.h | 14 | ||||
-rw-r--r-- | src/gui/painting/qplatformbackingstore.cpp | 22 | ||||
-rw-r--r-- | src/gui/painting/qplatformbackingstore.h | 11 | ||||
-rw-r--r-- | src/gui/painting/qtextureglyphcache.cpp | 2 | ||||
-rw-r--r-- | src/gui/painting/qtextureglyphcache_p.h | 1 | ||||
-rw-r--r-- | src/gui/text/qrawfont.cpp | 31 | ||||
-rw-r--r-- | src/gui/text/qrawfont_p.h | 37 | ||||
-rw-r--r-- | src/gui/text/qtextlayout.cpp | 10 |
11 files changed, 254 insertions, 135 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 867cb7c322..1cd5b869a6 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4511,7 +4511,6 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode dImage.d->dpmx = dotsPerMeterX(); dImage.d->dpmy = dotsPerMeterY(); - dImage.d->devicePixelRatio = devicePixelRatio(); // initizialize the data if (d->format == QImage::Format_Indexed8) { @@ -4526,13 +4525,19 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode memset(dImage.bits(), 0x00, dImage.byteCount()); 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 @@ -4544,6 +4549,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; } diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 07a7c601fa..895ea1b07b 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -1114,9 +1114,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 diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 4bc87d2be8..6ed2fe58b9 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,38 +153,129 @@ 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<typename T> +void QOpenGL2PaintEngineExPrivate::updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode) +{ + static const GLenum target = GL_TEXTURE_2D; + + activateTextureUnit(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); +} + +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) +{ + 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); +} + +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 ℑ + 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 - 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 texId = 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; - 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, *gradient, wrapMode, filterMode, ForceUpdate); } else if (style == Qt::TexturePattern) { currentBrushImage = currentBrush.textureImage(); @@ -224,9 +292,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; } @@ -569,9 +635,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(); @@ -580,8 +652,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); @@ -624,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 { @@ -1340,7 +1409,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!"); } @@ -1382,9 +1456,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(); @@ -1442,9 +1515,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()); } @@ -1485,9 +1558,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); @@ -1651,7 +1723,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; + activateTextureUnit(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) @@ -1817,9 +1907,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); @@ -1854,31 +1942,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; - if (lastMaskTextureUsed != cache->texture()) { - funcs.glBindTexture(GL_TEXTURE_2D, cache->texture()); - lastMaskTextureUsed = cache->texture(); - } + GLenum glFilterMode = filterMode == QOpenGLTextureGlyphCache::Linear ? GL_LINEAR : GL_NEAREST; - 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); @@ -1964,9 +2044,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; @@ -2102,7 +2181,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 85ecd82b6f..e8557e61cd 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,7 +186,7 @@ public: snapToPixelGrid(false), nativePaintingActive(false), inverseScale(1), - lastMaskTextureUsed(0) + lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT) { } ~QOpenGL2PaintEngineExPrivate(); @@ -193,7 +195,13 @@ public: void updateBrushUniforms(); void updateMatrix(); void updateCompositionMode(); - void updateTextureFilter(GLenum wrapMode, bool smoothPixmapTransform, GLuint id = GLuint(-1)); + + enum TextureUpdateMode { UpdateIfNeeded, ForceUpdate }; + template<typename T> + void updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode = UpdateIfNeeded); + template<typename T> + GLuint bindTexture(const T &texture); + void activateTextureUnit(GLenum textureUnit); void resetGLState(); @@ -295,8 +303,8 @@ public: GLfloat pmvMatrix[3][3]; GLfloat inverseScale; + GLenum lastTextureUnitUsed; GLuint lastTextureUsed; - GLuint lastMaskTextureUsed; bool needsSync; bool multisamplingAlwaysEnabled; 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 diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 79ebf12fec..38e714bfcc 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 2963c41f5c..efa3b8d902 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; 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..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++; @@ -2063,9 +2068,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<glyph_t> glyphsArray; QVarLengthArray<QFixedPoint> positionsArray; |