aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util/qquickpixmapcache.cpp
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2023-08-30 22:05:23 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2023-09-01 15:57:36 +0200
commit3df72c56e732341aa55fa8e4aff48dbaebc15018 (patch)
treedb71674bc5394c632d1659c7d2bc83d07e288605 /src/quick/util/qquickpixmapcache.cpp
parente1382f6ad7983a1adf082ba5852379a6bf154a83 (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.cpp109
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);
}