More distance-field cache refactoring.
authorYoann Lopes <yoann.lopes@nokia.com>
Tue, 13 Dec 2011 10:18:33 +0000 (11:18 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 14 Dec 2011 08:06:21 +0000 (09:06 +0100)
The distance field glyph node now uses preprocess().
The glyph cache is updated at that time, then when all the glyphs are
ready the node's geometry is updated.

addGlyphPositions and addGlyphTextures in QSGDistanceFieldGlyphCache
have been renamed to setGlyphsPosition and setGlyphsTexture to reflect the
fact that they can be used to update existing glyphs. For example when
a glyph has moved to a different texture.
When an existing glyph is updated, all nodes containing that glyph are
invalidated and their geometries are reconstructed with the new values.

Change-Id: I7758313155f48811e6027434e6c9a1c3df5dfab7
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
src/quick/scenegraph/qsgadaptationlayer.cpp
src/quick/scenegraph/qsgadaptationlayer_p.h
src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h

index 972bff8..57c0990 100644 (file)
@@ -228,8 +228,10 @@ void QSGDistanceFieldGlyphCache::update()
     storeGlyphs(distanceFields);
 }
 
-void QSGDistanceFieldGlyphCache::addGlyphPositions(const QList<GlyphPosition> &glyphs)
+void QSGDistanceFieldGlyphCache::setGlyphsPosition(const QList<GlyphPosition> &glyphs)
 {
+    QVector<quint32> invalidatedGlyphs;
+
     int count = glyphs.count();
     for (int i = 0; i < count; ++i) {
         GlyphPosition glyph = glyphs.at(i);
@@ -244,11 +246,22 @@ void QSGDistanceFieldGlyphCache::addGlyphPositions(const QList<GlyphPosition> &g
         c.width = br.width();
         c.height = br.height();
 
+        if (m_cacheData->texCoords.contains(glyph.glyph))
+            invalidatedGlyphs.append(glyph.glyph);
+
         m_cacheData->texCoords.insert(glyph.glyph, c);
     }
+
+    if (!invalidatedGlyphs.isEmpty()) {
+        QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
+        while (it != m_cacheData->m_registeredNodes.end()) {
+            (*it)->invalidateGlyphs(invalidatedGlyphs);
+            ++it;
+        }
+    }
 }
 
-void QSGDistanceFieldGlyphCache::addGlyphTextures(const QVector<glyph_t> &glyphs, const Texture &tex)
+void QSGDistanceFieldGlyphCache::setGlyphsTexture(const QVector<glyph_t> &glyphs, const Texture &tex)
 {
     int i = m_cacheData->textures.indexOf(tex);
     if (i == -1) {
@@ -259,14 +272,22 @@ void QSGDistanceFieldGlyphCache::addGlyphTextures(const QVector<glyph_t> &glyphs
     }
     Texture *texture = &(m_cacheData->textures[i]);
 
+    QVector<quint32> invalidatedGlyphs;
+
     int count = glyphs.count();
-    for (int j = 0; j < count; ++j)
-        m_cacheData->glyphTextures.insert(glyphs.at(j), texture);
+    for (int j = 0; j < count; ++j) {
+        glyph_t glyphIndex = glyphs.at(j);
+        if (m_cacheData->glyphTextures.contains(glyphIndex))
+            invalidatedGlyphs.append(glyphIndex);
+        m_cacheData->glyphTextures.insert(glyphIndex, texture);
+    }
 
-    QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
-    while (it != m_cacheData->m_registeredNodes.end()) {
-        (*it)->updateGeometry();
-        ++it;
+    if (!invalidatedGlyphs.isEmpty()) {
+        QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
+        while (it != m_cacheData->m_registeredNodes.end()) {
+            (*it)->invalidateGlyphs(invalidatedGlyphs);
+            ++it;
+        }
     }
 }
 
index 5912802..0c777ef 100644 (file)
@@ -195,8 +195,8 @@ protected:
     virtual void storeGlyphs(const QHash<glyph_t, QImage> &glyphs) = 0;
     virtual void releaseGlyphs(const QVector<glyph_t> &glyphs) = 0;
 
-    void addGlyphPositions(const QList<GlyphPosition> &glyphs);
-    void addGlyphTextures(const QVector<glyph_t> &glyphs, const Texture &tex);
+    void setGlyphsPosition(const QList<GlyphPosition> &glyphs);
+    void setGlyphsTexture(const QVector<glyph_t> &glyphs, const Texture &tex);
     void markGlyphsToRender(const QVector<glyph_t> &glyphs);
     void removeGlyph(glyph_t glyph);
 
index 95ccc8f..4f69ad8 100644 (file)
@@ -117,7 +117,7 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QVector<glyph_t> &gl
         }
     }
 
-    addGlyphPositions(glyphPositions);
+    setGlyphsPosition(glyphPositions);
     markGlyphsToRender(glyphsToRender);
 }
 
