diff options
| author | Shawn Rutledge <shawn.rutledge@qt.io> | 2023-08-30 22:05:23 +0200 |
|---|---|---|
| committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2023-09-01 15:57:36 +0200 |
| commit | 3df72c56e732341aa55fa8e4aff48dbaebc15018 (patch) | |
| tree | db71674bc5394c632d1659c7d2bc83d07e288605 /src/quick/util/qquickpixmapcache.cpp | |
| parent | e1382f6ad7983a1adf082ba5852379a6bf154a83 (diff) | |
Export QQuickPixmapKey and (renamed) QQuickPixmapCache for autotests
We need to be able to do a leak check in tst_qquickpixmapcache.
So we also need to use the singleton pattern rather than
Q_GLOBAL_STATIC. Since it gets more exposed this way, make
the badly-encapsulated parts of API available only to friends.
It's always been bothersome that various other places in the code are
including qquickpixmapcache_p.h to get QQuickPixmap, and
qquickpixmapcache_p.h also does not include any class called
QQuickPixmapCache as you'd expect; while arguably, QQuickPixmapStore is
the cache. Often in comments I've needed to refer to "the code in
qquickpixmapcache.cpp" because it's a very private, inbred family of
related classes that don't match the header name. So now we split the
headers: qquickpixmapcache_p.h is for the cache, which is now called
QQuickPixmapCache; and qquickpixmap_p.h is the header most often needed
in other places. Most classes in qquickpixmap_p.h are exported, but
QQuickPixmapCache itself is not (except for autotests). It cannot be
defined in the header that gets included in Particles for example: then
it wouldn't link, because the implementation is not (and shouldn't be)
exported, and that's not what Particles needs anyway.
Task-number: QTBUG-81266
Task-number: QTBUG-114953
Change-Id: Ifd7f253b8bbaa130eb52d5546f342754f99f47bb
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/quick/util/qquickpixmapcache.cpp')
| -rw-r--r-- | src/quick/util/qquickpixmapcache.cpp | 109 |
1 files changed, 34 insertions, 75 deletions
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 7f37643920..a17a9aebc3 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -40,10 +40,10 @@ #define IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT 8 -// After QQuickPixmapStore::unreferencePixmap() it may get deleted via a timer in 30 seconds +// After QQuickPixmapCache::unreferencePixmap() it may get deleted via a timer in 30 seconds #define CACHE_EXPIRE_TIME 30 -// How many (1/4) of the unreferenced pixmaps to delete in QQuickPixmapStore::timerEvent() +// How many (1/4) of the unreferenced pixmaps to delete in QQuickPixmapCache::timerEvent() #define CACHE_REMOVAL_FRACTION 4 #define PIXMAP_PROFILE(Code) Q_QUICK_PROFILE(QQuickProfiler::ProfilePixmapCache, Code) @@ -100,7 +100,7 @@ Q_LOGGING_CATEGORY(lcImg, "qt.quick.image") /*! \internal The maximum currently-unused image data that can be stored for potential - later reuse, in bytes. See QQuickPixmapStore::shrinkCache() + later reuse, in bytes. See QQuickPixmapCache::shrinkCache() */ static int cache_limit = 2048 * 1024; @@ -293,7 +293,7 @@ public: # define PIXMAP_READER_LOCK() #endif -class QQuickPixmapStore; +class QQuickPixmapCache; /*! \internal The private storage for QQuickPixmap. @@ -370,9 +370,9 @@ public: int cost() const; void addref(); - void release(QQuickPixmapStore *store = nullptr); + void release(QQuickPixmapCache *store = nullptr); void addToCache(); - void removeFromCache(QQuickPixmapStore *store = nullptr); + void removeFromCache(QQuickPixmapCache *store = nullptr); uint refCount; int frameCount; @@ -401,7 +401,7 @@ public: QQuickPixmapReply *reply; // prev/next pointers to form a linked list for dereferencing pixmaps that are currently unused - // (those get lazily deleted in QQuickPixmapStore::shrinkCache()) + // (those get lazily deleted in QQuickPixmapCache::shrinkCache()) QQuickPixmapData *prevUnreferenced; QQuickPixmapData**prevUnreferencedPtr; QQuickPixmapData *nextUnreferenced; @@ -1178,15 +1178,6 @@ void QQuickPixmapReader::run() #endif } -struct QQuickPixmapKey -{ - const QUrl *url; - const QRect *region; - const QSize *size; - int frame; - QQuickImageProviderOptions options; -}; - inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs) { return *lhs.url == *rhs.url && @@ -1225,45 +1216,13 @@ inline QDebug operator<<(QDebug debug, const QQuickPixmapKey &key) } #endif -class QQuickPixmapStore : public QObject -{ - Q_OBJECT -public: - QQuickPixmapStore(); - ~QQuickPixmapStore(); - - void unreferencePixmap(QQuickPixmapData *); - void referencePixmap(QQuickPixmapData *); - - void purgeCache(); - -protected: - void timerEvent(QTimerEvent *) override; - -public: - QHash<QQuickPixmapKey, QQuickPixmapData *> m_cache; - QMutex m_cacheMutex; // avoid simultaneous iteration and modification - -private: - Q_DISABLE_COPY(QQuickPixmapStore) - void shrinkCache(int remove); - - QQuickPixmapData *m_unreferencedPixmaps; - QQuickPixmapData *m_lastUnreferencedPixmap; - - int m_unreferencedCost; - int m_timerId; - bool m_destroying; -}; -Q_GLOBAL_STATIC(QQuickPixmapStore, pixmapStore); - - -QQuickPixmapStore::QQuickPixmapStore() - : m_unreferencedPixmaps(nullptr), m_lastUnreferencedPixmap(nullptr), m_unreferencedCost(0), m_timerId(-1), m_destroying(false) +QQuickPixmapCache *QQuickPixmapCache::instance() { + static QQuickPixmapCache self; + return &self; } -QQuickPixmapStore::~QQuickPixmapStore() +QQuickPixmapCache::~QQuickPixmapCache() { m_destroying = true; @@ -1306,7 +1265,7 @@ QQuickPixmapStore::~QQuickPixmapStore() Declare that \a data is currently unused so that shrinkCache() can lazily delete it later. */ -void QQuickPixmapStore::unreferencePixmap(QQuickPixmapData *data) +void QQuickPixmapCache::unreferencePixmap(QQuickPixmapData *data) { Q_ASSERT(data->prevUnreferenced == nullptr); Q_ASSERT(data->prevUnreferencedPtr == nullptr); @@ -1340,7 +1299,7 @@ void QQuickPixmapStore::unreferencePixmap(QQuickPixmapData *data) Declare that \a data is being used (by a QQuickPixmap) so that shrinkCache() won't delete it. (This is not reference counting though.) */ -void QQuickPixmapStore::referencePixmap(QQuickPixmapData *data) +void QQuickPixmapCache::referencePixmap(QQuickPixmapData *data) { Q_ASSERT(data->prevUnreferencedPtr); @@ -1364,7 +1323,7 @@ void QQuickPixmapStore::referencePixmap(QQuickPixmapData *data) Delete the least-recently-released QQuickPixmapData instances until the remaining bytes are less than cache_limit. */ -void QQuickPixmapStore::shrinkCache(int remove) +void QQuickPixmapCache::shrinkCache(int remove) { qCDebug(lcImg) << "reduce unreferenced cost" << m_unreferencedCost << "to less than limit" << cache_limit; while ((remove > 0 || m_unreferencedCost > cache_limit) && m_lastUnreferencedPixmap) { @@ -1385,7 +1344,7 @@ void QQuickPixmapStore::shrinkCache(int remove) } } -void QQuickPixmapStore::timerEvent(QTimerEvent *) +void QQuickPixmapCache::timerEvent(QTimerEvent *) { int removalCost = m_unreferencedCost / CACHE_REMOVAL_FRACTION; @@ -1397,14 +1356,14 @@ void QQuickPixmapStore::timerEvent(QTimerEvent *) } } -void QQuickPixmapStore::purgeCache() +void QQuickPixmapCache::purgeCache() { shrinkCache(m_unreferencedCost); } void QQuickPixmap::purgeCache() { - pixmapStore()->purgeCache(); + QQuickPixmapCache::instance()->purgeCache(); } QQuickPixmapReply::QQuickPixmapReply(QQuickPixmapData *d) @@ -1470,10 +1429,10 @@ void QQuickPixmapData::addref() ++refCount; PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount)); if (prevUnreferencedPtr) - pixmapStore()->referencePixmap(this); + QQuickPixmapCache::instance()->referencePixmap(this); } -void QQuickPixmapData::release(QQuickPixmapStore *store) +void QQuickPixmapData::release(QQuickPixmapCache *store) { Q_ASSERT(refCount > 0); --refCount; @@ -1490,7 +1449,7 @@ void QQuickPixmapData::release(QQuickPixmapStore *store) QQuickPixmapReader::readerMutex.unlock(); } - store = store ? store : pixmapStore(); + store = store ? store : QQuickPixmapCache::instance(); if (pixmapStatus == QQuickPixmap::Ready #ifdef Q_OS_WEBOS && storeToCache @@ -1508,7 +1467,7 @@ void QQuickPixmapData::release(QQuickPixmapStore *store) } /*! \internal - Add this to the global static QQuickPixmapStore. + Add this to the QQuickPixmapCache singleton. \note The actual image will end up in QQuickPixmapData::textureFactory. At the time addToCache() is called, it's generally not yet loaded; so the @@ -1522,30 +1481,30 @@ void QQuickPixmapData::addToCache() { if (!inCache) { QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, providerOptions }; - QMutexLocker locker(&pixmapStore()->m_cacheMutex); + QMutexLocker locker(&QQuickPixmapCache::instance()->m_cacheMutex); if (lcImg().isDebugEnabled()) { - qCDebug(lcImg) << "adding" << key << "to total" << pixmapStore()->m_cache.size(); - for (auto it = pixmapStore()->m_cache.keyBegin(); it != pixmapStore()->m_cache.keyEnd(); ++it) { + qCDebug(lcImg) << "adding" << key << "to total" << QQuickPixmapCache::instance()->m_cache.size(); + for (auto it = QQuickPixmapCache::instance()->m_cache.keyBegin(); it != QQuickPixmapCache::instance()->m_cache.keyEnd(); ++it) { if (*(it->url) == url && it->frame == frame) qDebug(lcImg) << " similar pre-existing:" << *it; } } - pixmapStore()->m_cache.insert(key, this); + QQuickPixmapCache::instance()->m_cache.insert(key, this); inCache = true; PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>( - url, pixmapStore()->m_cache.size())); + url, QQuickPixmapCache::instance()->m_cache.size())); } } -void QQuickPixmapData::removeFromCache(QQuickPixmapStore *store) +void QQuickPixmapData::removeFromCache(QQuickPixmapCache *store) { if (inCache) { if (!store) - store = pixmapStore(); + store = QQuickPixmapCache::instance(); QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, providerOptions }; - QMutexLocker locker(&pixmapStore()->m_cacheMutex); + QMutexLocker locker(&QQuickPixmapCache::instance()->m_cacheMutex); store->m_cache.remove(key); - qCDebug(lcImg) << "removed" << key << implicitSize << "; total remaining" << pixmapStore()->m_cache.size(); + qCDebug(lcImg) << "removed" << key << implicitSize << "; total remaining" << QQuickPixmapCache::instance()->m_cache.size(); inCache = false; PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>( url, store->m_cache.size())); @@ -1880,9 +1839,9 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &reques } QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, providerOptions }; - QQuickPixmapStore *store = pixmapStore(); + QQuickPixmapCache *store = QQuickPixmapCache::instance(); - QMutexLocker locker(&pixmapStore()->m_cacheMutex); + QMutexLocker locker(&QQuickPixmapCache::instance()->m_cacheMutex); QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end(); #ifdef Q_OS_WEBOS @@ -1977,7 +1936,7 @@ void QQuickPixmap::loadImageFromDevice(QQmlEngine *engine, QIODevice *device, co { auto oldD = d; QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, providerOptions }; - QQuickPixmapStore *store = pixmapStore(); + QQuickPixmapCache *store = QQuickPixmapCache::instance(); QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end(); QMutexLocker locker(&store->m_cacheMutex); iter = store->m_cache.find(key); @@ -2036,7 +1995,7 @@ bool QQuickPixmap::isCached(const QUrl &url, const QRect &requestRegion, const Q const int frame, const QQuickImageProviderOptions &options) { QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, options }; - QQuickPixmapStore *store = pixmapStore(); + QQuickPixmapCache *store = QQuickPixmapCache::instance(); return store->m_cache.contains(key); } |
