Krita Source Code Documentation
Loading...
Searching...
No Matches
KisFrameDataSerializer Class Reference

#include <KisFrameDataSerializer.h>

+ Inheritance diagram for KisFrameDataSerializer:

Classes

struct  Frame
 
struct  FrameTile
 

Public Member Functions

QString fileNameForFrame (int frameId)
 
QString filePathForFrame (int frameId)
 
void forgetFrame (int frameId)
 
int generateFrameId ()
 
quint8 * getCompressionBuffer (int size)
 
bool hasFrame (int frameId) const
 
 KisFrameDataSerializer ()
 
 KisFrameDataSerializer (const QString &frameCachePath)
 
Frame loadFrame (int frameId, KisTextureTileInfoPoolSP pool)
 
void moveFrame (int srcFrameId, int dstFrameId)
 
 Private (const QString &frameCachePath)
 
int saveFrame (const Frame &frame)
 
QString subfolderNameForFrame (int frameId)
 
 ~KisFrameDataSerializer ()
 
- Public Member Functions inherited from Private
 Private (KisCanvas2 *c)
 

Static Public Member Functions

static void addFrames (Frame &dst, const Frame &src)
 
static boost::optional< qreal > estimateFrameUniqueness (const Frame &lhs, const Frame &rhs, qreal portion)
 
static bool subtractFrames (Frame &dst, const Frame &src)
 

Public Attributes

QByteArray compressionBuffer
 
QTemporaryDir framesDir
 
QDir framesDirObject
 
int nextFrameId = 0
 
- Public Attributes inherited from Private
KisCanvas2canvas
 
int displayedFrame
 
int intendedFrame
 

Static Private Member Functions

template<template< typename U > class OpPolicy>
static bool processFrames (KisFrameDataSerializer::Frame &dst, const KisFrameDataSerializer::Frame &src)
 

Private Attributes

const QScopedPointer< Privatem_d
 

Detailed Description

KisFrameDataSerializer is the lowest level class for storing frame data on disk. Its responsibilities are simple:

1) Accept low-level frame data object (KisFrameDataSerializer::Frame), which contains raw data in it (the data may be not a pixel data, but a preprocessed pixel differences)

2) Compress this data and save it on disk

Definition at line 15 of file KisFrameDataSerializer.cpp.

Constructor & Destructor Documentation

◆ KisFrameDataSerializer() [1/2]

KisFrameDataSerializer::KisFrameDataSerializer ( )

Definition at line 64 of file KisFrameDataSerializer.cpp.

◆ KisFrameDataSerializer() [2/2]

KisFrameDataSerializer::KisFrameDataSerializer ( const QString & frameCachePath)

Definition at line 69 of file KisFrameDataSerializer.cpp.

70 : m_d(new Private(frameCachePath))
71{
72}
const QScopedPointer< Private > m_d

◆ ~KisFrameDataSerializer()

KisFrameDataSerializer::~KisFrameDataSerializer ( )

Definition at line 74 of file KisFrameDataSerializer.cpp.

75{
76}

Member Function Documentation

◆ addFrames()

void KisFrameDataSerializer::addFrames ( KisFrameDataSerializer::Frame & dst,
const Frame & src )
static

Definition at line 345 of file KisFrameDataSerializer.cpp.

346{
347 // TODO: don't spend time on calculation of "framesAreSame" in this case
348 (void) processFrames<std::plus>(dst, src);
349}
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)

References void().

◆ estimateFrameUniqueness()

boost::optional< qreal > KisFrameDataSerializer::estimateFrameUniqueness ( const Frame & lhs,
const Frame & rhs,
qreal portion )
static

Definition at line 247 of file KisFrameDataSerializer.cpp.

