Updated distance field glyph caches to use QDistanceField.
authorYoann Lopes <yoann.lopes@digia.com>
Wed, 21 Aug 2013 12:40:01 +0000 (14:40 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Tue, 27 Aug 2013 18:35:55 +0000 (20:35 +0200)
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 <eskil.abrahamsen-blomfeldt@digia.com>
src/quick/scenegraph/qsgadaptationlayer.cpp
src/quick/scenegraph/qsgadaptationlayer_p.h
src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h

index 3536975..3c87722 100644 (file)
@@ -168,13 +168,11 @@ void QSGDistanceFieldGlyphCache::update()
         qsg_render_timer.start();
 #endif
 
-    QHash<glyph_t, QImage> distanceFields;
-
+    QList<QDistanceField> 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
index cc22bfa..9e17310 100644 (file)
@@ -230,7 +230,7 @@ protected:
     };
 
     virtual void requestGlyphs(const QSet<glyph_t> &glyphs) = 0;
-    virtual void storeGlyphs(const QHash<glyph_t, QImage> &glyphs) = 0;
+    virtual void storeGlyphs(const QList<QDistanceField> &glyphs) = 0;
     virtual void referenceGlyphs(const QSet<glyph_t> &glyphs) = 0;
     virtual void releaseGlyphs(const QSet<glyph_t> &glyphs) = 0;
 
index 4652a22..884abd3 100644 (file)
@@ -142,13 +142,19 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
     markGlyphsToRender(glyphsToRender);
 }
 
-void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage> &glyphs)
+void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs)
 {
     QHash<TextureInfo *, QVector<glyph_t> > glyphTextures;
 
-    QHash<glyph_t, QImage>::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<glyph_t, QImage>
 
         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<glyph_t, QImage>
             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<TextureInfo *, QVector<glyph_t> >::const_iterator i;
     for (i = glyphTextures.constBegin(); i != glyphTextures.constEnd(); ++i) {
         Texture t;
@@ -198,7 +205,7 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &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;
index ef722d8..4ce3a50 100644 (file)
@@ -58,7 +58,7 @@ public:
     virtual ~QSGDefaultDistanceFieldGlyphCache();
 
     void requestGlyphs(const QSet<glyph_t> &glyphs);
-    void storeGlyphs(const QHash<glyph_t, QImage> &glyphs);
+    void storeGlyphs(const QList<QDistanceField> &glyphs);
     void referenceGlyphs(const QSet<glyph_t> &glyphs);
     void releaseGlyphs(const QSet<glyph_t> &glyphs);
 
@@ -73,7 +73,7 @@ private:
         GLuint texture;
         QSize size;
         QRect allocatedArea;
-        QImage image;
+        QDistanceField image;
 
         TextureInfo() : texture(0)
         { }
index 97bb429..c15263f 100644 (file)
@@ -300,7 +300,7 @@ void QSGSharedDistanceFieldGlyphCache::waitForGlyphs()
     }
 }
 
-void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage> &glyphs)
+void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs)
 {
     {
         QMutexLocker locker(&m_pendingGlyphsMutex);
@@ -312,14 +312,12 @@ void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
         int glyphCount = glyphs.size();
         QVector<quint32> glyphIds(glyphCount);
         QVector<QImage> images(glyphCount);
-        QHash<glyph_t, QImage>::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;
index ac613c1..2c57424 100644 (file)
@@ -66,7 +66,7 @@ public:
 
     void requestGlyphs(const QSet<glyph_t> &glyphs);
     void referenceGlyphs(const QSet<glyph_t> &glyphs);
-    void storeGlyphs(const QHash<glyph_t, QImage> &glyphs);
+    void storeGlyphs(const QList<QDistanceField> &glyphs);
     void releaseGlyphs(const QSet<glyph_t> &glyphs);
 
 Q_SIGNALS: