diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 972bff80e081c45f434214497e73792e2ab129b6..57c0990f1dd3a35c3210da3e5ba21e2c423f3cc5 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -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;
+        }
     }
 }
 
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 5912802a84f837d12e677af2cb84477ad262f4b2..0c777ef639b96a541114243e9adff2876fe58ed1 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -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);
 
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 95ccc8f437d5323afbc71ece9ae20538a2f3304e..4f69ad8c44367fe87452d4c459e1aa05dded267a 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -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
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
index d3b90bed604da21fdb2f099f3e482a5ac1f10575..def4d9486b49586237ca6d5e3ab4bb5562963476 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -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;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index 164af0b2e729b65d3edd8908f15335860dac80a6..938fe9b42d08227cf93a66cca7e981a09d5f6c37 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -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;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
index 8096d4ae70cc6576e4d5afd01e6da0587d961eb9..0669fd4a80c907ec18e4408298367661eda3e70e 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -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;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
index dbdc6e249898470ad9fef57038dad7965622790f..d71cc48196e83878011f5c9308d6b8e2c9ce0472 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -69,7 +69,7 @@ public:
 
     QSize textureSize() const { return m_size; }
 
-    bool updateCache();
+    bool updateTextureSize();
 
 protected:
     QSize m_size;