248{
249 if (lhs.pixelSize != rhs.pixelSize) return boost::none;
250 if (lhs.frameTiles.size() != rhs.frameTiles.size()) return boost::none;
251
252 const int pixelSize = lhs.pixelSize;
253 int numSampledPixels = 0;
254 int numUniquePixels = 0;
255 const int sampleStep = portion > 0.0 ? qMax(1, qRound(1.0 / portion)) : 0;
256
257 for (int i = 0; i < int(lhs.frameTiles.size()); i++) {
258 const FrameTile &lhsTile = lhs.frameTiles[i];
259 const FrameTile &rhsTile = rhs.frameTiles[i];
260
261 if (lhsTile.col != rhsTile.col ||
262 lhsTile.row != rhsTile.row ||
263 lhsTile.rect != rhsTile.rect) {
264
265 return boost::none;
266 }
267
268 if (sampleStep > 0) {
269 const int numPixels = lhsTile.rect.width() * lhsTile.rect.height();
270
271 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(lhsTile.data.data(), boost::none);
272 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(rhsTile.data.data(), boost::none);
273
274 for (int j = 0; j < numPixels; j += sampleStep) {
275 quint8 *lhsDataPtr = lhsTile.data.data() + j * pixelSize;
276 quint8 *rhsDataPtr = rhsTile.data.data() + j * pixelSize;
277
278 if (std::memcmp(lhsDataPtr, rhsDataPtr, pixelSize) != 0) {
279 numUniquePixels++;
280 }
281 numSampledPixels++;
282 }
283 }
284 }
285
286 return numSampledPixels > 0 ? qreal(numUniquePixels) / numSampledPixels : 1.0;
287}
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References KisFrameDataSerializer::FrameTile::col, KisFrameDataSerializer::FrameTile::data, DataBuffer::data(), KisFrameDataSerializer::Frame::frameTiles, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, KisFrameDataSerializer::Frame::pixelSize, KisFrameDataSerializer::FrameTile::rect, and KisFrameDataSerializer::FrameTile::row.

◆ fileNameForFrame()

QString KisFrameDataSerializer::fileNameForFrame ( int frameId)
inline

Definition at line 34 of file KisFrameDataSerializer.cpp.

34 {
35 return QString("frame_%1").arg(frameId);
36 }

◆ filePathForFrame()

QString KisFrameDataSerializer::filePathForFrame ( int frameId)
inline

Definition at line 38 of file KisFrameDataSerializer.cpp.

39 {
40 return framesDirObject.filePath(
41 subfolderNameForFrame(frameId) + '/' +
42 fileNameForFrame(frameId));
43 }
QString subfolderNameForFrame(int frameId)
QString fileNameForFrame(int frameId)

◆ forgetFrame()

void KisFrameDataSerializer::forgetFrame ( int frameId)

Definition at line 241 of file KisFrameDataSerializer.cpp.

242{
243 const QString framePath = m_d->filePathForFrame(frameId);
244 QFile::remove(framePath);
245}

References m_d.

◆ generateFrameId()

int KisFrameDataSerializer::generateFrameId ( )
inline

Definition at line 45 of file KisFrameDataSerializer.cpp.

45 {
46 // TODO: handle wrapping and range compression
47 return nextFrameId++;
48 }

◆ getCompressionBuffer()

quint8 * KisFrameDataSerializer::getCompressionBuffer ( int size)
inline

Definition at line 50 of file KisFrameDataSerializer.cpp.

50 {
51 if (compressionBuffer.size() < size) {
52 compressionBuffer.resize(size);
53 }
54 return reinterpret_cast<quint8*>(compressionBuffer.data());
55 }

◆ hasFrame()

bool KisFrameDataSerializer::hasFrame ( int frameId) const

Definition at line 235 of file KisFrameDataSerializer.cpp.

236{
237 const QString framePath = m_d->filePathForFrame(frameId);
238 return QFileInfo(framePath).exists();
239}

References m_d.

◆ loadFrame()

KisFrameDataSerializer::Frame KisFrameDataSerializer::loadFrame ( int frameId,
KisTextureTileInfoPoolSP pool )

Definition at line 141 of file KisFrameDataSerializer.cpp.

