File indexing completed on 2024-05-12 15:58:31
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 0013 0014 class KisPaintDeviceCache 0015 { 0016 public: 0017 KisPaintDeviceCache(KisPaintDevice *paintDevice) 0018 : m_paintDevice(paintDevice), 0019 m_exactBoundsCache(paintDevice), 0020 m_nonDefaultPixelAreaCache(paintDevice), 0021 m_regionCache(paintDevice), 0022 m_sequenceNumber(0) 0023 { 0024 } 0025 0026 KisPaintDeviceCache(const KisPaintDeviceCache &rhs) 0027 : m_paintDevice(rhs.m_paintDevice), 0028 m_exactBoundsCache(rhs.m_paintDevice), 0029 m_nonDefaultPixelAreaCache(rhs.m_paintDevice), 0030 m_regionCache(rhs.m_paintDevice), 0031 m_sequenceNumber(0) 0032 { 0033 } 0034 0035 void setupCache() { 0036 invalidate(); 0037 } 0038 0039 void invalidate() { 0040 m_thumbnailsValid = false; 0041 m_exactBoundsCache.invalidate(); 0042 m_nonDefaultPixelAreaCache.invalidate(); 0043 m_regionCache.invalidate(); 0044 m_sequenceNumber++; 0045 } 0046 0047 QRect exactBounds() { 0048 return m_exactBoundsCache.getValue(m_paintDevice->defaultBounds()->wrapAroundMode()); 0049 } 0050 0051 QRect exactBoundsAmortized() { 0052 QRect bounds; 0053 bool result = m_exactBoundsCache.tryGetValue(bounds, m_paintDevice->defaultBounds()->wrapAroundMode()); 0054 0055 if (!result) { 0056 /** 0057 * The calculation of the exact bounds might be too slow 0058 * in some special cases, e.g. for an empty canvas of 7k 0059 * by 6k. So we just always return extent, when the exact 0060 * bounds is not available. 0061 */ 0062 bounds = m_paintDevice->extent(); 0063 } 0064 0065 return bounds; 0066 } 0067 0068 QRect nonDefaultPixelArea() { 0069 return m_nonDefaultPixelAreaCache.getValue(m_paintDevice->defaultBounds()->wrapAroundMode()); 0070 } 0071 0072 KisRegion region() { 0073 return m_regionCache.getValue(m_paintDevice->defaultBounds()->wrapAroundMode()); 0074 } 0075 0076 QImage createThumbnail(qint32 w, qint32 h, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { 0077 QImage thumbnail; 0078 0079 if (h == 0 || w == 0) { 0080 return thumbnail; 0081 } 0082 0083 if (m_thumbnailsValid) { 0084 thumbnail = findThumbnail(w, h, oversample); 0085 } 0086 else { 0087 m_thumbnails.clear(); 0088 m_thumbnailsValid = true; 0089 } 0090 0091 if (thumbnail.isNull()) { 0092 thumbnail = m_paintDevice->createThumbnail(w, h, QRect(), oversample, renderingIntent, conversionFlags); 0093 cacheThumbnail(w, h, oversample, thumbnail); 0094 } 0095 0096 return thumbnail; 0097 } 0098 0099 int sequenceNumber() const { 0100 return m_sequenceNumber; 0101 } 0102 0103 private: 0104 inline QImage findThumbnail(qint32 w, qint32 h, qreal oversample) { 0105 QImage resultImage; 0106 if (m_thumbnails.contains(w) && m_thumbnails[w].contains(h) && m_thumbnails[w][h].contains(oversample)) { 0107 resultImage = m_thumbnails[w][h][oversample]; 0108 } 0109 return resultImage; 0110 } 0111 0112 inline void cacheThumbnail(qint32 w, qint32 h, qreal oversample, QImage image) { 0113 m_thumbnails[w][h][oversample] = image; 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 bool m_thumbnailsValid {false}; 0154 QMap<int, QMap<int, QMap<qreal,QImage> > > m_thumbnails; 0155 QAtomicInt m_sequenceNumber; 0156 }; 0157 0158 #endif /* __KIS_PAINT_DEVICE_CACHE_H */