diff options
Diffstat (limited to 'src/quick/scenegraph')
7 files changed, 170 insertions, 112 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index ee9fd9fbbb..8012af9cfc 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -63,14 +63,14 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity) This function should return a mask where each bit represents OpenGL states changed by the \l render() function: \list - \o DepthState - depth write mask, depth test enabled, depth comparison function - \o StencilState - stencil write masks, stencil test enabled, stencil operations, + \li DepthState - depth write mask, depth test enabled, depth comparison function + \li StencilState - stencil write masks, stencil test enabled, stencil operations, stencil comparison functions - \o ScissorState - scissor enabled, scissor test enabled - \o ColorState - clear color, color write mask - \o BlendState - blend enabled, blend function - \o CullState - front face, cull face enabled - \o ViewportState - viewport + \li ScissorState - scissor enabled, scissor test enabled + \li ColorState - clear color, color write mask + \li BlendState - blend enabled, blend function + \li CullState - front face, cull face enabled + \li ViewportState - viewport \endlist The function is called by the renderer so it can reset the OpenGL states after rendering this @@ -96,17 +96,17 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity) The following states are set before this function is called: \list - \o glDepthMask(false) - \o glDisable(GL_DEPTH_TEST) - \o glStencilMask(0) - \o glEnable(GL_STENCIL_TEST)/glDisable(GL_STENCIL_TEST) depending on clip - \o glStencilFunc(GL_EQUAL, state.stencilValue, 0xff) depending on clip - \o glEnable(GL_SCISSOR_TEST)/glDisable(GL_SCISSOR_TEST) depending on clip - \o glScissor(state.scissorRect.x(), state.scissorRect.y(), + \li glDepthMask(false) + \li glDisable(GL_DEPTH_TEST) + \li glStencilMask(0) + \li glEnable(GL_STENCIL_TEST)/glDisable(GL_STENCIL_TEST) depending on clip + \li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff) depending on clip + \li glEnable(GL_SCISSOR_TEST)/glDisable(GL_SCISSOR_TEST) depending on clip + \li glScissor(state.scissorRect.x(), state.scissorRect.y(), state.scissorRect.width(), state.scissorRect.height()) depending on clip - \o glEnable(GL_BLEND) - \o glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) - \o glDisable(GL_CULL_FACE) + \li glEnable(GL_BLEND) + \li glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) + \li glDisable(GL_CULL_FACE) \endlist States that are not listed above, but are included in \l StateFlags, can have arbitrary 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; diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 79e5c3b0f4..a86e663755 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -71,11 +71,9 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode() delete m_material; if (m_glyph_cache) { - QVector<quint32> glyphIndexes; - for (int i = 0; i < m_allGlyphs.count(); ++i) - glyphIndexes.append(m_allGlyphs.at(i).glyphIndex); - m_glyph_cache->release(glyphIndexes); + m_glyph_cache->release(m_glyphs.glyphIndexes()); m_glyph_cache->unregisterGlyphNode(this); + m_glyph_cache->unregisterOwnerElement(ownerElement()); } for (int i = 0; i < m_nodesToDelete.count(); ++i) @@ -122,15 +120,9 @@ 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.count(); ++i) { - GlyphInfo gi; - gi.glyphIndex = glyphIndexes.at(i); - gi.position = glyphPositions.at(i); - m_allGlyphs.append(gi); - m_allGlyphIndexesLookup.insert(gi.glyphIndex); - } + const QVector<quint32> glyphIndexes = m_glyphs.glyphIndexes(); + for (int i = 0; i < glyphIndexes.count(); ++i) + m_allGlyphIndexesLookup.insert(glyphIndexes.at(i)); m_dirtyGeometry = true; m_dirtyMaterial = true; @@ -204,34 +196,43 @@ void QSGDistanceFieldGlyphNode::updateGeometry() Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT); - QHash<const QSGDistanceFieldGlyphCache::Texture *, QList<GlyphInfo> > glyphsInOtherTextures; + QHash<const QSGDistanceFieldGlyphCache::Texture *, GlyphInfo> glyphsInOtherTextures; + + const QVector<quint32> indexes = m_glyphs.glyphIndexes(); + const QVector<QPointF> positions = m_glyphs.positions(); QVector<QSGGeometry::TexturedPoint2D> vp; - vp.reserve(m_allGlyphs.size() * 4); + vp.reserve(indexes.size() * 4); QVector<ushort> ip; - ip.reserve(m_allGlyphs.size() * 6); + ip.reserve(indexes.size() * 6); QPointF margins(2, 2); QPointF texMargins = margins / m_glyph_cache->fontScale(); - for (int i = 0; i < m_allGlyphs.size(); ++i) { - GlyphInfo glyphInfo = m_allGlyphs.at(i); - QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphInfo.glyphIndex); + + for (int i = 0; i < indexes.size(); ++i) { + const int glyphIndex = indexes.at(i); + QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex); if (c.isNull()) continue; - const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphInfo.glyphIndex); + const QPointF position = positions.at(i); + + const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphIndex); if (texture->textureId && !m_texture) m_texture = texture; if (m_texture != texture) { - if (texture->textureId) - glyphsInOtherTextures[texture].append(glyphInfo); + if (texture->textureId) { + GlyphInfo &glyphInfo = glyphsInOtherTextures[texture]; + glyphInfo.indexes.append(glyphIndex); + glyphInfo.positions.append(position); + } continue; } - QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphInfo.glyphIndex); + QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex); if (!metrics.isNull() && !c.isNull()) { metrics.width += margins.x() * 2; @@ -244,8 +245,8 @@ void QSGDistanceFieldGlyphNode::updateGeometry() c.height += texMargins.y() * 2; } - qreal x = glyphInfo.position.x() + metrics.baselineX + m_position.x(); - qreal y = glyphInfo.position.y() - metrics.baselineY + m_position.y(); + qreal x = position.x() + metrics.baselineX + m_position.x(); + qreal y = position.y() - metrics.baselineY + m_position.y(); m_boundingRect |= QRectF(x, y, metrics.width, metrics.height); @@ -260,7 +261,7 @@ void QSGDistanceFieldGlyphNode::updateGeometry() float ty2 = ty1 + c.height; if (m_baseLine.isNull()) - m_baseLine = glyphInfo.position; + m_baseLine = position; int o = vp.size(); @@ -285,7 +286,7 @@ void QSGDistanceFieldGlyphNode::updateGeometry() ip.append(o + 0); } - QHash<const QSGDistanceFieldGlyphCache::Texture *, QList<GlyphInfo> >::const_iterator ite = glyphsInOtherTextures.constBegin(); + QHash<const QSGDistanceFieldGlyphCache::Texture *, GlyphInfo>::const_iterator ite = glyphsInOtherTextures.constBegin(); while (ite != glyphsInOtherTextures.constEnd()) { QHash<const QSGDistanceFieldGlyphCache::Texture *, QSGDistanceFieldGlyphNode *>::iterator subIt = m_subNodes.find(ite.key()); if (subIt == m_subNodes.end()) { @@ -299,17 +300,9 @@ void QSGDistanceFieldGlyphNode::updateGeometry() subIt = m_subNodes.insert(ite.key(), subNode); } - QVector<quint32> glyphIndexes; - QVector<QPointF> positions; - const QList<GlyphInfo> &subNodeGlyphs = ite.value(); - for (int i = 0; i < subNodeGlyphs.count(); ++i) { - const GlyphInfo &info = subNodeGlyphs.at(i); - glyphIndexes.append(info.glyphIndex); - positions.append(info.position); - } QGlyphRun subNodeGlyphRun(m_glyphs); - subNodeGlyphRun.setGlyphIndexes(glyphIndexes); - subNodeGlyphRun.setPositions(positions); + subNodeGlyphRun.setGlyphIndexes(ite->indexes); + subNodeGlyphRun.setPositions(ite->positions); subIt.value()->setGlyphs(m_originalPosition, subNodeGlyphRun); subIt.value()->update(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h index 65ac2d499c..9406ee1bc8 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h @@ -96,11 +96,10 @@ private: QList<QSGDistanceFieldGlyphNode *> m_nodesToDelete; struct GlyphInfo { - quint32 glyphIndex; - QPointF position; + QVector<quint32> indexes; + QVector<QPointF> positions; }; QSet<quint32> m_allGlyphIndexesLookup; - QList<GlyphInfo> m_allGlyphs; uint m_dirtyGeometry: 1; uint m_dirtyMaterial: 1; diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp index 76fb9036f4..cd5aaaedd7 100644 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp @@ -234,14 +234,25 @@ void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs void QSGSharedDistanceFieldGlyphCache::registerOwnerElement(QQuickItem *ownerElement) { - bool ok = connect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); - Q_ASSERT_X(ok, Q_FUNC_INFO, "QML element that owns a glyph node must have triggerPreprocess() slot"); - Q_UNUSED(ok); + Owner &owner = m_registeredOwners[ownerElement]; + if (owner.ref == 0) { + owner.item = ownerElement; + + bool ok = connect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); + Q_ASSERT_X(ok, Q_FUNC_INFO, "QML element that owns a glyph node must have triggerPreprocess() slot"); + Q_UNUSED(ok); + } + ++owner.ref; } void QSGSharedDistanceFieldGlyphCache::unregisterOwnerElement(QQuickItem *ownerElement) { - disconnect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); + QHash<QQuickItem *, Owner>::iterator it = m_registeredOwners.find(ownerElement); + if (it != m_registeredOwners.end() && --it->ref <= 0) { + if (it->item) + disconnect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); + m_registeredOwners.erase(it); + } } #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG_) diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h index 4a91b4473a..19844bbda4 100644 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h @@ -44,6 +44,7 @@ #include <QtCore/qwaitcondition.h> #include <private/qsgadaptationlayer_p.h> +#include <private/qqmlguard_p.h> QT_BEGIN_HEADER @@ -105,8 +106,19 @@ private: QPoint position; }; + struct Owner + { + Owner() : ref(0) {} + Owner(const Owner &o) : item(o.item), ref(o.ref) {} + Owner &operator =(const Owner &o) { item = o.item; ref = o.ref; return *this; } + + QQmlGuard<QQuickItem> item; + int ref; + }; + QHash<quint32, PendingGlyph> m_pendingReadyGlyphs; QHash<glyph_t, void *> m_bufferForGlyph; + QHash<QQuickItem *, Owner> m_registeredOwners; }; QT_END_NAMESPACE |