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