aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp86
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h59
2 files changed, 94 insertions, 51 deletions
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 05d076ec1e..5864f35060 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -62,6 +62,7 @@ QSGDefaultDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDefaultDistanceF
QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
: QSGDistanceFieldGlyphCache(man, c, font)
, m_maxTextureSize(0)
+ , m_maxTextureCount(3)
{
m_textureData = textureData(c);
}
@@ -77,25 +78,32 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
if (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty())
continue;
+ if (textureIsFull(m_textureData->currentTexture) && m_textureData->textures.count() < m_maxTextureCount)
+ m_textureData->currentTexture = m_textureData->addTexture();
+
m_textureData->unusedGlyphs.remove(glyphIndex);
+ DistanceFieldTextureData::TextureInfo *tex = m_textureData->currentTexture;
+
GlyphPosition p;
p.glyph = glyphIndex;
- p.position = QPointF(m_textureData->currX, m_textureData->currY);
+ p.position = QPointF(tex->currX, tex->currY);
if (!cacheIsFull()) {
- m_textureData->currX += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution());
- if (m_textureData->currX >= maxTextureSize()) {
- m_textureData->currX = 0;
- m_textureData->currY += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution());
+ tex->currX += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution());
+ if (tex->currX >= maxTextureSize()) {
+ tex->currX = 0;
+ tex->currY += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution());
}
} else {
// Recycle glyphs
if (!m_textureData->unusedGlyphs.isEmpty()) {
glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
+ tex = m_textureData->glyphsTexture.value(unusedGlyph);
p.position = QPointF(unusedCoord.x, unusedCoord.y);
m_textureData->unusedGlyphs.remove(unusedGlyph);
+ m_textureData->glyphsTexture.remove(unusedGlyph);
removeGlyph(unusedGlyph);
}
}
@@ -103,6 +111,7 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph
if (p.position.y() < maxTextureSize()) {
glyphPositions.append(p);
glyphsToRender.append(glyphIndex);
+ m_textureData->glyphsTexture.insert(glyphIndex, tex);
}
}
@@ -114,41 +123,46 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
{
int requiredWidth = maxTextureSize();
int rows = 128 / (requiredWidth / QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution())); // Enough rows to fill the latin1 set by default..
- int requiredHeight = qMin(maxTextureSize(),
- qMax(m_textureData->currY + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()),
- QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()) * rows));
-
- resizeTexture((requiredWidth), (requiredHeight));
- glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
- QVector<glyph_t> glyphTextures;
+ QHash<DistanceFieldTextureData::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();
TexCoord c = glyphTexCoord(glyphIndex);
+ DistanceFieldTextureData::TextureInfo *texInfo = m_textureData->glyphsTexture.value(glyphIndex);
- glyphTextures.append(glyphIndex);
+ int requiredHeight = qMin(maxTextureSize(),
+ qMax(texInfo->currY + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()),
+ QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()) * rows));
+
+ resizeTexture(texInfo, requiredWidth, requiredHeight);
+ glBindTexture(GL_TEXTURE_2D, texInfo->texture);
+
+ glyphTextures[texInfo].append(glyphIndex);
QImage glyph = it.value();
if (useWorkaroundBrokenFBOReadback()) {
uchar *inBits = glyph.scanLine(0);
- uchar *outBits = m_textureData->image.scanLine(int(c.y)) + int(c.x);
+ uchar *outBits = texInfo->image.scanLine(int(c.y)) + int(c.x);
for (int y = 0; y < glyph.height(); ++y) {
qMemCopy(outBits, inBits, glyph.width());
inBits += glyph.bytesPerLine();
- outBits += m_textureData->image.bytesPerLine();
+ outBits += texInfo->image.bytesPerLine();
}
}
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
}
- Texture t;
- t.textureId = m_textureData->texture;
- t.size = m_textureData->size;
- setGlyphsTexture(glyphTextures, t);
+ QHash<DistanceFieldTextureData::TextureInfo *, QVector<glyph_t> >::const_iterator i;
+ for (i = glyphTextures.constBegin(); i != glyphTextures.constEnd(); ++i) {
+ Texture t;
+ t.textureId = i.key()->texture;
+ t.size = i.key()->size;
+ setGlyphsTexture(i.value(), t);
+ }
}
void QSGDefaultDistanceFieldGlyphCache::referenceGlyphs(const QSet<glyph_t> &glyphs)
@@ -161,15 +175,15 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyph
m_textureData->unusedGlyphs += glyphs;
}
-void QSGDefaultDistanceFieldGlyphCache::createTexture(int width, int height)
+void QSGDefaultDistanceFieldGlyphCache::createTexture(DistanceFieldTextureData::TextureInfo *texInfo, int width, int height)
{
- if (useWorkaroundBrokenFBOReadback() && m_textureData->image.isNull())
- m_textureData->image = QImage(width, height, QImage::Format_Indexed8);
+ if (useWorkaroundBrokenFBOReadback() && texInfo->image.isNull())
+ texInfo->image = QImage(width, height, QImage::Format_Indexed8);
while (glGetError() != GL_NO_ERROR) { }
- glGenTextures(1, &m_textureData->texture);
- glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+ glGenTextures(1, &texInfo->texture);
+ glBindTexture(GL_TEXTURE_2D, texInfo->texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -177,35 +191,35 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(int width, int height)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- m_textureData->size = QSize(width, height);
+ texInfo->size = QSize(width, height);
GLuint error = glGetError();
if (error != GL_NO_ERROR) {
glBindTexture(GL_TEXTURE_2D, 0);
- glDeleteTextures(1, &m_textureData->texture);
- m_textureData->texture = 0;
+ glDeleteTextures(1, &texInfo->texture);
+ texInfo->texture = 0;
}
}
-void QSGDefaultDistanceFieldGlyphCache::resizeTexture(int width, int height)
+void QSGDefaultDistanceFieldGlyphCache::resizeTexture(DistanceFieldTextureData::TextureInfo *texInfo, int width, int height)
{
- int oldWidth = m_textureData->size.width();
- int oldHeight = m_textureData->size.height();
+ int oldWidth = texInfo->size.width();
+ int oldHeight = texInfo->size.height();
if (width == oldWidth && height == oldHeight)
return;
- GLuint oldTexture = m_textureData->texture;
- createTexture(width, height);
+ GLuint oldTexture = texInfo->texture;
+ createTexture(texInfo, width, height);
if (!oldTexture)
return;
- updateTexture(oldTexture, m_textureData->texture, m_textureData->size);
+ updateTexture(oldTexture, texInfo->texture, texInfo->size);
if (useWorkaroundBrokenFBOReadback()) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, m_textureData->image.constBits());
- m_textureData->image = m_textureData->image.copy(0, 0, width, height);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.constBits());
+ texInfo->image = texInfo->image.copy(0, 0, width, height);
glDeleteTextures(1, &oldTexture);
return;
}
@@ -267,7 +281,7 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(int width, int height)
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+ glBindTexture(GL_TEXTURE_2D, texInfo->texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index 76e4a64e60..12bbcce060 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -59,37 +59,55 @@ public:
void referenceGlyphs(const QSet<glyph_t> &glyphs);
void releaseGlyphs(const QSet<glyph_t> &glyphs);
- bool cacheIsFull() const { return m_textureData->currY >= maxTextureSize(); }
+ bool cacheIsFull() const {
+ return m_textureData->textures.count() == m_maxTextureCount
+ && textureIsFull(m_textureData->currentTexture);
+ }
bool useWorkaroundBrokenFBOReadback() const;
int maxTextureSize() const;
-private:
- void createTexture(int width, int height);
- void resizeTexture(int width, int height);
+ void setMaxTextureCount(int max) { m_maxTextureCount = max; }
+ int maxTextureCount() const { return m_maxTextureCount; }
+private:
mutable int m_maxTextureSize;
+ int m_maxTextureCount;
struct DistanceFieldTextureData : public QOpenGLSharedResource {
- GLuint texture;
+ struct TextureInfo {
+ GLuint texture;
+ QSize size;
+ int currX;
+ int currY;
+ QImage image;
+
+ TextureInfo() : texture(0), currX(0), currY(0)
+ { }
+ };
+
+ TextureInfo *currentTexture;
+ QList<TextureInfo> textures;
+ QHash<glyph_t, TextureInfo *> glyphsTexture;
GLuint fbo;
- QSize size;
QSet<glyph_t> unusedGlyphs;
- int currX;
- int currY;
- QImage image;
QOpenGLShaderProgram *blitProgram;
GLfloat blitVertexCoordinateArray[8];
GLfloat blitTextureCoordinateArray[8];
+ TextureInfo *addTexture()
+ {
+ textures.append(TextureInfo());
+ return &textures.last();
+ }
+
DistanceFieldTextureData(QOpenGLContext *ctx)
: QOpenGLSharedResource(ctx->shareGroup())
- , texture(0)
, fbo(0)
- , currX(0)
- , currY(0)
, blitProgram(0)
{
+ currentTexture = addTexture();
+
blitVertexCoordinateArray[0] = -1.0f;
blitVertexCoordinateArray[1] = -1.0f;
blitVertexCoordinateArray[2] = 1.0f;
@@ -111,19 +129,26 @@ private:
void invalidateResource()
{
- texture = 0;
+ glyphsTexture.clear();
+ textures.clear();
fbo = 0;
- size = QSize();
delete blitProgram;
blitProgram = 0;
+
+ currentTexture = addTexture();
}
void freeResource(QOpenGLContext *ctx)
{
- glDeleteTextures(1, &texture);
+ glyphsTexture.clear();
+ for (int i = 0; i < textures.count(); ++i)
+ glDeleteTextures(1, &textures[i].texture);
+ textures.clear();
ctx->functions()->glDeleteFramebuffers(1, &fbo);
delete blitProgram;
blitProgram = 0;
+
+ currentTexture = addTexture();
}
void createBlitProgram()
@@ -155,6 +180,10 @@ private:
}
};
+ void createTexture(DistanceFieldTextureData::TextureInfo * texInfo, int width, int height);
+ void resizeTexture(DistanceFieldTextureData::TextureInfo * texInfo, int width, int height);
+ bool textureIsFull (const DistanceFieldTextureData::TextureInfo *tex) const { return tex->currY >= maxTextureSize(); }
+
DistanceFieldTextureData *textureData(QOpenGLContext *c);
DistanceFieldTextureData *m_textureData;
static QHash<QString, QOpenGLMultiGroupSharedResource> m_textures_data;