File indexing completed on 2024-06-16 04:12:35
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_STORE_H_ 0009 #define KIS_TILE_DATA_STORE_H_ 0010 0011 #include "kritaimage_export.h" 0012 0013 #include <QReadWriteLock> 0014 #include "kis_tile_data_interface.h" 0015 0016 #include "kis_tile_data_pooler.h" 0017 #include "swap/kis_tile_data_swapper.h" 0018 #include "swap/kis_swapped_data_store.h" 0019 #include "3rdparty/lock_free_map/concurrent_map.h" 0020 0021 class KisTileDataStoreIterator; 0022 class KisTileDataStoreReverseIterator; 0023 class KisTileDataStoreClockIterator; 0024 0025 /** 0026 * Stores tileData objects. When needed compresses them and swaps. 0027 */ 0028 class KRITAIMAGE_EXPORT KisTileDataStore 0029 { 0030 public: 0031 KisTileDataStore(); 0032 ~KisTileDataStore(); 0033 static KisTileDataStore* instance(); 0034 0035 void debugPrintList(); 0036 0037 struct MemoryStatistics { 0038 qint64 totalMemorySize; 0039 qint64 realMemorySize; 0040 qint64 historicalMemorySize; 0041 0042 qint64 poolSize; 0043 0044 qint64 swapSize; 0045 }; 0046 0047 MemoryStatistics memoryStatistics(); 0048 void tryForceUpdateMemoryStatisticsWhileIdle(); 0049 0050 /** 0051 * Returns total number of tiles present: in memory 0052 * or in a swap file 0053 */ 0054 inline qint32 numTiles() const 0055 { 0056 return m_numTiles.loadAcquire() + m_swappedStore.numTiles(); 0057 } 0058 0059 /** 0060 * Returns the number of tiles present in memory only 0061 */ 0062 inline qint32 numTilesInMemory() const 0063 { 0064 return m_numTiles.loadAcquire(); 0065 } 0066 0067 inline void checkFreeMemory() 0068 { 0069 m_swapper.checkFreeMemory(); 0070 } 0071 0072 /** 0073 * \see m_memoryMetric 0074 */ 0075 inline qint64 memoryMetric() const 0076 { 0077 return m_memoryMetric.loadAcquire(); 0078 } 0079 0080 KisTileDataStoreIterator* beginIteration(); 0081 void endIteration(KisTileDataStoreIterator* iterator); 0082 0083 KisTileDataStoreReverseIterator* beginReverseIteration(); 0084 void endIteration(KisTileDataStoreReverseIterator* iterator); 0085 0086 KisTileDataStoreClockIterator* beginClockIteration(); 0087 void endIteration(KisTileDataStoreClockIterator* iterator); 0088 0089 inline KisTileData* createDefaultTileData(qint32 pixelSize, const quint8 *defPixel) 0090 { 0091 return allocTileData(pixelSize, defPixel); 0092 } 0093 0094 // Called by The Memento Manager after every commit 0095 inline void kickPooler() 0096 { 0097 m_pooler.kick(); 0098 0099 //FIXME: maybe, rename a function? 0100 m_swapper.kick(); 0101 } 0102 0103 /** 0104 * Try swap out the tile data. 0105 * It may fail in case the tile is being accessed 0106 * at the same moment of time. 0107 */ 0108 bool trySwapTileData(KisTileData *td); 0109 0110 0111 /** 0112 * WARN: The following three method are only for usage 0113 * in KisTileData. Do not call them directly! 0114 */ 0115 0116 KisTileData *duplicateTileData(KisTileData *rhs); 0117 0118 void freeTileData(KisTileData *td); 0119 0120 /** 0121 * Ensures that the tile data is totally present in memory 0122 * and it's swapping is blocked by holding td->m_swapLock 0123 * in a read mode. 0124 * PRECONDITIONS: td->m_swapLock is *unlocked* 0125 * m_listRWLock is *unlocked* 0126 * POSTCONDITIONS: td->m_data is in memory and 0127 * td->m_swapLock is locked 0128 * m_listRWLock is unlocked 0129 */ 0130 void ensureTileDataLoaded(KisTileData *td); 0131 0132 void registerTileData(KisTileData *td); 0133 void unregisterTileData(KisTileData *td); 0134 0135 private: 0136 KisTileData *allocTileData(qint32 pixelSize, const quint8 *defPixel); 0137 0138 inline void registerTileDataImp(KisTileData *td); 0139 inline void unregisterTileDataImp(KisTileData *td); 0140 void freeRegisteredTiles(); 0141 0142 friend class DeadlockyThread; 0143 friend class KisLowMemoryTests; 0144 void debugSwapAll(); 0145 void debugClear(); 0146 0147 friend class KisTiledDataManagerTest; 0148 void testingSuspendPooler(); 0149 void testingResumePooler(); 0150 0151 friend class KisLowMemoryBenchmark; 0152 void testingRereadConfig(); 0153 private: 0154 KisTileDataPooler m_pooler; 0155 KisTileDataSwapper m_swapper; 0156 0157 friend class KisTileDataStoreTest; 0158 friend class KisTileDataPoolerTest; 0159 KisSwappedDataStore m_swappedStore; 0160 0161 /** 0162 * This metric is used for computing the volume 0163 * of memory occupied by tile data objects. 0164 * metric = num_bytes / (KisTileData::WIDTH * KisTileData::HEIGHT) 0165 */ 0166 QAtomicInt m_numTiles; 0167 QAtomicInt m_memoryMetric; 0168 QAtomicInt m_counter; 0169 QAtomicInt m_clockIndex; 0170 ConcurrentMap<int, KisTileData*> m_tileDataMap; 0171 QReadWriteLock m_iteratorLock; 0172 }; 0173 0174 template<typename T> 0175 inline T MiB_TO_METRIC(T value) 0176 { 0177 unsigned long long __MiB = 1ULL << 20; 0178 return value * (__MiB / (KisTileData::WIDTH * KisTileData::HEIGHT)); 0179 } 0180 0181 #endif /* KIS_TILE_DATA_STORE_H_ */ 0182