summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@theqtcompany.com>2014-12-18 12:12:58 +0100
committerSimon Hausmann <simon.hausmann@theqtcompany.com>2014-12-18 12:12:58 +0100
commite281537f2049af0b96fd87158f2b7212afe8ab5f (patch)
tree7f9e3b14a2456cc779aa165457192094507dd257 /src/gui
parente0a8b5ce88bc50440dcec2fe3a86d83e2a7dc7b0 (diff)
parent84569773db68408704193268bc42a200bb25a924 (diff)
Merge remote-tracking branch 'origin/5.4' into dev
Conflicts: src/corelib/global/qglobal.h src/platformsupport/platformcompositor/qopenglcompositor.cpp src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp tests/auto/gui/kernel/qwindow/tst_qwindow.cpp Change-Id: I5422868500be695584a496dbbbc719d146bc572d
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/image/qimage.cpp11
-rw-r--r--src/gui/kernel/qopenglcontext.cpp6
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp244
-rw-r--r--src/gui/opengl/qopenglpaintengine_p.h14
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp22
-rw-r--r--src/gui/painting/qplatformbackingstore.h11
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp2
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h1
-rw-r--r--src/gui/text/qrawfont.cpp31
-rw-r--r--src/gui/text/qrawfont_p.h37
-rw-r--r--src/gui/text/qtextlayout.cpp10
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 &image;
+ 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 &regi
// 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 &regi
// 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(&current);
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;