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_ */