Skip to content

Commit

Permalink
Use a single distance-field cache instance for all sizes of a given f…
Browse files Browse the repository at this point in the history
…ont.

Previously we had a different cache instance for each font size, but
they all shared the same textures and positions. Only the glyph metrics
were specific to each font size.
The metrics for each font sizes are now calculated by scaling the metrics
of the distance-field size (54px).

Change-Id: I0d9016990dedd93318893506afb1dba7a5249e2e
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
  • Loading branch information
Yoann Lopes authored and Qt by Nokia committed Mar 19, 2012
1 parent 3bf01de commit b271abe
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 314 deletions.
186 changes: 63 additions & 123 deletions src/quick/scenegraph/qsgadaptationlayer.cpp
Expand Up @@ -45,90 +45,60 @@
#include <QtQuick/private/qsgdistancefieldutil_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
#include <private/qrawfont_p.h>
#include <private/qdistancefield_p.h>
#include <QtGui/qguiapplication.h>
#include <qdir.h>

QT_BEGIN_NAMESPACE


QHash<QString, QOpenGLMultiGroupSharedResource> QSGDistanceFieldGlyphCache::m_caches_data;
QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture;

QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
: ctx(c)
, m_manager(man)
, m_pendingGlyphs(64)
{
Q_ASSERT(font.isValid());
m_font = font;

m_cacheData = cacheData();

QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
QRawFontPrivate *fontD = QRawFontPrivate::get(font);
m_glyphCount = fontD->fontEngine->glyphCount();

m_cacheData->doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;

m_referenceFont = m_font;
m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution));
m_referenceFont = font;
m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution));
Q_ASSERT(m_referenceFont.isValid());
}

QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
{
}

QSGDistanceFieldGlyphCache::GlyphCacheData *QSGDistanceFieldGlyphCache::cacheData()
{
QString key = QString::fromLatin1("%1_%2_%3_%4")
.arg(m_font.familyName())
.arg(m_font.styleName())
.arg(m_font.weight())
.arg(m_font.style());
return m_caches_data[key].value<QSGDistanceFieldGlyphCache::GlyphCacheData>(ctx);
}

qreal QSGDistanceFieldGlyphCache::fontScale() const
QSGDistanceFieldGlyphCache::GlyphData &QSGDistanceFieldGlyphCache::glyphData(glyph_t glyph)
{
return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution);
QHash<glyph_t, GlyphData>::iterator data = m_glyphsData.find(glyph);
if (data == m_glyphsData.end()) {
GlyphData gd;
gd.texture = &s_emptyTexture;
QPainterPath path = m_referenceFont.pathForGlyph(glyph);
gd.boundingRect = path.boundingRect();
data = m_glyphsData.insert(glyph, gd);
}

int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
{
return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution);
return data.value();
}

QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph, qreal pixelSize)
{
QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
if (metric == m_metrics.end()) {
QPainterPath path = m_font.pathForGlyph(glyph);
QRectF br = path.boundingRect();
GlyphData &gd = glyphData(glyph);
qreal scale = fontScale(pixelSize);

Metrics m;
m.width = br.width();
m.height = br.height();
m.baselineX = br.x();
m.baselineY = -br.y();

metric = m_metrics.insert(glyph, m);
}
m.width = gd.boundingRect.width() * scale;
m.height = gd.boundingRect.height() * scale;
m.baselineX = gd.boundingRect.x() * scale;
m.baselineY = -gd.boundingRect.y() * scale;

return metric.value();
}

QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph) const
{
return m_cacheData->texCoords.value(glyph);
}

static QSGDistanceFieldGlyphCache::Texture g_emptyTexture;

const QSGDistanceFieldGlyphCache::Texture *QSGDistanceFieldGlyphCache::glyphTexture(glyph_t glyph) const
{
QHash<glyph_t, Texture*>::const_iterator it = m_cacheData->glyphTextures.find(glyph);
if (it == m_cacheData->glyphTextures.constEnd())
return &g_emptyTexture;
return it.value();
return m;
}

