File indexing completed on 2024-06-16 04:12:34
0001 /* 0002 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com> 0003 * SPDX-FileCopyrightText: 2018 Andrey Kamakin <a.kamakin@icloud.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef KIS_TILE_DATA_INTERFACE_H_ 0009 #define KIS_TILE_DATA_INTERFACE_H_ 0010 0011 #include <QReadWriteLock> 0012 #include <QAtomicInt> 0013 0014 #include "kis_lockless_stack.h" 0015 #include "swap/kis_chunk_allocator.h" 0016 0017 class KisTileData; 0018 class KisTileDataStore; 0019 0020 /** 0021 * WARNING: Those definitions for internal use only! 0022 * Please use KisTileData::WIDTH/HEIGHT instead 0023 */ 0024 #define __TILE_DATA_WIDTH 64 0025 #define __TILE_DATA_HEIGHT 64 0026 0027 typedef KisLocklessStack<KisTileData*> KisTileDataCache; 0028 0029 typedef QLinkedList<KisTileData*> KisTileDataList; 0030 typedef KisTileDataList::iterator KisTileDataListIterator; 0031 typedef KisTileDataList::const_iterator KisTileDataListConstIterator; 0032 0033 0034 class SimpleCache 0035 { 0036 public: 0037 SimpleCache() = default; 0038 ~SimpleCache(); 0039 0040 bool push(int pixelSize, quint8 *&ptr) 0041 { 0042 QReadLocker l(&m_cacheLock); 0043 switch (pixelSize) { 0044 case 4: 0045 m_4Pool.push(ptr); 0046 break; 0047 case 8: 0048 m_8Pool.push(ptr); 0049 break; 0050 case 16: 0051 m_16Pool.push(ptr); 0052 break; 0053 default: 0054 return false; 0055 } 0056 0057 return true; 0058 } 0059 0060 bool pop(int pixelSize, quint8 *&ptr) 0061 { 0062 QReadLocker l(&m_cacheLock); 0063 switch (pixelSize) { 0064 case 4: 0065 return m_4Pool.pop(ptr); 0066 case 8: 0067 return m_8Pool.pop(ptr); 0068 case 16: 0069 return m_16Pool.pop(ptr); 0070 default: 0071 return false; 0072 } 0073 } 0074 0075 void clear(); 0076 0077 private: 0078 QReadWriteLock m_cacheLock; 0079 KisLocklessStack<quint8*> m_4Pool; 0080 KisLocklessStack<quint8*> m_8Pool; 0081 KisLocklessStack<quint8*> m_16Pool; 0082 }; 0083 0084 0085 /** 0086 * Stores actual tile's data 0087 */ 0088 class KRITAIMAGE_EXPORT KisTileData 0089 { 0090 public: 0091 KisTileData(qint32 pixelSize, const quint8 *defPixel, KisTileDataStore *store, bool checkFreeMemory = true); 0092 0093 private: 0094 KisTileData(const KisTileData& rhs, bool checkFreeMemory = true); 0095 0096 public: 0097 ~KisTileData(); 0098 0099 enum EnumTileDataState { 0100 NORMAL = 0, 0101 COMPRESSED, 0102 SWAPPED 0103 }; 0104 0105 /** 0106 * Information about data stored 0107 */ 0108 inline quint8* data() const; 0109 inline void setData(const quint8 *data); 0110 inline quint32 pixelSize() const; 0111 0112 /** 0113 * Increments usersCount of a TD and refs shared pointer counter 0114 * Used by KisTile for COW 0115 */ 0116 inline bool acquire(); 0117 0118 /** 0119 * Decrements usersCount of a TD and derefs shared pointer counter 0120 * Used by KisTile for COW 0121 */ 0122 inline bool release(); 0123 0124 /** 0125 * Only refs shared pointer counter. 0126 * Used only by KisMementoManager without 0127 * consideration of COW. 0128 */ 0129 inline bool ref() const; 0130 0131 /** 0132 * Only refs shared pointer counter. 0133 * Used only by KisMementoManager without 0134 * consideration of COW. 0135 */ 0136 inline bool deref(); 0137 0138 /** 0139 * Creates a clone of the tile data safely. 0140 * It will try to use the cached clones. 0141 */ 0142 inline KisTileData* clone(); 0143 0144 /** 0145 * Control the access of swapper to the tile data 0146 */ 0147 inline void blockSwapping(); 0148 inline void unblockSwapping(); 0149 0150 /** 0151 * The position of the tile data in a swap file 0152 */ 0153 inline KisChunk swapChunk() const; 0154 inline void setSwapChunk(KisChunk chunk); 0155 0156 /** 0157 * Show whether a tile data is a part of history 0158 */ 0159 inline bool mementoed() const; 0160 inline void setMementoed(bool value); 0161 0162 /** 0163 * Controlling methods for setting 'age' marks 0164 */ 0165 inline int age() const; 0166 inline void resetAge(); 0167 inline void markOld(); 0168 0169 /** 0170 * Returns number of tiles (or memento items), 0171 * referencing the tile data. 0172 */ 0173 inline qint32 numUsers() const; 0174 0175 /** 0176 * Convenience method. Returns true iff the tile data is linked to 0177 * information only and therefore can be swapped out easily. 0178 * 0179 * Effectively equivalent to: (mementoed() && numUsers() <= 1) 0180 */ 0181 inline bool historical() const; 0182 0183 /** 0184 * Used for swapping purposes only. 0185 * Frees the memory occupied by the tile data. 0186 * (the caller must save the data beforehand) 0187 */ 0188 void releaseMemory(); 0189 0190 /** 0191 * Used for swapping purposes only. 0192 * Allocates memory for the tile data after 0193 * it has been freed in releaseMemory(). 0194 * NOTE: the new data can be not-initialized 0195 * and you must fill it yourself! 0196 * 0197 * \see releaseMemory() 0198 */ 0199 void allocateMemory(); 0200 0201 /** 0202 * Releases internal pools, which keep blobs where the tiles are 0203 * stored. The point is that we don't allocate the tiles from 0204 * glibc directly, but use pools (implemented via boost) to 0205 * allocate bigger chunks. This method should be called when one 0206 * knows that we have just free'd quite a lot of memory and we 0207 * won't need it anymore. E.g. when a document has been closed. 0208 */ 0209 static void releaseInternalPools(); 0210 0211 private: 0212 void fillWithPixel(const quint8 *defPixel); 0213 0214 static quint8* allocateData(const qint32 pixelSize); 0215 static void freeData(quint8 *ptr, const qint32 pixelSize); 0216 private: 0217 friend class KisTileDataPooler; 0218 friend class KisTileDataPoolerTest; 0219 /** 0220 * A list of pre-duplicated tiledatas. 0221 * To make a COW faster, KisTileDataPooler thread duplicates 0222 * a tile beforehand and stores clones here, in this stack 0223 */ 0224 KisTileDataCache m_clonesStack; 0225 0226 private: 0227 friend class KisTile; 0228 friend class KisTileDataStore; 0229 0230 friend class KisTileDataStoreIterator; 0231 friend class KisTileDataStoreReverseIterator; 0232 friend class KisTileDataStoreClockIterator; 0233 0234 /** 0235 * The state of the tile. 0236 * Filled in by tileDataStore and 0237 * checked in KisTile::acquireFor* 0238 * see also: comment for @m_data 0239 */ 0240 mutable EnumTileDataState m_state; 0241 0242 /** 0243 * Iterator that points to a position in the list 0244 * where the tile data is stored 0245 */ 0246 int m_tileNumber = -1; 0247 0248 private: 0249 /** 0250 * The chunk of the swap file, that corresponds 0251 * to this tile data. Used by KisSwappedDataStore. 0252 */ 0253 KisChunk m_swapChunk; 0254 0255 0256 /** 0257 * The flag is set by KisMementoItem to show this 0258 * tile data is going down in history. 0259 * 0260 * (m_mementoFlag && m_usersCount == 1) means that 0261 * the only user of tile data is a memento manager. 0262 */ 0263 qint32 m_mementoFlag; 0264 0265 /** 0266 * Counts up time after last access to the tile data. 0267 * 0 - recently accessed 0268 * 1+ - not recently accessed 0269 */ 0270 //FIXME: make memory aligned 0271 int m_age; 0272 0273 0274 /** 0275 * The primitive for controlling swapping of the tile. 0276 * lockForRead() - used by regular threads to ensure swapper 0277 * won't touch this tile data. 0278 * tryLockForWrite() - used by swapper to check no-one reads 0279 * this tile data 0280 */ 0281 QReadWriteLock m_swapLock; 0282 0283 private: 0284 friend class KisLowMemoryTests; 0285 0286 /** 0287 * FIXME: We should be able to work in const environment 0288 * even when actual data is swapped out to disk 0289 */ 0290 mutable quint8* m_data; 0291 0292 /** 0293 * How many tiles/mementoes use 0294 * this tiledata through COW? 0295 */ 0296 mutable QAtomicInt m_usersCount; 0297 0298 /** 0299 * Shared pointer counter 0300 */ 0301 mutable QAtomicInt m_refCount; 0302 0303 0304 qint32 m_pixelSize; 0305 //qint32 m_timeStamp; 0306 0307 KisTileDataStore *m_store; 0308 static SimpleCache m_cache; 0309 0310 public: 0311 static const qint32 WIDTH; 0312 static const qint32 HEIGHT; 0313 }; 0314 0315 #endif /* KIS_TILE_DATA_INTERFACE_H_ */