@@ -159,7 +159,7 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
     Texture t;
     t.textureId = m_textureData->texture;
     t.size = m_textureData->size;
-    addGlyphTextures(glyphTextures, t);
+    setGlyphsTexture(glyphTextures, t);
 }
 
 void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QVector<glyph_t> &glyphs)
@@ -300,6 +300,9 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(int width, int height)
         glEnable(GL_BLEND);
     glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
     ctx->functions()->glUseProgram(oldProgram);
+
+    m_textureData->blitProgram->disableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
+    m_textureData->blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
 }
 
 bool QSGDefaultDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
index d3b90be..def4d94 100644 (file)
@@ -56,6 +56,7 @@ QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheM
     , m_dirtyGeometry(false)
     , m_dirtyMaterial(false)
 {
+    setFlag(UsePreprocess);
     m_geometry.setDrawingMode(GL_TRIANGLES);
     setGeometry(&m_geometry);
     setPreferredAntialiasingMode(cacheManager->defaultAntialiasingMode());
@@ -106,13 +107,10 @@ void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphR
     m_glyph_cache->populate(glyphs.glyphIndexes());
 
     const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
-    const QVector<QPointF> &glyphPositions = m_glyphs.positions();
-    for (int i = 0; i < glyphIndexes.size(); ++i) {
-        GlyphInfo g;
-        g.glyphIndex = glyphIndexes.at(i);
-        g.position = glyphPositions.at(i);
-        m_glyphsToAdd.append(g);
-    }
+    m_allGlyphIndexes += glyphIndexes;
+    m_allGlyphPositions += m_glyphs.positions();
+    for (int i = 0; i < glyphIndexes.count(); ++i)
+        m_allGlyphIndexesLookup.insert(glyphIndexes.at(i));
 
     m_dirtyGeometry = true;
     m_dirtyMaterial = true;
@@ -138,68 +136,70 @@ void QSGDistanceFieldGlyphNode::update()
 {
     if (m_dirtyMaterial)
         updateMaterial();
+}
+
+void QSGDistanceFieldGlyphNode::preprocess()
+{
+    Q_ASSERT(m_glyph_cache);
+
+    m_glyph_cache->update();
+
     if (m_dirtyGeometry)
         updateGeometry();
 }
 
+void QSGDistanceFieldGlyphNode::invalidateGlyphs(const QVector<quint32> &glyphs)
+{
+    if (m_dirtyGeometry)
+        return;
+
+    for (int i = 0; i < glyphs.count(); ++i) {
+        if (m_allGlyphIndexesLookup.contains(glyphs.at(i))) {
+            m_dirtyGeometry = true;
+            return;
+        }
+    }
+}
+
 void QSGDistanceFieldGlyphNode::updateGeometry()
 {
     Q_ASSERT(m_glyph_cache);
 
-    if (m_glyphsToAdd.isEmpty())
-        return;
-
     QSGGeometry *g = geometry();
 
     Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
 
-    int oldVertexCount = g->vertexCount();
-    int oldIndexCount = g->indexCount();
+    g->allocate(m_allGlyphIndexes.size() * 4, m_allGlyphIndexes.size() * 6);
 
-    QVector<QSGGeometry::TexturedPoint2D> vp;
-    vp.reserve(m_glyphsToAdd.size() * 4);
-    QVector<ushort> ip;
-    ip.reserve(m_glyphsToAdd.size() * 6);
+    QSGGeometry::TexturedPoint2D *vp = g->vertexDataAsTexturedPoint2D();
+    ushort *ip = g->indexDataAsUShort();
 
     QPointF margins(2, 2);
     QPointF texMargins = margins / m_glyph_cache->fontScale();
 
     const QSGDistanceFieldGlyphCache::Texture *textureToUse = 0;
 
-    QLinkedList<GlyphInfo>::iterator it = m_glyphsToAdd.begin();
-    while (it != m_glyphsToAdd.end()) {
-        quint32 glyphIndex = it->glyphIndex;
+    for (int i = 0; i < m_allGlyphIndexes.size(); ++i) {
+        quint32 glyphIndex = m_allGlyphIndexes.at(i);
+        QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
         QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
 
-        if (c.isNull()) {
-            if (!c.isValid())
-                ++it;
-            else
-                it = m_glyphsToAdd.erase(it);
-            continue;
-        }
-
         const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphIndex);
-        if (!texture->textureId) {
-            ++it;
-            continue;
-        }
-
-        QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
-
-        if (!textureToUse)
+        if (texture->textureId && !textureToUse)
             textureToUse = texture;
 
-        metrics.width += margins.x() * 2;
-        metrics.height += margins.y() * 2;
-        metrics.baselineX -= margins.x();
-        metrics.baselineY += margins.y();
-        c.xMargin -= texMargins.x();
-        c.yMargin -= texMargins.y();
-        c.width += texMargins.x() * 2;
-        c.height += texMargins.y() * 2;
+        if (!metrics.isNull() && !c.isNull()) {
+            metrics.width += margins.x() * 2;
+            metrics.height += margins.y() * 2;
+            metrics.baselineX -= margins.x();
+            metrics.baselineY += margins.y();
+            c.xMargin -= texMargins.x();
+            c.yMargin -= texMargins.y();
+            c.width += texMargins.x() * 2;
+            c.height += texMargins.y() * 2;
+        }
 
-        const QPointF &glyphPosition = it->position;
+        const QPointF &glyphPosition = m_allGlyphPositions.at(i);
         qreal x = glyphPosition.x() + metrics.baselineX + m_position.x();
         qreal y = glyphPosition.y() - metrics.baselineY + m_position.y();
 
@@ -218,55 +218,21 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
         if (m_baseLine.isNull())
             m_baseLine = glyphPosition;
 
-        int i = vp.size();
-
-        QSGGeometry::TexturedPoint2D v1;
-        v1.set(cx1, cy1, tx1, ty1);
-        QSGGeometry::TexturedPoint2D v2;
-        v2.set(cx2, cy1, tx2, ty1);
-        QSGGeometry::TexturedPoint2D v3;
-        v3.set(cx1, cy2, tx1, ty2);
-        QSGGeometry::TexturedPoint2D v4;
-        v4.set(cx2, cy2, tx2, ty2);
-        vp.append(v1);
-        vp.append(v2);
-        vp.append(v3);
-        vp.append(v4);
-
-        int o = i + oldVertexCount;
-        ip.append(o + 0);
-        ip.append(o + 2);
-        ip.append(o + 3);
-        ip.append(o + 3);
-        ip.append(o + 1);
-        ip.append(o + 0);
-
-        it = m_glyphsToAdd.erase(it);
+        int vi = i & 1 ? (m_allGlyphIndexes.size() + 1) / 2 + i / 2 : i / 2;
+        vp[4 * vi + 0].set(cx1, cy1, tx1, ty1);
+        vp[4 * vi + 1].set(cx2, cy1, tx2, ty1);
+        vp[4 * vi + 2].set(cx1, cy2, tx1, ty2);
+        vp[4 * vi + 3].set(cx2, cy2, tx2, ty2);
+
+        int o = i * 4;
+        ip[6 * i + 0] = o + 0;
+        ip[6 * i + 1] = o + 2;
+        ip[6 * i + 2] = o + 3;
+        ip[6 * i + 3] = o + 3;
+        ip[6 * i + 4] = o + 1;
+        ip[6 * i + 5] = o + 0;
     }
 
-    if (vp.isEmpty())
-        return;
-
-    void *data = 0;
-    if (oldVertexCount && oldIndexCount) {
-        int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)
-                     + oldIndexCount * sizeof(quint16);
-        data = qMalloc(byteSize);
-        memcpy(data, g->vertexData(), byteSize);
-    }
-
-    g->allocate(oldVertexCount + vp.size(), oldIndexCount + ip.size());
-
-    if (data) {
-        memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D));
-        memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D),
-               oldIndexCount * sizeof(quint16));
-        qFree(data);
-    }
-
-    memcpy(g->vertexDataAsTexturedPoint2D() + oldVertexCount, vp.constData(), vp.size() * sizeof(QSGGeometry::TexturedPoint2D));
-    memcpy(g->indexDataAsUShort() + oldIndexCount, ip.constData(), ip.size() * sizeof(quint16));
-
     setBoundingRect(m_boundingRect);
     markDirty(DirtyGeometry);
     m_dirtyGeometry = false;
