aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@digia.com>2013-08-21 14:40:01 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-27 20:35:55 +0200
commit184e27c0e69f9f8c342339e83cdf79ec5a97b58e (patch)
tree0529dcf5a0b5b86b98c40d257f69ecb7dcb9b3ee
parentcb9672c86d2679bcb0d9e10f76b12eb03f4c515e (diff)
Updated distance field glyph caches to use QDistanceField.
Some OpenGL drivers assume alpha-only images are always tightly packed, regardless of what is set for GL_UNPACK_ALIGNMENT. We now use QDistanceField to store glyphs, which aligns scanlines on a 1-byte boundary, instead of QImage which uses a 4-byte boundary. A previous workaround uploaded scanlines one at a time, but this is also broken with some other drivers... Task-number: QTBUG-30908 Task-number: QTBUG-32861 Change-Id: I46527fb48de1e00116f776427c45baa752c6176d Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp10
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h2
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp37
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h4
-rw-r--r--src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp16
-rw-r--r--src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h2
6 files changed, 40 insertions, 31 deletions
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 3536975e94..3c8772252c 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -168,13 +168,11 @@ void QSGDistanceFieldGlyphCache::update()
qsg_render_timer.start();
#endif
- QHash<glyph_t, QImage> distanceFields;
-
+ QList<QDistanceField> distanceFields;
for (int i = 0; i < m_pendingGlyphs.size(); ++i) {
- glyph_t glyphIndex = m_pendingGlyphs.at(i);
-
- QImage distanceField = qt_renderDistanceFieldGlyph(m_referenceFont, glyphIndex, m_doubleGlyphResolution);
- distanceFields.insert(glyphIndex, distanceField);
+ distanceFields.append(QDistanceField(m_referenceFont,
+ m_pendingGlyphs.at(i),
+ m_doubleGlyphResolution));
}
#ifndef QSG_NO_RENDER_TIMING
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index cc22bfa61f..9e173101ba 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -230,7 +230,7 @@ protected:
};
virtual void requestGlyphs(const QSet<glyph_t> &glyphs) = 0;
- virtual void storeGlyphs(const QHash<glyph_t, QImage> &glyphs) = 0;
+ virtual void storeGlyphs(const QList<QDistanceField> &glyphs) = 0;
virtual void referenceGlyphs(const QSet<glyph_t> &glyphs) = 0;
virtual void releaseGlyphs(const QSet<glyph_t> &glyphs) = 0;
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 4652a2241e..884abd3edc 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -142,13 +142,19 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
markGlyphsToRender(glyphsToRender);
}
-void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage> &glyphs)
+void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs)
{
QHash<TextureInfo *, QVector<glyph_t> > glyphTextures;
- QHash<glyph_t, QImage>::const_iterator it;
- for (it = glyphs.constBegin(); it != glyphs.constEnd(); ++it) {
- glyph_t glyphIndex = it.key();
+ GLint alignment = 4; // default value
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+
+ // Distance field data is always tightly packed
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ for (int i = 0; i < glyphs.size(); ++i) {
+ QDistanceField glyph = glyphs.at(i);
+ glyph_t glyphIndex = glyph.glyph();
TexCoord c = glyphTexCoord(glyphIndex);
TextureInfo *texInfo = m_glyphsTexture.value(glyphIndex);
@@ -157,7 +163,6 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
glyphTextures[texInfo].append(glyphIndex);
- QImage glyph = it.value();
int expectedWidth = qCeil(c.width + c.xMargin * 2);
if (glyph.width() != expectedWidth)
glyph = glyph.copy(0, 0, expectedWidth, glyph.height());
@@ -167,15 +172,17 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
uchar *outBits = texInfo->image.scanLine(int(c.y)) + int(c.x);
for (int y = 0; y < glyph.height(); ++y) {
memcpy(outBits, inBits, glyph.width());
- inBits += glyph.bytesPerLine();
- outBits += texInfo->image.bytesPerLine();
+ inBits += glyph.width();
+ outBits += texInfo->image.width();
}
}
- for (int i = 0; i < glyph.height(); ++i)
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, glyph.width(), 1, GL_ALPHA, GL_UNSIGNED_BYTE, glyph.scanLine(i));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
}
+ // restore to previous alignment
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+
QHash<TextureInfo *, QVector<glyph_t> >::const_iterator i;
for (i = glyphTextures.constBegin(); i != glyphTextures.constEnd(); ++i) {
Texture t;
@@ -198,7 +205,7 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyph
void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int width, int height)
{
if (useWorkaround() && texInfo->image.isNull())
- texInfo->image = QImage(width, height, QImage::Format_Indexed8);
+ texInfo->image = QDistanceField(width, height);
while (glGetError() != GL_NO_ERROR) { }
@@ -243,8 +250,14 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
updateTexture(oldTexture, texInfo->texture, texInfo->size);
if (useWorkaround()) {
- for (int i = 0; i < oldHeight; ++i)
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, oldWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.scanLine(i));
+ GLint alignment = 4; // default value
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.constBits());
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); // restore to previous value
+
texInfo->image = texInfo->image.copy(0, 0, width, height);
glDeleteTextures(1, &oldTexture);
return;
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index ef722d85df..4ce3a50d1b 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -58,7 +58,7 @@ public:
virtual ~QSGDefaultDistanceFieldGlyphCache();
void requestGlyphs(const QSet<glyph_t> &glyphs);
- void storeGlyphs(const QHash<glyph_t, QImage> &glyphs);
+ void storeGlyphs(const QList<QDistanceField> &glyphs);
void referenceGlyphs(const QSet<glyph_t> &glyphs);
void releaseGlyphs(const QSet<glyph_t> &glyphs);
@@ -73,7 +73,7 @@ private:
GLuint texture;
QSize size;
QRect allocatedArea;
- QImage image;
+ QDistanceField image;
TextureInfo() : texture(0)
{ }
diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
index 97bb4295f7..c15263f53f 100644
--- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
@@ -300,7 +300,7 @@ void QSGSharedDistanceFieldGlyphCache::waitForGlyphs()
}
}
-void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage> &glyphs)
+void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs)
{
{
QMutexLocker locker(&m_pendingGlyphsMutex);
@@ -312,14 +312,12 @@ void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
int glyphCount = glyphs.size();
QVector<quint32> glyphIds(glyphCount);
QVector<QImage> images(glyphCount);
- QHash<glyph_t, QImage>::const_iterator it = glyphs.constBegin();
- int i=0;
- while (it != glyphs.constEnd()) {
- m_requestedGlyphsThatHaveNotBeenReturned.insert(it.key());
- glyphIds[i] = it.key();
- images[i] = it.value();
-
- ++it; ++i;
+ for (int i = 0; i < glyphs.size(); ++i) {
+ const QDistanceField &df = glyphs.at(i);
+ m_requestedGlyphsThatHaveNotBeenReturned.insert(df.glyph());
+ glyphIds[i] = df.glyph();
+ // ### TODO: Handle QDistanceField in QPlatformSharedGraphicsCache
+ images[i] = df.toImage(QImage::Format_Indexed8);
}
m_hasPostedEvents = true;
diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h
index ac613c16f4..2c574246b6 100644
--- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h
@@ -66,7 +66,7 @@ public:
void requestGlyphs(const QSet<glyph_t> &glyphs);
void referenceGlyphs(const QSet<glyph_t> &glyphs);
- void storeGlyphs(const QHash<glyph_t, QImage> &glyphs);
+ void storeGlyphs(const QList<QDistanceField> &glyphs);
void releaseGlyphs(const QSet<glyph_t> &glyphs);
Q_SIGNALS: