File indexing completed on 2024-05-19 04:26:25
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef __KIS_PAINT_DEVICE_CACHE_H 0008 #define __KIS_PAINT_DEVICE_CACHE_H 0009 0010 #include "kis_lock_free_cache.h" 0011 #include <QElapsedTimer> 0012 #include <QReadWriteLock> 0013 #include <QReadLocker> 0014 #include <QWriteLocker> 0015 0016 class KisPaintDeviceCache 0017 { 0018 public: 0019 KisPaintDeviceCache(KisPaintDevice *paintDevice) 0020 : m_paintDevice(paintDevice), 0021 m_exactBoundsCache(paintDevice), 0022 m_nonDefaultPixelAreaCache(paintDevice), 0023 m_regionCache(paintDevice), 0024 m_sequenceNumber(0) 0025 { 0026 } 0027 0028 KisPaintDeviceCache(const KisPaintDeviceCache &rhs) 0029 : m_paintDevice(rhs.m_paintDevice), 0030 m_exactBoundsCache(rhs.m_paintDevice), 0031 m_nonDefaultPixelAreaCache(rhs.m_paintDevice), 0032 m_regionCache(rhs.m_paintDevice), 0033 m_sequenceNumber(0) 0034 { 0035 } 0036 0037 void setupCache() { 0038 invalidate(); 0039 } 0040 0041 void invalidate() { 0042 m_thumbnailsValid = false; 0043 m_exactBoundsCache.invalidate(); 0044 m_nonDefaultPixelAreaCache.invalidate(); 0045 m_regionCache.invalidate(); 0046 m_sequenceNumber++; 0047 } 0048 0049 QRect exactBounds() { 0050 return m_exactBoundsCache.getValue(m_paintDevice->defaultBounds()->wrapAroundMode()); 0051 } 0052 0053 QRect exactBoundsAmortized() { 0054 QRect bounds; 0055 bool result = m_exactBoundsCache.tryGetValue(bounds, m_paintDevice->defaultBounds()->wrapAroundMode()); 0056 0057 if (!result) { 0058 /** 0059 * The calculation of the exact bounds might be too slow 0060 * in some special cases, e.g. for an empty canvas of 7k 0061 * by 6k. So we just always return extent, when the exact 0062 * bounds is not available. 0063 */ 0064 bounds = m_paintDevice->extent(); 0065 } 0066 0067 return bounds; 0068 } 0069 0070 QRect nonDefaultPixelArea() { 0071 return m_nonDefaultPixelAreaCache.getValue(m_paintDevice->defaultBounds()->wrapAroundMode()); 0072 } 0073 0074 KisRegion region() { 0075 return m_regionCache.getValue(m_paintDevice->defaultBounds()->wrapAroundMode()); 0076 } 0077 0078 QImage createThumbnail(qint32 w, qint32 h, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { 0079 QImage thumbnail; 0080 0081 if (h == 0 || w == 0) { 0082 return thumbnail; 0083 } 0084 0085 { 0086 QReadLocker readLocker(&m_thumbnailsLock); 0087 if (m_thumbnailsValid) { 0088 if (m_thumbnails.contains(w) && m_thumbnails[w].contains(h) && m_thumbnails[w][h].contains(oversample)) { 0089 thumbnail = m_thumbnails[w][h][oversample]; 0090 } 0091 } 0092 else { 0093 readLocker.unlock(); 0094 QWriteLocker writeLocker(&m_thumbnailsLock); 0095 m_thumbnails.clear(); 0096 m_thumbnailsValid = true; 0097 } 0098 } 0099 0100 if (thumbnail.isNull()) { 0101 // the thumbnails in the cache are always generated from exact bounds 0102 thumbnail = m_paintDevice->createThumbnail(w, h, m_paintDevice->exactBounds(), oversample, renderingIntent, conversionFlags); 0103 0104 QWriteLocker writeLocker(&m_thumbnailsLock); 0105 m_thumbnails[w][h][oversample] = thumbnail; 0106 m_thumbnailsValid = true; 0107 } 0108 0109 return thumbnail; 0110 } 0111 0112 int sequenceNumber() const { 0113 return m_sequenceNumber; 0114 } 0115 0116 private: 0117 KisPaintDevice *m_paintDevice {nullptr}; 0118 0119 struct ExactBoundsCache : KisLockFreeCacheWithModeConsistency<QRect, bool> { 0120 ExactBoundsCache(KisPaintDevice *paintDevice) : m_paintDevice(paintDevice) {} 0121 0122 QRect calculateNewValue() const override { 0123 return m_paintDevice->calculateExactBounds(false); 0124 } 0125 private: 0126 KisPaintDevice *m_paintDevice; 0127 }; 0128 0129 struct NonDefaultPixelCache : KisLockFreeCacheWithModeConsistency<QRect, bool> { 0130 NonDefaultPixelCache(KisPaintDevice *paintDevice) : m_paintDevice(paintDevice) {} 0131 0132 QRect calculateNewValue() const override { 0133 return m_paintDevice->calculateExactBounds(true); 0134 } 0135 private: 0136 KisPaintDevice *m_paintDevice; 0137 }; 0138 0139 struct RegionCache : KisLockFreeCacheWithModeConsistency<KisRegion, bool> { 0140 RegionCache(KisPaintDevice *paintDevice) : m_paintDevice(paintDevice) {} 0141 0142 KisRegion calculateNewValue() const override { 0143 return m_paintDevice->dataManager()->region(); 0144 } 0145 private: 0146 KisPaintDevice *m_paintDevice; 0147 }; 0148 0149 ExactBoundsCache m_exactBoundsCache; 0150 NonDefaultPixelCache m_nonDefaultPixelAreaCache; 0151 RegionCache m_regionCache; 0152 0153 QReadWriteLock m_thumbnailsLock; 0154 bool m_thumbnailsValid {false}; 0155 QMap<int, QMap<int, QMap<qreal,QImage> > > m_thumbnails; 0156 0157 QAtomicInt m_sequenceNumber; 0158 }; 0159 0160 #endif /* __KIS_PAINT_DEVICE_CACHE_H */