aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@nokia.com>2011-12-13 11:18:33 +0100
committerQt by Nokia <qt-info@nokia.com>2011-12-14 09:06:21 +0100
commit17bffaa4d447959f08e16ca9a45885f631a16cc0 (patch)
treed5a014dd626e2fc07179938eedde661357cb5663 /src/quick
parent22a8387aeab93fd086b297443945487677aef280 (diff)
More distance-field cache refactoring.
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>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp37
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h4
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp7
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode.cpp148
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp10
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.h12
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h2
7 files changed, 105 insertions, 115 deletions
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 972bff80e0..57c0990f1d 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 5912802a84..0c777ef639 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 95ccc8f437..4f69ad8c44 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 d3b90bed60..def4d9486b 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 164af0b2e7..938fe9b42d 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 8096d4ae70..0669fd4a80 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 dbdc6e2498..d71cc48196 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;