From 4cd2f0bb2ff262bafb09eae23db919714858e4a2 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 14 Mar 2012 15:28:27 +1000 Subject: [PATCH] Fix memory leak with the shared distance field glyph cache. A new glyph node instance registers its owner element with its glyph cache which in the case of the shared distance field glyph cache connects a signal from the cache to a slot on the owner, changing the text creates a new node but destroying the old node didn't remove the connection causing them to accumulate over time. In the glyph node; unregister the owner element from the cache on destruction, and in the cache only connect an owner element the first time it is registered and keep a reference count so the items can be disconnected when registrations from all nodes have been cancelled. Change-Id: Ibf32a146e146dbbf4e0556d1bd756465bd8e45ba Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/scenegraph/qsgdistancefieldglyphnode.cpp | 1 + .../qsgshareddistancefieldglyphcache.cpp | 19 +++++++++++++++---- .../qsgshareddistancefieldglyphcache_p.h | 12 ++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 79e5c3b..e049e92 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -76,6 +76,7 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode() glyphIndexes.append(m_allGlyphs.at(i).glyphIndex); m_glyph_cache->release(glyphIndexes); m_glyph_cache->unregisterGlyphNode(this); + m_glyph_cache->unregisterOwnerElement(ownerElement()); } for (int i = 0; i < m_nodesToDelete.count(); ++i) diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp index 76fb903..cd5aaae 100644 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp @@ -234,14 +234,25 @@ void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet &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::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 4a91b44..19844bb 100644 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h @@ -44,6 +44,7 @@ #include #include +#include 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 item; + int ref; + }; + QHash m_pendingReadyGlyphs; QHash m_bufferForGlyph; + QHash m_registeredOwners; }; QT_END_NAMESPACE -- 1.7.2.5