void QSGDistanceFieldGlyphCache::populate(const QVector<glyph_t> &glyphs)
Expand All @@ -143,22 +113,17 @@ void QSGDistanceFieldGlyphCache::populate(const QVector<glyph_t> &glyphs)
continue;
}

++m_cacheData->glyphRefCount[glyphIndex];
GlyphData &gd = glyphData(glyphIndex);
++gd.ref;
referencedGlyphs.insert(glyphIndex);

if (m_cacheData->texCoords.contains(glyphIndex) || newGlyphs.contains(glyphIndex))
if (gd.texCoord.isValid() || newGlyphs.contains(glyphIndex))
continue;

QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
m_cacheData->glyphPaths.insert(glyphIndex, path);
if (path.isEmpty()) {
TexCoord c;
c.width = 0;
c.height = 0;
m_cacheData->texCoords.insert(glyphIndex, c);
continue;
}
gd.texCoord.width = 0;
gd.texCoord.height = 0;

if (!gd.boundingRect.isEmpty())
newGlyphs.insert(glyphIndex);
}

Expand All @@ -175,15 +140,16 @@ void QSGDistanceFieldGlyphCache::release(const QVector<glyph_t> &glyphs)
int count = glyphs.count();
for (int i = 0; i < count; ++i) {
glyph_t glyphIndex = glyphs.at(i);
if (--m_cacheData->glyphRefCount[glyphIndex] == 0 && !glyphTexCoord(glyphIndex).isNull())
GlyphData &gd = glyphData(glyphIndex);
if (--gd.ref == 0 && !gd.texCoord.isNull())
unusedGlyphs.insert(glyphIndex);
}
releaseGlyphs(unusedGlyphs);
}

void QSGDistanceFieldGlyphCache::update()
{
if (m_cacheData->pendingGlyphs.isEmpty())
if (m_pendingGlyphs.isEmpty())
return;

QHash<glyph_t, QImage> distanceFields;
Expand All @@ -194,16 +160,16 @@ void QSGDistanceFieldGlyphCache::update()
QString tmpPath = QString::fromLatin1("%1/.qt/").arg(QDir::tempPath());
QString keyBase = QString::fromLatin1("%1%2%3_%4_%5_%6.fontblob")
.arg(tmpPath)
.arg(m_font.familyName())
.arg(m_font.styleName())
.arg(m_font.weight())
.arg(m_font.style());
.arg(m_referenceFont.familyName())
.arg(m_referenceFont.styleName())
.arg(m_referenceFont.weight())
.arg(m_referenceFont.style());

if (cacheDistanceFields && !QFile::exists(tmpPath))
QDir(tmpPath).mkpath(tmpPath);

for (int i = 0; i < m_cacheData->pendingGlyphs.size(); ++i) {
glyph_t glyphIndex = m_cacheData->pendingGlyphs.at(i);
for (int i = 0; i < m_pendingGlyphs.size(); ++i) {
glyph_t glyphIndex = m_pendingGlyphs.at(i);

if (cacheDistanceFields) {
QString key = keyBase.arg(glyphIndex);
Expand All @@ -219,7 +185,7 @@ void QSGDistanceFieldGlyphCache::update()
}
}

QImage distanceField = qt_renderDistanceFieldGlyph(m_font, glyphIndex, m_cacheData->doubleGlyphResolution);
QImage distanceField = qt_renderDistanceFieldGlyph(m_referenceFont, glyphIndex, m_doubleGlyphResolution);
distanceFields.insert(glyphIndex, distanceField);

if (cacheDistanceFields) {
Expand All @@ -230,7 +196,7 @@ void QSGDistanceFieldGlyphCache::update()
}
}

m_cacheData->pendingGlyphs.reset();
m_pendingGlyphs.reset();

storeGlyphs(distanceFields);
}
Expand All @@ -242,28 +208,22 @@ void QSGDistanceFieldGlyphCache::setGlyphsPosition(const QList<GlyphPosition> &g
int count = glyphs.count();
for (int i = 0; i < count; ++i) {
GlyphPosition glyph = glyphs.at(i);
GlyphData &gd = glyphData(glyph.glyph);

Q_ASSERT(m_cacheData->glyphPaths.contains(glyph.glyph));

QPainterPath path = m_cacheData->glyphPaths.value(glyph.glyph);
QRectF br = path.boundingRect();
TexCoord c;
c.xMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution));
c.yMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution));
c.x = glyph.position.x();
c.y = glyph.position.y();
c.width = br.width();
c.height = br.height();