142{
143 KisLzfCompression compression;
144
145 QElapsedTimer loadingTime;
146 loadingTime.start();
147
148 int loadedFrameId = -1;
150
151 qint64 compressionTime = 0;
152
153 const QString framePath = m_d->filePathForFrame(frameId);
154
155 QFile file(framePath);
157 if (!file.open(QFile::ReadOnly)) return frame;
158
159 QDataStream stream(&file);
160
161 int numTiles = 0;
162
163 stream >> loadedFrameId;
164 stream >> frame.pixelSize;
165 stream >> numTiles;
167
168
169
170 for (int i = 0; i < numTiles; i++) {
171 FrameTile tile(pool);
172 stream >> tile.col;
173 stream >> tile.row;
174 stream >> tile.rect;
175
176 const int frameByteSize = frame.pixelSize * tile.rect.width() * tile.rect.height();
177 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(frameByteSize <= pool->chunkSize(frame.pixelSize),
179
180 bool isCompressed = false;
181 int inputSize = -1;
182
183 stream >> isCompressed;
184 stream >> inputSize;
185
186 if (isCompressed) {
187 const int maxBufferSize = compression.outputBufferSize(inputSize);
188 quint8 *buffer = m_d->getCompressionBuffer(maxBufferSize);
189 stream.readRawData((char*)buffer, inputSize);
190
191 tile.data.allocate(frame.pixelSize);
192
193 QElapsedTimer compTime;
194 compTime.start();
195
196 const int decompressedSize =
197 compression.decompress(buffer, inputSize, tile.data.data(), frameByteSize);
198
199 compressionTime += compTime.nsecsElapsed();
200
201 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(frameByteSize == decompressedSize,
203
204 } else {
205 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(frameByteSize == inputSize,
207
208 tile.data.allocate(frame.pixelSize);
209 stream.readRawData((char*)tile.data.data(), inputSize);
210 }
211
212 frame.frameTiles.push_back(std::move(tile));
213 }
214
215 Q_UNUSED(compressionTime);
216
217 file.close();
218
219 return frame;
220}
qint32 decompress(const quint8 *input, qint32 inputLength, quint8 *output, qint32 outputLength) override
qint32 outputBufferSize(qint32 dataSize) override
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
std::vector< FrameTile > frameTiles

References DataBuffer::allocate(), KisFrameDataSerializer::FrameTile::col, KisFrameDataSerializer::FrameTile::data, DataBuffer::data(), KisLzfCompression::decompress(), KisFrameDataSerializer::Frame::frameTiles, KIS_SAFE_ASSERT_RECOVER_NOOP, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, KisLzfCompression::outputBufferSize(), KisFrameDataSerializer::Frame::pixelSize, KisFrameDataSerializer::FrameTile::rect, and KisFrameDataSerializer::FrameTile::row.

◆ moveFrame()

void KisFrameDataSerializer::moveFrame ( int srcFrameId,
int dstFrameId )

Definition at line 222 of file KisFrameDataSerializer.cpp.

223{
224 const QString srcFramePath = m_d->filePathForFrame(srcFrameId);
225 const QString dstFramePath = m_d->filePathForFrame(dstFrameId);
226 KIS_SAFE_ASSERT_RECOVER_RETURN(QFileInfo(srcFramePath).exists());
227
228 KIS_SAFE_ASSERT_RECOVER(!QFileInfo(dstFramePath).exists()) {
229 QFile::remove(dstFramePath);
230 }
231
232 QFile::rename(srcFramePath, dstFramePath);
233}
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_RETURN, and m_d.

◆ Private()

KisFrameDataSerializer::Private ( const QString & frameCachePath)
inline

Definition at line 17 of file KisFrameDataSerializer.cpp.

18 : framesDir(
19 (!frameCachePath.isEmpty() && QTemporaryDir(frameCachePath + "/KritaFrameCacheXXXXXX").isValid()
20 ? frameCachePath
21 : QDir::tempPath())
22 + "/KritaFrameCacheXXXXXX")
23 {
24 framesDirObject = QDir(framesDir.path());
25 framesDirObject.makeAbsolute();
26 }

◆ processFrames()

template<template< typename U > class OpPolicy>
bool KisFrameDataSerializer::processFrames ( KisFrameDataSerializer::Frame & dst,
const KisFrameDataSerializer::Frame & src )
staticprivate

Definition at line 311 of file KisFrameDataSerializer.cpp.

312{
313 bool framesAreSame = true;
314
316
317 for (int i = 0; i < int(src.frameTiles.size()); i++) {
318 const FrameTile &srcTile = src.frameTiles[i];
319 FrameTile &dstTile = dst.frameTiles[i];
320
321 const int numBytes = srcTile.rect.width() * srcTile.rect.height() * src.pixelSize;
322 const int numQWords = numBytes / 8;
323
324 const quint64 *srcDataPtr = reinterpret_cast<const quint64*>(srcTile.data.data());
325 quint64 *dstDataPtr = reinterpret_cast<quint64*>(dstTile.data.data());
326
327 framesAreSame &= processData<OpPolicy>(dstDataPtr, srcDataPtr, numQWords);
328
329
330 const int tailBytes = numBytes % 8;
331 const quint8 *srcTailDataPtr = srcTile.data.data() + numBytes - tailBytes;
332 quint8 *dstTailDataPtr = dstTile.data.data() + numBytes - tailBytes;
333
334 framesAreSame &= processData<OpPolicy>(dstTailDataPtr, srcTailDataPtr, tailBytes);
335 }
336
337 return framesAreSame;
338}
static boost::optional< qreal > estimateFrameUniqueness(const Frame &lhs, const Frame &rhs, qreal portion)

References KisFrameDataSerializer::FrameTile::data, DataBuffer::data(), estimateFrameUniqueness(), KisFrameDataSerializer::Frame::frameTiles, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisFrameDataSerializer::FrameTile::rect.

◆ saveFrame()

int KisFrameDataSerializer::saveFrame ( const Frame & frame)

Definition at line 78 of file KisFrameDataSerializer.cpp.

79{
80 KisLzfCompression compression;
81
82 const int frameId = m_d->generateFrameId();
83
84 const QString frameSubfolder = m_d->subfolderNameForFrame(frameId);
85
86 if (!m_d->framesDirObject.exists(frameSubfolder)) {
87 m_d->framesDirObject.mkpath(frameSubfolder);
88 }
89
90 const QString frameRelativePath = frameSubfolder + '/' + m_d->fileNameForFrame(frameId);
91
92 if (m_d->framesDirObject.exists(frameRelativePath)) {
93 qWarning() << "WARNING: overwriting existing frame file!" << frameRelativePath;
94 forgetFrame(frameId);
95 }
96
97 const QString frameFilePath = m_d->framesDirObject.filePath(frameRelativePath);
98
99 QFile file(frameFilePath);
100 file.open(QFile::WriteOnly);
101
102 QDataStream stream(&file);
103 stream << frameId;
104 stream << frame.pixelSize;
105
106 stream << int(frame.frameTiles.size());
107
108 for (int i = 0; i < int(frame.frameTiles.size()); i++) {
109 const FrameTile &tile = frame.frameTiles[i];
110
111 stream << tile.col;
112 stream << tile.row;
113 stream << tile.rect;
114
115 const int frameByteSize = frame.pixelSize * tile.rect.width() * tile.rect.height();
116 const int maxBufferSize = compression.outputBufferSize(frameByteSize);
117 quint8 *buffer = m_d->getCompressionBuffer(maxBufferSize);
118
119 const int compressedSize =
120 compression.compress(tile.data.data(), frameByteSize, buffer, maxBufferSize);
121
122 //ENTER_FUNCTION() << ppVar(compressedSize) << ppVar(frameByteSize);
123
124 const bool isCompressed = compressedSize < frameByteSize;
125 stream << isCompressed;
126
127 if (isCompressed) {
128 stream << compressedSize;
129 stream.writeRawData((char*)buffer, compressedSize);
130 } else {
131 stream << frameByteSize;
132 stream.writeRawData((char*)tile.data.data(), frameByteSize);
133 }
134 }
135
136 file.close();
137
138 return frameId;
139}
qint32 compress(const quint8 *input, qint32 inputLength, quint8 *output, qint32 outputLength) override

References KisFrameDataSerializer::FrameTile::col, KisLzfCompression::compress(), KisFrameDataSerializer::FrameTile::data, DataBuffer::data(), forgetFrame(), KisFrameDataSerializer::Frame::frameTiles, m_d, KisLzfCompression::outputBufferSize(), KisFrameDataSerializer::Frame::pixelSize, KisFrameDataSerializer::FrameTile::rect, and KisFrameDataSerializer::FrameTile::row.

◆ subfolderNameForFrame()

QString KisFrameDataSerializer::subfolderNameForFrame ( int frameId)
inline

Definition at line 28 of file KisFrameDataSerializer.cpp.

29 {
30 const int subfolderIndex = frameId & 0xff00;
31 return QString::number(subfolderIndex);
32 }

◆ subtractFrames()

bool KisFrameDataSerializer::subtractFrames ( KisFrameDataSerializer::Frame & dst,
const Frame & src )
static

Definition at line 340 of file KisFrameDataSerializer.cpp.

341{
342 return processFrames<std::minus>(dst, src);
343}

Member Data Documentation

◆ compressionBuffer

QByteArray KisFrameDataSerializer::compressionBuffer

Definition at line 61 of file KisFrameDataSerializer.cpp.

◆ framesDir

QTemporaryDir KisFrameDataSerializer::framesDir

Definition at line 57 of file KisFrameDataSerializer.cpp.

◆ framesDirObject

QDir KisFrameDataSerializer::framesDirObject

Definition at line 58 of file KisFrameDataSerializer.cpp.

◆ m_d

const QScopedPointer<Private> KisFrameDataSerializer::m_d
private

Definition at line 122 of file KisFrameDataSerializer.h.

◆ nextFrameId

int KisFrameDataSerializer::nextFrameId = 0

Definition at line 59 of file KisFrameDataSerializer.cpp.


The documentation for this class was generated from the following files: