File indexing completed on 2024-05-19 04:29:12
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "KisFrameCacheStore.h" 0007 0008 #include <KoColorSpace.h> 0009 #include "kis_update_info.h" 0010 #include "KisFrameDataSerializer.h" 0011 #include "opengl/KisOpenGLUpdateInfoBuilder.h" 0012 0013 #define SANITY_CHECK 0014 0015 namespace { 0016 enum FrameType { 0017 FrameFull, 0018 FrameCopy, 0019 FrameDiff 0020 }; 0021 0022 struct FrameInfo; 0023 typedef QSharedPointer<FrameInfo> FrameInfoSP; 0024 0025 struct FrameInfo { 0026 // full frame 0027 FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, const KisFrameDataSerializer::Frame &frame); 0028 // diff frame 0029 FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame, const KisFrameDataSerializer::Frame &frame); 0030 // copy frame 0031 FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame); 0032 0033 ~FrameInfo(); 0034 0035 FrameType type() const { 0036 return m_type; 0037 } 0038 0039 int levelOfDetail() const { 0040 return m_levelOfDetail; 0041 } 0042 0043 QRect dirtyImageRect() const { 0044 return m_dirtyImageRect; 0045 } 0046 0047 QRect imageBounds() const { 0048 return m_imageBounds; 0049 } 0050 0051 int frameDataId() const { 0052 return m_savedFrameDataId; 0053 } 0054 0055 FrameInfoSP baseFrame() const { 0056 return m_baseFrame; 0057 } 0058 0059 int m_levelOfDetail = 0; 0060 QRect m_dirtyImageRect; 0061 QRect m_imageBounds; 0062 FrameInfoSP m_baseFrame; 0063 FrameType m_type = FrameFull; 0064 int m_savedFrameDataId = -1; 0065 KisFrameDataSerializer &m_serializer; 0066 }; 0067 0068 // full frame 0069 FrameInfo::FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, const KisFrameDataSerializer::Frame &frame) 0070 : m_levelOfDetail(levelOfDetail), 0071 m_dirtyImageRect(dirtyImageRect), 0072 m_imageBounds(imageBounds), 0073 m_baseFrame(0), 0074 m_type(FrameFull), 0075 m_serializer(serializer) 0076 { 0077 m_savedFrameDataId = m_serializer.saveFrame(frame); 0078 } 0079 0080 // diff frame 0081 FrameInfo::FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame, const KisFrameDataSerializer::Frame &frame) 0082 : m_levelOfDetail(levelOfDetail), 0083 m_dirtyImageRect(dirtyImageRect), 0084 m_imageBounds(imageBounds), 0085 m_baseFrame(baseFrame), 0086 m_type(FrameDiff), 0087 m_serializer(serializer) 0088 { 0089 m_savedFrameDataId = m_serializer.saveFrame(frame); 0090 } 0091 0092 // copy frame 0093 FrameInfo::FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame) 0094 : m_levelOfDetail(levelOfDetail), 0095 m_dirtyImageRect(dirtyImageRect), 0096 m_imageBounds(imageBounds), 0097 m_baseFrame(baseFrame), 0098 m_type(FrameCopy), 0099 m_savedFrameDataId(-1), 0100 m_serializer(serializer) 0101 { 0102 } 0103 0104 FrameInfo::~FrameInfo() 0105 { 0106 KIS_SAFE_ASSERT_RECOVER_RETURN(m_savedFrameDataId >= 0 || m_type == FrameCopy); 0107 0108 if (m_savedFrameDataId >= 0) { 0109 m_serializer.forgetFrame(m_savedFrameDataId); 0110 } 0111 } 0112 0113 } 0114 0115 0116 struct KRITAUI_NO_EXPORT KisFrameCacheStore::Private 0117 { 0118 Private(const QString &frameCachePath) 0119 : serializer(frameCachePath) 0120 { 0121 } 0122 0123 // the serializer should be killed after *all* the frame info objects 0124 // got destroyed, because they use it in their own destruction 0125 KisFrameDataSerializer serializer; 0126 0127 KisFrameDataSerializer::Frame lastSavedFullFrame; 0128 int lastSavedFullFrameId = -1; 0129 0130 KisFrameDataSerializer::Frame lastLoadedBaseFrame; 0131 FrameInfoSP lastLoadedBaseFrameInfo; 0132 0133 QMap<int, FrameInfoSP> savedFrames; 0134 }; 0135 0136 KisFrameCacheStore::KisFrameCacheStore() 0137 : KisFrameCacheStore(QString()) 0138 { 0139 } 0140 0141 KisFrameCacheStore::KisFrameCacheStore(const QString &frameCachePath) 0142 : m_d(new Private(frameCachePath)) 0143 { 0144 } 0145 0146 0147 KisFrameCacheStore::~KisFrameCacheStore() 0148 { 0149 } 0150 0151 void KisFrameCacheStore::saveFrame(int frameId, KisOpenGLUpdateInfoSP info, const QRect &imageBounds) 0152 { 0153 int pixelSize = 0; 0154 0155 Q_FOREACH (auto tile, info->tileList) { 0156 #ifdef SANITY_CHECK 0157 if (!pixelSize) { 0158 pixelSize = tile->pixelSize(); 0159 } else { 0160 KIS_SAFE_ASSERT_RECOVER_RETURN(pixelSize == tile->pixelSize()); 0161 } 0162 #else 0163 pixelSize = tile->pixelSize(); 0164 break; 0165 #endif 0166 } 0167 0168 KIS_SAFE_ASSERT_RECOVER_RETURN(pixelSize); 0169 0170 // TODO: assert that dirty image rect is equal to the full image rect 0171 // TODO: assert tile color space coincides with the destination color space 0172 0173 KisFrameDataSerializer::Frame frame; 0174 frame.pixelSize = pixelSize; 0175 0176 for (auto it = info->tileList.begin(); it != info->tileList.end(); ++it) { 0177 KisFrameDataSerializer::FrameTile tile(KisTextureTileInfoPoolSP(0)); // TODO: fix the pool should never be null! 0178 tile.col = (*it)->tileCol(); 0179 tile.row = (*it)->tileRow(); 0180 tile.rect = (*it)->realPatchRect(); 0181 tile.data = std::move((*it)->takePixelData()); 0182 0183 KIS_SAFE_ASSERT_RECOVER(tile.data.data()) { continue; } 0184 0185 frame.frameTiles.push_back(std::move(tile)); 0186 } 0187 0188 FrameInfoSP frameInfo; 0189 0190 if (m_d->lastSavedFullFrame.isValid()) { 0191 boost::optional<qreal> uniqueness = KisFrameDataSerializer::estimateFrameUniqueness(m_d->lastSavedFullFrame, frame, 0.01); 0192 0193 0194 if (uniqueness) { 0195 0196 /** 0197 * The full-copying code is disabled intentionally: 0198 * 0199 * We should never remove user-visible data on basis of statistics. On smaller 0200 * images, like 32x32 pixels, there might be really subtle changes that 0201 * are important for the user. So we should use difference instead of dumb 0202 * copying. 0203 */ 0204 #if 0 0205 if (*uniqueness == 0.0) { 0206 FrameInfoSP baseFrameInfo = m_d->savedFrames[m_d->lastSavedFullFrameId]; 0207 frameInfo = toQShared(new FrameInfo(info->dirtyImageRect(), 0208 imageBounds, 0209 info->levelOfDetail(), 0210 m_d->serializer, 0211 baseFrameInfo)); 0212 0213 } else 0214 #endif 0215 if (*uniqueness < 0.5) { 0216 FrameInfoSP baseFrameInfo = m_d->savedFrames[m_d->lastSavedFullFrameId]; 0217 0218 KisFrameDataSerializer::subtractFrames(frame, m_d->lastSavedFullFrame); 0219 frameInfo = toQShared(new FrameInfo(info->dirtyImageRect(), 0220 imageBounds, 0221 info->levelOfDetail(), 0222 m_d->serializer, 0223 baseFrameInfo, 0224 frame)); 0225 } 0226 } 0227 } 0228 0229 if (!frameInfo) { 0230 frameInfo = toQShared(new FrameInfo(info->dirtyImageRect(), 0231 imageBounds, 0232 info->levelOfDetail(), 0233 m_d->serializer, 0234 frame)); 0235 } 0236 0237 m_d->savedFrames.insert(frameId, frameInfo); 0238 0239 if (frameInfo->type() == FrameFull) { 0240 m_d->lastSavedFullFrame = std::move(frame); 0241 m_d->lastSavedFullFrameId = frameId; 0242 } 0243 } 0244 0245 KisOpenGLUpdateInfoSP KisFrameCacheStore::loadFrame(int frameId, const KisOpenGLUpdateInfoBuilder &builder) 0246 { 0247 KisOpenGLUpdateInfoSP info = new KisOpenGLUpdateInfo(); 0248 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->savedFrames.contains(frameId), info); 0249 0250 FrameInfoSP frameInfo = m_d->savedFrames[frameId]; 0251 0252 info->assignDirtyImageRect(frameInfo->dirtyImageRect()); 0253 info->assignLevelOfDetail(frameInfo->levelOfDetail()); 0254 0255 KisFrameDataSerializer::Frame frame; 0256 0257 switch (frameInfo->type()) { 0258 case FrameFull: 0259 frame = m_d->serializer.loadFrame(frameInfo->frameDataId(), builder.textureInfoPool()); 0260 m_d->lastLoadedBaseFrame = frame.clone(); 0261 m_d->lastLoadedBaseFrameInfo = frameInfo; 0262 break; 0263 case FrameCopy: { 0264 FrameInfoSP baseFrameInfo = frameInfo->baseFrame(); 0265 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(baseFrameInfo, KisOpenGLUpdateInfoSP()); 0266 0267 if (baseFrameInfo == m_d->lastLoadedBaseFrameInfo) { 0268 frame = m_d->lastLoadedBaseFrame.clone(); 0269 } else { 0270 frame = m_d->serializer.loadFrame(baseFrameInfo->frameDataId(), builder.textureInfoPool()); 0271 m_d->lastLoadedBaseFrame = frame.clone(); 0272 m_d->lastLoadedBaseFrameInfo = baseFrameInfo; 0273 } 0274 break; 0275 } 0276 case FrameDiff: { 0277 FrameInfoSP baseFrameInfo = frameInfo->baseFrame(); 0278 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(baseFrameInfo, KisOpenGLUpdateInfoSP()); 0279 0280 if (baseFrameInfo == m_d->lastLoadedBaseFrameInfo) { 0281 // noop 0282 } else { 0283 m_d->lastLoadedBaseFrame = m_d->serializer.loadFrame(baseFrameInfo->frameDataId(), builder.textureInfoPool()); 0284 m_d->lastLoadedBaseFrameInfo = baseFrameInfo; 0285 0286 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->lastLoadedBaseFrame.isValid(), KisOpenGLUpdateInfoSP()); 0287 } 0288 0289 const KisFrameDataSerializer::Frame &baseFrame = m_d->lastLoadedBaseFrame; 0290 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(baseFrame.isValid(), KisOpenGLUpdateInfoSP()); 0291 0292 frame = m_d->serializer.loadFrame(frameInfo->frameDataId(), builder.textureInfoPool()); 0293 KisFrameDataSerializer::addFrames(frame, baseFrame); 0294 break; 0295 } 0296 } 0297 0298 for (auto it = frame.frameTiles.begin(); it != frame.frameTiles.end(); ++it) { 0299 KisFrameDataSerializer::FrameTile &tile = *it; 0300 0301 QRect patchRect = tile.rect; 0302 0303 if (frameInfo->levelOfDetail()) { 0304 patchRect = KisLodTransform::upscaledRect(patchRect, frameInfo->levelOfDetail()); 0305 } 0306 0307 const QRect fullSizeTileRect = 0308 builder.calculatePhysicalTileRect(tile.col, tile.row, 0309 frameInfo->imageBounds(), 0310 frameInfo->levelOfDetail()); 0311 0312 KisTextureTileUpdateInfoSP tileInfo( 0313 new KisTextureTileUpdateInfo(tile.col, tile.row, 0314 fullSizeTileRect, patchRect, 0315 frameInfo->imageBounds(), 0316 frameInfo->levelOfDetail(), 0317 builder.textureInfoPool())); 0318 0319 tileInfo->putPixelData(std::move(tile.data), builder.destinationColorSpace()); 0320 0321 info->tileList << tileInfo; 0322 } 0323 0324 return info; 0325 } 0326 0327 void KisFrameCacheStore::moveFrame(int srcFrameId, int dstFrameId) 0328 { 0329 KIS_SAFE_ASSERT_RECOVER_RETURN(srcFrameId != dstFrameId); 0330 0331 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->savedFrames.contains(srcFrameId)); 0332 0333 KIS_SAFE_ASSERT_RECOVER(!m_d->savedFrames.contains(dstFrameId)) { 0334 m_d->savedFrames.remove(dstFrameId); 0335 } 0336 0337 m_d->savedFrames.insert(dstFrameId, m_d->savedFrames[srcFrameId]); 0338 m_d->savedFrames.remove(srcFrameId); 0339 0340 if (m_d->lastSavedFullFrameId == srcFrameId) { 0341 m_d->lastSavedFullFrameId = dstFrameId; 0342 } 0343 } 0344 0345 void KisFrameCacheStore::forgetFrame(int frameId) 0346 { 0347 KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->savedFrames.contains(frameId)); 0348 0349 if (m_d->lastSavedFullFrameId == frameId) { 0350 m_d->lastSavedFullFrame = KisFrameDataSerializer::Frame(); 0351 m_d->lastSavedFullFrameId = -1; 0352 } 0353 0354 m_d->savedFrames.remove(frameId); 0355 } 0356 0357 bool KisFrameCacheStore::hasFrame(int frameId) const 0358 { 0359 return m_d->savedFrames.contains(frameId); 0360 } 0361 0362 int KisFrameCacheStore::frameLevelOfDetail(int frameId) const 0363 { 0364 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->savedFrames.contains(frameId), 0); 0365 return m_d->savedFrames[frameId]->levelOfDetail(); 0366 } 0367 0368 QRect KisFrameCacheStore::frameDirtyRect(int frameId) const 0369 { 0370 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->savedFrames.contains(frameId), QRect()); 0371 return m_d->savedFrames[frameId]->dirtyImageRect(); 0372 }