if (m_cacheData->texCoords.contains(glyph.glyph))
if (!gd.texCoord.isNull())
invalidatedGlyphs.append(glyph.glyph);

m_cacheData->texCoords.insert(glyph.glyph, c);
gd.texCoord.xMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
gd.texCoord.yMargin = QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
gd.texCoord.x = glyph.position.x();
gd.texCoord.y = glyph.position.y();
gd.texCoord.width = gd.boundingRect.width();
gd.texCoord.height = gd.boundingRect.height();
}

if (!invalidatedGlyphs.isEmpty()) {
QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
while (it != m_cacheData->m_registeredNodes.end()) {
QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_registeredNodes.begin();
while (it != m_registeredNodes.end()) {
(*it)->invalidateGlyphs(invalidatedGlyphs);
++it;
}
Expand All @@ -287,28 +247,29 @@ void QSGDistanceFieldGlyphCache::processPendingGlyphs()

void QSGDistanceFieldGlyphCache::setGlyphsTexture(const QVector<glyph_t> &glyphs, const Texture &tex)
{
int i = m_cacheData->textures.indexOf(tex);
int i = m_textures.indexOf(tex);
if (i == -1) {
m_cacheData->textures.append(tex);
i = m_cacheData->textures.size() - 1;
m_textures.append(tex);
i = m_textures.size() - 1;
} else {
m_cacheData->textures[i].size = tex.size;
m_textures[i].size = tex.size;
}
Texture *texture = &(m_cacheData->textures[i]);
Texture *texture = &(m_textures[i]);

QVector<quint32> invalidatedGlyphs;

int count = glyphs.count();
for (int j = 0; j < count; ++j) {
glyph_t glyphIndex = glyphs.at(j);
if (m_cacheData->glyphTextures.contains(glyphIndex))
GlyphData &gd = glyphData(glyphIndex);
if (gd.texture != &s_emptyTexture)
invalidatedGlyphs.append(glyphIndex);
m_cacheData->glyphTextures.insert(glyphIndex, texture);
gd.texture = texture;
}

if (!invalidatedGlyphs.isEmpty()) {
QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
while (it != m_cacheData->m_registeredNodes.end()) {
QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_registeredNodes.begin();
while (it != m_registeredNodes.end()) {
(*it)->invalidateGlyphs(invalidatedGlyphs);
++it;
}
Expand All @@ -319,20 +280,14 @@ void QSGDistanceFieldGlyphCache::markGlyphsToRender(const QVector<glyph_t> &glyp
{
int count = glyphs.count();
for (int i = 0; i < count; ++i)
m_cacheData->pendingGlyphs.add(glyphs.at(i));
}

void QSGDistanceFieldGlyphCache::removeGlyph(glyph_t glyph)
{
m_cacheData->texCoords.remove(glyph);
m_cacheData->glyphTextures.remove(glyph);
m_pendingGlyphs.add(glyphs.at(i));
}

void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize)
{
int count = m_cacheData->textures.count();
int count = m_textures.count();
for (int i = 0; i < count; ++i) {
Texture &tex = m_cacheData->textures[i];
Texture &tex = m_textures[i];
if (tex.textureId == oldTex) {
tex.textureId = newTex;
tex.size = newTexSize;
Expand All @@ -341,20 +296,5 @@ void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, con
}
}

bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph) const
{
return m_cacheData->texCoords.contains(glyph);
}

void QSGDistanceFieldGlyphCache::registerGlyphNode(QSGDistanceFieldGlyphNode *node)
{
m_cacheData->m_registeredNodes.append(node);
}

void QSGDistanceFieldGlyphCache::unregisterGlyphNode(QSGDistanceFieldGlyphNode *node)
{
m_cacheData->m_registeredNodes.removeOne(node);
}


QT_END_NAMESPACE

0 comments on commit b271abe

Please sign in to comment.