index 164af0b..938fe9b 100644 (file)
@@ -138,7 +138,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
     QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
     QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
 
-    bool updated = material->updateCache();
+    bool updated = material->updateTextureSize();
 
     if (oldMaterial == 0
            || material->color() != oldMaterial->color()
@@ -207,15 +207,13 @@ QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const
     return new QSGDistanceFieldTextMaterialShader;
 }
 
-bool QSGDistanceFieldTextMaterial::updateCache()
+bool QSGDistanceFieldTextMaterial::updateTextureSize()
 {
-    m_glyph_cache->update();
     if (!m_texture)
         m_texture = m_glyph_cache->glyphTexture(-1); // invalid texture
-    QSize glyphCacheSize = m_texture->size;
-    if (glyphCacheSize != m_size) {
-        m_size = glyphCacheSize;
 
+    if (m_texture->size != m_size) {
+        m_size = m_texture->size;
         return true;
     } else {
         return false;
index 8096d4a..0669fd4 100644 (file)
@@ -70,6 +70,10 @@ public:
 
     virtual void update();
 
+    void preprocess();
+
+    void invalidateGlyphs(const QVector<quint32> &glyphs);
+
     void updateGeometry();
 
 private:
@@ -88,11 +92,9 @@ private:
     AntialiasingMode m_antialiasingMode;
     QRectF m_boundingRect;
 
-    struct GlyphInfo {
-        quint32 glyphIndex;
-        QPointF position;
-    };
-    QLinkedList<GlyphInfo> m_glyphsToAdd;
+    QVector<quint32> m_allGlyphIndexes;
+    QSet<quint32> m_allGlyphIndexesLookup;
+    QVector<QPointF> m_allGlyphPositions;
 
     uint m_dirtyGeometry: 1;
     uint m_dirtyMaterial: 1;
index dbdc6e2..d71cc48 100644 (file)
@@ -69,7 +69,7 @@ public:
 
     QSize textureSize() const { return m_size; }
 
-    bool updateCache();
+    bool updateTextureSize();
 
 protected:
     QSize m_size;