Krita Source Code Documentation
Loading...
Searching...
No Matches
KisFrameCacheStore.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2018 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
7
8#include <KoColorSpace.h>
9#include "kis_update_info.h"
12
13#define SANITY_CHECK
14
15namespace {
16enum FrameType {
17 FrameFull,
18 FrameCopy,
19 FrameDiff
20};
21
22struct FrameInfo;
23typedef QSharedPointer<FrameInfo> FrameInfoSP;
24
25struct FrameInfo {
26 // full frame
27 FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, const KisFrameDataSerializer::Frame &frame);
28 // diff frame
29 FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame, const KisFrameDataSerializer::Frame &frame);
30 // copy frame
31 FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame);
32
33 ~FrameInfo();
34
35 FrameType type() const {
36 return m_type;
37 }
38
39 int levelOfDetail() const {
40 return m_levelOfDetail;
41 }
42
43 QRect dirtyImageRect() const {
44 return m_dirtyImageRect;
45 }
46
47 QRect imageBounds() const {
48 return m_imageBounds;
49 }
50
51 int frameDataId() const {
52 return m_savedFrameDataId;
53 }
54
55 FrameInfoSP baseFrame() const {
56 return m_baseFrame;
57 }
58
59 int m_levelOfDetail = 0;
60 QRect m_dirtyImageRect;
61 QRect m_imageBounds;
62 FrameInfoSP m_baseFrame;
63 FrameType m_type = FrameFull;
64 int m_savedFrameDataId = -1;
65 KisFrameDataSerializer &m_serializer;
66};
67
68// full frame
69FrameInfo::FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, const KisFrameDataSerializer::Frame &frame)
70 : m_levelOfDetail(levelOfDetail),
71 m_dirtyImageRect(dirtyImageRect),
72 m_imageBounds(imageBounds),
73 m_baseFrame(0),
74 m_type(FrameFull),
75 m_serializer(serializer)
76{
77 m_savedFrameDataId = m_serializer.saveFrame(frame);
78}
79
80// diff frame
81FrameInfo::FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame, const KisFrameDataSerializer::Frame &frame)
82 : m_levelOfDetail(levelOfDetail),
83 m_dirtyImageRect(dirtyImageRect),
84 m_imageBounds(imageBounds),
85 m_baseFrame(baseFrame),
86 m_type(FrameDiff),
87 m_serializer(serializer)
88{
89 m_savedFrameDataId = m_serializer.saveFrame(frame);
90}
91
92// copy frame
93FrameInfo::FrameInfo(const QRect &dirtyImageRect, const QRect &imageBounds, int levelOfDetail, KisFrameDataSerializer &serializer, FrameInfoSP baseFrame)
94 : m_levelOfDetail(levelOfDetail),
95 m_dirtyImageRect(dirtyImageRect),
96 m_imageBounds(imageBounds),
97 m_baseFrame(baseFrame),
98 m_type(FrameCopy),
99 m_savedFrameDataId(-1),
100 m_serializer(serializer)
101{
102}
103
104FrameInfo::~FrameInfo()
105{
106 KIS_SAFE_ASSERT_RECOVER_RETURN(m_savedFrameDataId >= 0 || m_type == FrameCopy);
107
108 if (m_savedFrameDataId >= 0) {
109 m_serializer.forgetFrame(m_savedFrameDataId);
110 }
111}
112
113}
114
115
116struct KRITAUI_NO_EXPORT KisFrameCacheStore::Private
117{
118 Private(const QString &frameCachePath)
119 : serializer(frameCachePath)
120 {
121 }
122
123 // the serializer should be killed after *all* the frame info objects
124 // got destroyed, because they use it in their own destruction
126
128 int lastSavedFullFrameId = -1;
129
132
133 QMap<int, FrameInfoSP> savedFrames;
134};
135
140
141KisFrameCacheStore::KisFrameCacheStore(const QString &frameCachePath)
142 : m_d(new Private(frameCachePath))
143{
144}
145
146
150
151void KisFrameCacheStore::saveFrame(int frameId, KisOpenGLUpdateInfoSP info, const QRect &imageBounds)
152{
153 int pixelSize = 0;
154
155 Q_FOREACH (auto tile, info->tileList) {
156#ifdef SANITY_CHECK
157 if (!pixelSize) {
158 pixelSize = tile->pixelSize();
159 } else {
160 KIS_SAFE_ASSERT_RECOVER_RETURN(pixelSize == tile->pixelSize());
161 }
162#else
163 pixelSize = tile->pixelSize();
164 break;
165#endif
166 }
167
169
170 // TODO: assert that dirty image rect is equal to the full image rect
171 // TODO: assert tile color space coincides with the destination color space
172
174 frame.pixelSize = pixelSize;
175
176 for (auto it = info->tileList.begin(); it != info->tileList.end(); ++it) {
177 KisFrameDataSerializer::FrameTile tile(KisTextureTileInfoPoolSP(0)); // TODO: fix the pool should never be null!
178 tile.col = (*it)->tileCol();
179 tile.row = (*it)->tileRow();
180 tile.rect = (*it)->realPatchRect();
181 tile.data = std::move((*it)->takePixelData());
182
183 KIS_SAFE_ASSERT_RECOVER(tile.data.data()) { continue; }
184
185 frame.frameTiles.push_back(std::move(tile));
186 }
187
188 FrameInfoSP frameInfo;
189
190 if (m_d->lastSavedFullFrame.isValid()) {
191 boost::optional<qreal> uniqueness = KisFrameDataSerializer::estimateFrameUniqueness(m_d->lastSavedFullFrame, frame, 0.01);
192
193
194 if (uniqueness) {
195
204#if 0
205 if (*uniqueness == 0.0) {
206 FrameInfoSP baseFrameInfo = m_d->savedFrames[m_d->lastSavedFullFrameId];
207 frameInfo = toQShared(new FrameInfo(info->dirtyImageRect(),
208 imageBounds,
209 info->levelOfDetail(),
210 m_d->serializer,
211 baseFrameInfo));
212
213 } else
214#endif
215 if (*uniqueness < 0.5) {
216 FrameInfoSP baseFrameInfo = m_d->savedFrames[m_d->lastSavedFullFrameId];
217
218 KisFrameDataSerializer::subtractFrames(frame, m_d->lastSavedFullFrame);
219 frameInfo = toQShared(new FrameInfo(info->dirtyImageRect(),
220 imageBounds,
221 info->levelOfDetail(),
222 m_d->serializer,
223 baseFrameInfo,
224 frame));
225 }
226 }
227 }
228
229 if (!frameInfo) {
230 frameInfo = toQShared(new FrameInfo(info->dirtyImageRect(),
231 imageBounds,
232 info->levelOfDetail(),
233 m_d->serializer,
234 frame));
235 }
236
237 m_d->savedFrames.insert(frameId, frameInfo);
238
239 if (frameInfo->type() == FrameFull) {
240 m_d->lastSavedFullFrame = std::move(frame);
241 m_d->lastSavedFullFrameId = frameId;
242 }
243}
244
246{
248 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->savedFrames.contains(frameId), info);
249
250 FrameInfoSP frameInfo = m_d->savedFrames[frameId];
251
252 info->assignDirtyImageRect(frameInfo->dirtyImageRect());
253 info->assignLevelOfDetail(frameInfo->levelOfDetail());
254
256
257 switch (frameInfo->type()) {
258 case FrameFull:
259 frame = m_d->serializer.loadFrame(frameInfo->frameDataId(), builder.textureInfoPool());
260 m_d->lastLoadedBaseFrame = frame.clone();
261 m_d->lastLoadedBaseFrameInfo = frameInfo;
262 break;
263 case FrameCopy: {
264 FrameInfoSP baseFrameInfo = frameInfo->baseFrame();
266
267 if (baseFrameInfo == m_d->lastLoadedBaseFrameInfo) {
268 frame = m_d->lastLoadedBaseFrame.clone();
269 } else {
270 frame = m_d->serializer.loadFrame(baseFrameInfo->frameDataId(), builder.textureInfoPool());
271 m_d->lastLoadedBaseFrame = frame.clone();
272 m_d->lastLoadedBaseFrameInfo = baseFrameInfo;
273 }
274 break;
275 }
276 case FrameDiff: {
277 FrameInfoSP baseFrameInfo = frameInfo->baseFrame();
279
280 if (baseFrameInfo == m_d->lastLoadedBaseFrameInfo) {
281 // noop
282 } else {
283 m_d->lastLoadedBaseFrame = m_d->serializer.loadFrame(baseFrameInfo->frameDataId(), builder.textureInfoPool());
284 m_d->lastLoadedBaseFrameInfo = baseFrameInfo;
285
286 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->lastLoadedBaseFrame.isValid(), KisOpenGLUpdateInfoSP());
287 }
288
289 const KisFrameDataSerializer::Frame &baseFrame = m_d->lastLoadedBaseFrame;
291
292 frame = m_d->serializer.loadFrame(frameInfo->frameDataId(), builder.textureInfoPool());
293 KisFrameDataSerializer::addFrames(frame, baseFrame);
294 break;
295 }
296 }
297
298 for (auto it = frame.frameTiles.begin(); it != frame.frameTiles.end(); ++it) {
300
301 QRect patchRect = tile.rect;
302
303 if (frameInfo->levelOfDetail()) {
304 patchRect = KisLodTransform::upscaledRect(patchRect, frameInfo->levelOfDetail());
305 }
306
307 const QRect fullSizeTileRect =
308 builder.calculatePhysicalTileRect(tile.col, tile.row,
309 frameInfo->imageBounds(),
310 frameInfo->levelOfDetail());
311
313 new KisTextureTileUpdateInfo(tile.col, tile.row,
314 fullSizeTileRect, patchRect,
315 frameInfo->imageBounds(),
316 frameInfo->levelOfDetail(),
317 builder.textureInfoPool()));
318
319 tileInfo->putPixelData(std::move(tile.data), builder.destinationColorSpace());
320
321 info->tileList << tileInfo;
322 }
323
324 return info;
325}
326
327void KisFrameCacheStore::moveFrame(int srcFrameId, int dstFrameId)
328{
329 KIS_SAFE_ASSERT_RECOVER_RETURN(srcFrameId != dstFrameId);
330
331 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->savedFrames.contains(srcFrameId));
332
333 KIS_SAFE_ASSERT_RECOVER(!m_d->savedFrames.contains(dstFrameId)) {
334 m_d->savedFrames.remove(dstFrameId);
335 }
336
337 m_d->savedFrames.insert(dstFrameId, m_d->savedFrames[srcFrameId]);
338 m_d->savedFrames.remove(srcFrameId);
339
340 if (m_d->lastSavedFullFrameId == srcFrameId) {
341 m_d->lastSavedFullFrameId = dstFrameId;
342 }
343}
344
346{
347 KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->savedFrames.contains(frameId));
348
349 if (m_d->lastSavedFullFrameId == frameId) {
350 m_d->lastSavedFullFrame = KisFrameDataSerializer::Frame();
351 m_d->lastSavedFullFrameId = -1;
352 }
353
354 m_d->savedFrames.remove(frameId);
355}
356
357bool KisFrameCacheStore::hasFrame(int frameId) const
358{
359 return m_d->savedFrames.contains(frameId);
360}
361
363{
364 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->savedFrames.contains(frameId), 0);
365 return m_d->savedFrames[frameId]->levelOfDetail();
366}
367
369{
370 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->savedFrames.contains(frameId), QRect());
371 return m_d->savedFrames[frameId]->dirtyImageRect();
372}
KisSharedPtr< KisOpenGLUpdateInfo > KisOpenGLUpdateInfoSP
static QRect upscaledRect(const QRect &srcRect, int lod)
KisTextureTileUpdateInfoSPList tileList
void assignLevelOfDetail(int lod)
QRect dirtyImageRect() const override
void assignDirtyImageRect(const QRect &rect)
int levelOfDetail() const override
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
QSharedPointer< KisTextureTileInfoPool > KisTextureTileInfoPoolSP
QSharedPointer< T > toQShared(T *ptr)
KisFrameDataSerializer::Frame lastLoadedBaseFrame
QMap< int, FrameInfoSP > savedFrames
bool hasFrame(int frameId) const
KisFrameDataSerializer serializer
int frameLevelOfDetail(int frameId) const
const QScopedPointer< Private > m_d
KisFrameDataSerializer::Frame lastSavedFullFrame
void saveFrame(int frameId, KisOpenGLUpdateInfoSP info, const QRect &imageBounds)
void moveFrame(int srcFrameId, int dstFrameId)
KisOpenGLUpdateInfoSP loadFrame(int frameId, const KisOpenGLUpdateInfoBuilder &builder)
QRect frameDirtyRect(int frameId) const
Private(const QString &frameCachePath)
FrameInfoSP lastLoadedBaseFrameInfo
void forgetFrame(int frameId)
std::vector< FrameTile > frameTiles
static boost::optional< qreal > estimateFrameUniqueness(const Frame &lhs, const Frame &rhs, qreal portion)
static void addFrames(Frame &dst, const Frame &src)
static bool subtractFrames(Frame &dst, const Frame &src)
const KoColorSpace * destinationColorSpace() const
KisTextureTileInfoPoolSP textureInfoPool() const
QRect calculatePhysicalTileRect(int col, int row, const QRect &imageBounds, int levelOfDetail) const