File indexing completed on 2024-05-12 15:59:31
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Cyrille Berger <cberger@cberger.net> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "KoColorConversionCache.h" 0008 0009 #include <QHash> 0010 #include <QList> 0011 #include <QMutex> 0012 #include <QThreadStorage> 0013 0014 #include <KoColorSpace.h> 0015 0016 struct KoColorConversionCacheKey { 0017 0018 KoColorConversionCacheKey(const KoColorSpace* _src, 0019 const KoColorSpace* _dst, 0020 KoColorConversionTransformation::Intent _renderingIntent, 0021 KoColorConversionTransformation::ConversionFlags _conversionFlags) 0022 : src(_src) 0023 , dst(_dst) 0024 , renderingIntent(_renderingIntent) 0025 , conversionFlags(_conversionFlags) 0026 { 0027 } 0028 0029 bool operator==(const KoColorConversionCacheKey& rhs) const { 0030 return (*src == *(rhs.src)) && (*dst == *(rhs.dst)) 0031 && (renderingIntent == rhs.renderingIntent) 0032 && (conversionFlags == rhs.conversionFlags); 0033 } 0034 0035 const KoColorSpace* src; 0036 const KoColorSpace* dst; 0037 KoColorConversionTransformation::Intent renderingIntent; 0038 KoColorConversionTransformation::ConversionFlags conversionFlags; 0039 }; 0040 0041 uint qHash(const KoColorConversionCacheKey& key) 0042 { 0043 return qHash(key.src) + qHash(key.dst) + qHash(key.renderingIntent) + qHash(key.conversionFlags); 0044 } 0045 0046 struct KoColorConversionCache::CachedTransformation { 0047 0048 CachedTransformation(KoColorConversionTransformation* _transfo) 0049 : transfo(_transfo), use(0) 0050 {} 0051 0052 ~CachedTransformation() { 0053 delete transfo; 0054 } 0055 0056 bool isNotInUse() { 0057 return !use; 0058 } 0059 0060 KoColorConversionTransformation* transfo; 0061 QAtomicInt use; 0062 }; 0063 0064 typedef QPair<KoColorConversionCacheKey, KoCachedColorConversionTransformation> FastPathCacheItem; 0065 0066 struct KoColorConversionCache::Private { 0067 QMultiHash< KoColorConversionCacheKey, CachedTransformation*> cache; 0068 QMutex cacheMutex; 0069 0070 QThreadStorage<FastPathCacheItem*> fastStorage; 0071 }; 0072 0073 0074 KoColorConversionCache::KoColorConversionCache() : d(new Private) 0075 { 0076 } 0077 0078 KoColorConversionCache::~KoColorConversionCache() 0079 { 0080 Q_FOREACH (CachedTransformation* transfo, d->cache) { 0081 delete transfo; 0082 } 0083 delete d; 0084 } 0085 0086 KoCachedColorConversionTransformation KoColorConversionCache::cachedConverter(const KoColorSpace* src, 0087 const KoColorSpace* dst, 0088 KoColorConversionTransformation::Intent _renderingIntent, 0089 KoColorConversionTransformation::ConversionFlags _conversionFlags) 0090 { 0091 KoColorConversionCacheKey key(src, dst, _renderingIntent, _conversionFlags); 0092 0093 FastPathCacheItem *cacheItem = 0094 d->fastStorage.localData(); 0095 0096 if (cacheItem) { 0097 if (cacheItem->first == key) { 0098 return cacheItem->second; 0099 } 0100 } 0101 0102 cacheItem = 0; 0103 0104 QMutexLocker lock(&d->cacheMutex); 0105 QList< CachedTransformation* > cachedTransfos = d->cache.values(key); 0106 if (cachedTransfos.size() != 0) { 0107 Q_FOREACH (CachedTransformation* ct, cachedTransfos) { 0108 ct->transfo->setSrcColorSpace(src); 0109 ct->transfo->setDstColorSpace(dst); 0110 0111 cacheItem = new FastPathCacheItem(key, KoCachedColorConversionTransformation(ct)); 0112 break; 0113 } 0114 } 0115 if (!cacheItem) { 0116 KoColorConversionTransformation* transfo = src->createColorConverter(dst, _renderingIntent, _conversionFlags); 0117 CachedTransformation* ct = new CachedTransformation(transfo); 0118 d->cache.insert(key, ct); 0119 cacheItem = new FastPathCacheItem(key, KoCachedColorConversionTransformation(ct)); 0120 } 0121 0122 d->fastStorage.setLocalData(cacheItem); 0123 return cacheItem->second; 0124 } 0125 0126 void KoColorConversionCache::colorSpaceIsDestroyed(const KoColorSpace* cs) 0127 { 0128 d->fastStorage.setLocalData(0); 0129 0130 QMutexLocker lock(&d->cacheMutex); 0131 QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator endIt = d->cache.end(); 0132 for (QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator it = d->cache.begin(); it != endIt;) { 0133 if (it.key().src == cs || it.key().dst == cs) { 0134 Q_ASSERT(it.value()->isNotInUse()); // That's terribely evil, if that assert fails, that means that someone is using a color transformation with a color space which is currently being deleted 0135 delete it.value(); 0136 it = d->cache.erase(it); 0137 } else { 0138 ++it; 0139 } 0140 } 0141 } 0142 0143 //--------- KoCachedColorConversionTransformation ----------// 0144 0145 KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(KoColorConversionCache::CachedTransformation* transfo) 0146 : m_transfo(transfo) 0147 { 0148 m_transfo = transfo; 0149 m_transfo->use.ref(); 0150 } 0151 0152 KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(const KoCachedColorConversionTransformation& rhs) 0153 : m_transfo(rhs.m_transfo) 0154 { 0155 m_transfo->use.ref(); 0156 } 0157 0158 KoCachedColorConversionTransformation::~KoCachedColorConversionTransformation() 0159 { 0160 Q_ASSERT(m_transfo->use > 0); 0161 m_transfo->use.deref(); 0162 } 0163 0164 const KoColorConversionTransformation* KoCachedColorConversionTransformation::transformation() const 0165 { 0166 return m_transfo->transfo; 0167 } 0168