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;