File indexing completed on 2024-12-22 04:12:47
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef __KIS_TEXTURE_TILE_INFO_POOL_H 0008 #define __KIS_TEXTURE_TILE_INFO_POOL_H 0009 0010 #include <boost/pool/pool.hpp> 0011 #include <QtGlobal> 0012 #include <QVector> 0013 0014 #include <QMutex> 0015 #include <QMutexLocker> 0016 #include <QSharedPointer> 0017 #include <QApplication> 0018 0019 #include "kis_assert.h" 0020 #include "kis_debug.h" 0021 #include "kis_global.h" 0022 #include "kis_signal_compressor.h" 0023 0024 #include "kritaui_export.h" 0025 0026 const int minPoolChunk = 32; // 8 MiB (default, with tilesize 256) 0027 const int maxPoolChunk = 128; // 32 MiB (default, with tilesize 256) 0028 const int freeThreshold = 64; // 16 MiB (default, with tilesize 256) 0029 0030 0031 /** 0032 * A pool for keeping the chunks of data of constant size. We have one 0033 * such pool per used openGL tile size. The size of the chunk 0034 * obviously depends on the size of the tile in pixels and the size of 0035 * a single pixel in bytes. 0036 * 0037 * As soon as the number of allocations drops to zero, all the memory 0038 * is returned back to the operating system. Please note, that there 0039 * is *no way* of reclaiming even unused pool memory until *all* the 0040 * allocated chunks are free'd. 0041 */ 0042 class KRITAUI_EXPORT KisTextureTileInfoPoolSingleSize 0043 { 0044 public: 0045 KisTextureTileInfoPoolSingleSize(int tileWidth, int tileHeight, int pixelSize) 0046 : m_chunkSize(tileWidth * tileHeight * pixelSize), 0047 m_pool(m_chunkSize, minPoolChunk, maxPoolChunk), 0048 m_numAllocations(0), 0049 m_maxAllocations(0), 0050 m_numFrees(0) 0051 { 0052 } 0053 0054 quint8* malloc() { 0055 m_numAllocations++; 0056 m_maxAllocations = qMax(m_maxAllocations, m_numAllocations); 0057 0058 return (quint8*)m_pool.malloc(); 0059 } 0060 0061 bool free(quint8 *ptr) { 0062 m_numAllocations--; 0063 m_numFrees++; 0064 m_pool.free(ptr); 0065 0066 KIS_ASSERT_RECOVER_NOOP(m_numAllocations >= 0); 0067 0068 return !m_numAllocations && m_maxAllocations > freeThreshold; 0069 } 0070 0071 int chunkSize() const { 0072 return m_chunkSize; 0073 } 0074 0075 int numFrees() const { 0076 return m_numFrees; 0077 } 0078 0079 void tryPurge(int numFrees) { 0080 // checking numFrees here is asserting that there were no frees 0081 // between the time we originally indicated the purge and now. 0082 if (numFrees == m_numFrees && !m_numAllocations) { 0083 m_pool.purge_memory(); 0084 m_maxAllocations = 0; 0085 } 0086 } 0087 0088 private: 0089 const int m_chunkSize; 0090 boost::pool<boost::default_user_allocator_new_delete> m_pool; 0091 int m_numAllocations; 0092 int m_maxAllocations; 0093 int m_numFrees; 0094 }; 0095 0096 class KisTextureTileInfoPool; 0097 0098 class KRITAUI_EXPORT KisTextureTileInfoPoolWorker : public QObject 0099 { 0100 Q_OBJECT 0101 public: 0102 KisTextureTileInfoPoolWorker(KisTextureTileInfoPool *pool); 0103 0104 public Q_SLOTS: 0105 void slotPurge(int pixelSize, int numFrees); 0106 void slotDelayedPurge(); 0107 0108 private: 0109 KisTextureTileInfoPool *m_pool; 0110 KisSignalCompressor m_compressor; 0111 QMap<int, int> m_purge; 0112 }; 0113 0114 /** 0115 * A universal pool for keeping the openGL tile of different pixel 0116 * sizes. The underlying pools are created for each pixel size on 0117 * demand. 0118 */ 0119 class KRITAUI_EXPORT KisTextureTileInfoPool : public QObject 0120 { 0121 Q_OBJECT 0122 public: 0123 KisTextureTileInfoPool(int tileWidth, int tileHeight) 0124 : m_tileWidth(tileWidth), 0125 m_tileHeight(tileHeight) 0126 { 0127 m_worker = new KisTextureTileInfoPoolWorker(this); 0128 m_worker->moveToThread(QApplication::instance()->thread()); 0129 connect(this, SIGNAL(purge(int, int)), m_worker, SLOT(slotPurge(int, int))); 0130 } 0131 0132 ~KisTextureTileInfoPool() { 0133 delete m_worker; 0134 qDeleteAll(m_pools); 0135 } 0136 0137 /** 0138 * Alloc a tile with the specified pixel size 0139 */ 0140 quint8* malloc(int pixelSize) { 0141 QMutexLocker l(&m_mutex); 0142 0143 if (m_pools.size() <= pixelSize) { 0144 m_pools.resize(pixelSize + 1); 0145 } 0146 0147 if (!m_pools[pixelSize]) { 0148 m_pools[pixelSize] = 0149 new KisTextureTileInfoPoolSingleSize(m_tileWidth, m_tileHeight, pixelSize); 0150 } 0151 0152 return m_pools[pixelSize]->malloc(); 0153 } 0154 0155 /** 0156 * Free a tile with the specified pixel size 0157 */ 0158 void free(quint8 *ptr, int pixelSize) { 0159 QMutexLocker l(&m_mutex); 0160 KisTextureTileInfoPoolSingleSize *pool = m_pools[pixelSize]; 0161 if (pool->free(ptr)) { 0162 emit purge(pixelSize, pool->numFrees()); 0163 } 0164 } 0165 0166 /** 0167 * \return the length of the chunks stored in the pool 0168 */ 0169 int chunkSize(int pixelSize) const { 0170 QMutexLocker l(&m_mutex); 0171 return m_pools[pixelSize]->chunkSize(); 0172 } 0173 0174 void tryPurge(int pixelSize, int numFrees) { 0175 QMutexLocker l(&m_mutex); 0176 m_pools[pixelSize]->tryPurge(numFrees); 0177 } 0178 0179 Q_SIGNALS: 0180 void purge(int pixelSize, int numFrees); 0181 0182 private: 0183 mutable QMutex m_mutex; 0184 const int m_tileWidth; 0185 const int m_tileHeight; 0186 QVector<KisTextureTileInfoPoolSingleSize*> m_pools; 0187 KisTextureTileInfoPoolWorker *m_worker; 0188 }; 0189 0190 typedef QSharedPointer<KisTextureTileInfoPool> KisTextureTileInfoPoolSP; 0191 0192 class KRITAUI_EXPORT KisTextureTileInfoPoolRegistry 0193 { 0194 typedef QWeakPointer<KisTextureTileInfoPool> KisTextureTileInfoPoolWSP; 0195 typedef QPair<int, int> PoolId; 0196 0197 public: 0198 KisTextureTileInfoPoolSP getPool(int tileWidth, int tileHeight) { 0199 QMutexLocker l(&m_mutex); 0200 0201 PoolId id(tileWidth, tileHeight); 0202 0203 KisTextureTileInfoPoolSP pool = 0204 m_storage[id].toStrongRef(); 0205 0206 if (!pool) { 0207 pool = toQShared( 0208 new KisTextureTileInfoPool(tileWidth, tileHeight)); 0209 m_storage[id] = pool; 0210 } 0211 0212 return pool; 0213 } 0214 0215 private: 0216 QMutex m_mutex; 0217 QHash<PoolId, KisTextureTileInfoPoolWSP> m_storage; 0218 }; 0219 0220 0221 #endif /* __KIS_TEXTURE_TILE_INFO_POOL_H */