From: Yoann Lopes Date: Wed, 21 Aug 2013 12:40:01 +0000 (+0200) Subject: Updated distance field glyph caches to use QDistanceField. X-Git-Tag: upstream/5.2.1~421^2^2~21 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=184e27c0e69f9f8c342339e83cdf79ec5a97b58e;p=platform%2Fupstream%2Fqtdeclarative.git Updated distance field glyph caches to use QDistanceField. Some OpenGL drivers assume alpha-only images are always tightly packed, regardless of what is set for GL_UNPACK_ALIGNMENT. We now use QDistanceField to store glyphs, which aligns scanlines on a 1-byte boundary, instead of QImage which uses a 4-byte boundary. A previous workaround uploaded scanlines one at a time, but this is also broken with some other drivers... Task-number: QTBUG-30908 Task-number: QTBUG-32861 Change-Id: I46527fb48de1e00116f776427c45baa752c6176d Reviewed-by: Eskil Abrahamsen Blomfeldt --- diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 3536975..3c87722 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -168,13 +168,11 @@ void QSGDistanceFieldGlyphCache::update() qsg_render_timer.start(); #endif - QHash distanceFields; - + QList distanceFields; for (int i = 0; i < m_pendingGlyphs.size(); ++i) { - glyph_t glyphIndex = m_pendingGlyphs.at(i); - - QImage distanceField = qt_renderDistanceFieldGlyph(m_referenceFont, glyphIndex, m_doubleGlyphResolution); - distanceFields.insert(glyphIndex, distanceField); + distanceFields.append(QDistanceField(m_referenceFont, + m_pendingGlyphs.at(i), + m_doubleGlyphResolution)); } #ifndef QSG_NO_RENDER_TIMING diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index cc22bfa..9e17310 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -230,7 +230,7 @@ protected: }; virtual void requestGlyphs(const QSet &glyphs) = 0; - virtual void storeGlyphs(const QHash &glyphs) = 0; + virtual void storeGlyphs(const QList &glyphs) = 0; virtual void referenceGlyphs(const QSet &glyphs) = 0; virtual void releaseGlyphs(const QSet &glyphs) = 0; diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index 4652a22..884abd3 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -142,13 +142,19 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet &glyph markGlyphsToRender(glyphsToRender); } -void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash &glyphs) +void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList &glyphs) { QHash > glyphTextures; - QHash::const_iterator it; - for (it = glyphs.constBegin(); it != glyphs.constEnd(); ++it) { - glyph_t glyphIndex = it.key(); + GLint alignment = 4; // default value + glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + + // Distance field data is always tightly packed + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + for (int i = 0; i < glyphs.size(); ++i) { + QDistanceField glyph = glyphs.at(i); + glyph_t glyphIndex = glyph.glyph(); TexCoord c = glyphTexCoord(glyphIndex); TextureInfo *texInfo = m_glyphsTexture.value(glyphIndex); @@ -157,7 +163,6 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash glyphTextures[texInfo].append(glyphIndex); - QImage glyph = it.value(); int expectedWidth = qCeil(c.width + c.xMargin * 2); if (glyph.width() != expectedWidth) glyph = glyph.copy(0, 0, expectedWidth, glyph.height()); @@ -167,15 +172,17 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash uchar *outBits = texInfo->image.scanLine(int(c.y)) + int(c.x); for (int y = 0; y < glyph.height(); ++y) { memcpy(outBits, inBits, glyph.width()); - inBits += glyph.bytesPerLine(); - outBits += texInfo->image.bytesPerLine(); + inBits += glyph.width(); + outBits += texInfo->image.width(); } } - for (int i = 0; i < glyph.height(); ++i) - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, glyph.width(), 1, GL_ALPHA, GL_UNSIGNED_BYTE, glyph.scanLine(i)); + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits()); } + // restore to previous alignment + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); + QHash >::const_iterator i; for (i = glyphTextures.constBegin(); i != glyphTextures.constEnd(); ++i) { Texture t; @@ -198,7 +205,7 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet &glyph void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int width, int height) { if (useWorkaround() && texInfo->image.isNull()) - texInfo->image = QImage(width, height, QImage::Format_Indexed8); + texInfo->image = QDistanceField(width, height); while (glGetError() != GL_NO_ERROR) { } @@ -243,8 +250,14 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int updateTexture(oldTexture, texInfo->texture, texInfo->size); if (useWorkaround()) { - for (int i = 0; i < oldHeight; ++i) - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, oldWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.scanLine(i)); + GLint alignment = 4; // default value + glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.constBits()); + + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); // restore to previous value + texInfo->image = texInfo->image.copy(0, 0, width, height); glDeleteTextures(1, &oldTexture); return; diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index ef722d8..4ce3a50 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -58,7 +58,7 @@ public: virtual ~QSGDefaultDistanceFieldGlyphCache(); void requestGlyphs(const QSet &glyphs); - void storeGlyphs(const QHash &glyphs); + void storeGlyphs(const QList &glyphs); void referenceGlyphs(const QSet &glyphs); void releaseGlyphs(const QSet &glyphs); @@ -73,7 +73,7 @@ private: GLuint texture; QSize size; QRect allocatedArea; - QImage image; + QDistanceField image; TextureInfo() : texture(0) { } diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp index 97bb429..c15263f 100644 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp @@ -300,7 +300,7 @@ void QSGSharedDistanceFieldGlyphCache::waitForGlyphs() } } -void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash &glyphs) +void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QList &glyphs) { { QMutexLocker locker(&m_pendingGlyphsMutex); @@ -312,14 +312,12 @@ void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash int glyphCount = glyphs.size(); QVector glyphIds(glyphCount); QVector images(glyphCount); - QHash::const_iterator it = glyphs.constBegin(); - int i=0; - while (it != glyphs.constEnd()) { - m_requestedGlyphsThatHaveNotBeenReturned.insert(it.key()); - glyphIds[i] = it.key(); - images[i] = it.value(); - - ++it; ++i; + for (int i = 0; i < glyphs.size(); ++i) { + const QDistanceField &df = glyphs.at(i); + m_requestedGlyphsThatHaveNotBeenReturned.insert(df.glyph()); + glyphIds[i] = df.glyph(); + // ### TODO: Handle QDistanceField in QPlatformSharedGraphicsCache + images[i] = df.toImage(QImage::Format_Indexed8); } m_hasPostedEvents = true; diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h index ac613c1..2c57424 100644 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h @@ -66,7 +66,7 @@ public: void requestGlyphs(const QSet &glyphs); void referenceGlyphs(const QSet &glyphs); - void storeGlyphs(const QHash &glyphs); + void storeGlyphs(const QList &glyphs); void releaseGlyphs(const QSet &glyphs); Q_SIGNALS: