Commit c4f03c7c authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement saving/loading of KisOpenGLUpdateInfo to harddrive

The task is done by KisFrameCacheStore, which will also compress
the data in the future.
parent d6fccbd2
......@@ -425,6 +425,7 @@ endif()
kis_animation_importer.cpp
KisSyncedAudioPlayback.cpp
KisFrameDataSerializer.cpp
KisFrameCacheStore.cpp
)
if(UNIX)
......
/*
* Copyright (c) 2018 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisFrameCacheStore.h"
#include <KoColorSpace.h>
#include "kis_update_info.h"
#include "KisFrameDataSerializer.h"
#include "opengl/KisOpenGLUpdateInfoBuilder.h"
#define SANITY_CHECK
namespace {
struct SerializedFrameInfo {
int levelOfDetail = 0;
QRect dirtyImageRect;
};
}
struct KRITAUI_NO_EXPORT KisFrameCacheStore::Private
{
Private(KisTextureTileInfoPoolSP pool, const QString &frameCachePath)
: serializer(pool, frameCachePath)
{
}
KisFrameDataSerializer serializer;
QMap<int, SerializedFrameInfo> savedFrames;
};
KisFrameCacheStore::KisFrameCacheStore(KisTextureTileInfoPoolSP pool)
: KisFrameCacheStore(pool, QString())
{
}
KisFrameCacheStore::KisFrameCacheStore(KisTextureTileInfoPoolSP pool, const QString &frameCachePath)
: m_d(new Private(pool, frameCachePath))
{
}
KisFrameCacheStore::~KisFrameCacheStore()
{
}
void KisFrameCacheStore::saveFrame(int frameId, KisOpenGLUpdateInfoSP info)
{
int pixelSize = 0;
Q_FOREACH (auto tile, info->tileList) {
#ifdef SANITY_CHECK
if (!pixelSize) {
pixelSize = tile->pixelSize();
} else {
KIS_SAFE_ASSERT_RECOVER_RETURN(pixelSize == tile->pixelSize());
}
#else
pixelSize = tile->pixelSize();
break;
#endif
}
KIS_SAFE_ASSERT_RECOVER_RETURN(pixelSize);
SerializedFrameInfo frameInfo;
frameInfo.levelOfDetail = info->levelOfDetail();
frameInfo.dirtyImageRect = info->dirtyImageRect();
// TODO: assert that dirty image rect is equal to the full image rect
// TODO: assert tile color space coicides with the destination color space
m_d->savedFrames.insert(frameId, frameInfo);
KisFrameDataSerializer::Frame frame;
frame.frameId = frameId;
frame.pixelSize = pixelSize;
for (auto it = info->tileList.begin(); it != info->tileList.end(); ++it) {
KisFrameDataSerializer::FrameTile tile(m_d->serializer.tileInfoPool());
tile.col = (*it)->tileCol();
tile.row = (*it)->tileRow();
tile.rect = (*it)->realPatchRect();
tile.data = std::move((*it)->takePixelData());
frame.frameTiles.push_back(std::move(tile));
}
m_d->serializer.saveFrame(frame);
}
KisOpenGLUpdateInfoSP KisFrameCacheStore::loadFrame(int frameId, const KisOpenGLUpdateInfoBuilder &builder)
{
KisOpenGLUpdateInfoSP info = new KisOpenGLUpdateInfo();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->savedFrames.contains(frameId), info);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->serializer.hasFrame(frameId), info);
const SerializedFrameInfo &savedFrameInfo = m_d->savedFrames[frameId];
info->assignDirtyImageRect(savedFrameInfo.dirtyImageRect);
info->assignLevelOfDetail(savedFrameInfo.levelOfDetail);
KisFrameDataSerializer::Frame frame = m_d->serializer.loadFrame(frameId);
for (auto it = frame.frameTiles.begin(); it != frame.frameTiles.end(); ++it) {
KisFrameDataSerializer::FrameTile &tile = *it;
QRect patchRect = tile.rect;
if (savedFrameInfo.levelOfDetail) {
patchRect = KisLodTransform::upscaledRect(patchRect, savedFrameInfo.levelOfDetail);
}
const QRect fullSizeTileRect =
builder.calculatePhysicalTileRect(tile.col, tile.row,
savedFrameInfo.dirtyImageRect,
savedFrameInfo.levelOfDetail);
KisTextureTileUpdateInfoSP tileInfo(
new KisTextureTileUpdateInfo(tile.col, tile.row,
fullSizeTileRect, patchRect,
savedFrameInfo.dirtyImageRect,
savedFrameInfo.levelOfDetail,
m_d->serializer.tileInfoPool()));
tileInfo->putPixelData(std::move(tile.data), builder.destinationColorSpace());
info->tileList << tileInfo;
}
return info;
}
void KisFrameCacheStore::forgetFrame(int frameId)
{
KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->savedFrames.contains(frameId));
KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->serializer.hasFrame(frameId));
m_d->savedFrames.remove(frameId);
m_d->serializer.forgetFrame(frameId);
}
bool KisFrameCacheStore::hasFrame(int frameId) const
{
return m_d->savedFrames.contains(frameId);
}
/*
* Copyright (c) 2018 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KISFRAMECACHESTORE_H
#define KISFRAMECACHESTORE_H
#include "kritaui_export.h"
#include <QScopedPointer>
#include "kis_types.h"
#include "opengl/kis_texture_tile_info_pool.h"
class KisOpenGLUpdateInfoBuilder;
class KisOpenGLUpdateInfo;
typedef KisSharedPtr<KisOpenGLUpdateInfo> KisOpenGLUpdateInfoSP;
class KRITAUI_EXPORT KisFrameCacheStore
{
public:
KisFrameCacheStore(KisTextureTileInfoPoolSP pool);
KisFrameCacheStore(KisTextureTileInfoPoolSP pool, const QString &frameCachePath);
~KisFrameCacheStore();
void saveFrame(int frameId, KisOpenGLUpdateInfoSP info);
KisOpenGLUpdateInfoSP loadFrame(int frameId, const KisOpenGLUpdateInfoBuilder &builder);
void forgetFrame(int frameId);
bool hasFrame(int frameId) const;
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif // KISFRAMECACHESTORE_H
......@@ -21,7 +21,7 @@
#include <QTemporaryDir>
struct KisFrameDataSerializer::Private
struct KRITAUI_NO_EXPORT KisFrameDataSerializer::Private
{
Private(const QString &frameCachePath, KisTextureTileInfoPoolSP _pool)
: framesDir(
......@@ -101,10 +101,9 @@ void KisFrameDataSerializer::saveFrame(const KisFrameDataSerializer::Frame &fram
stream << tile.col;
stream << tile.row;
stream << tile.size.width();
stream << tile.size.height();
stream << tile.rect;
const int bufferSize = frame.pixelSize * tile.size.width() * tile.size.height();
const int bufferSize = frame.pixelSize * tile.rect.width() * tile.rect.height();
stream.writeRawData((char*)tile.data.data(), bufferSize);
}
......@@ -134,10 +133,9 @@ KisFrameDataSerializer::Frame KisFrameDataSerializer::loadFrame(int frameId)
FrameTile tile(m_d->pool);
stream >> tile.col;
stream >> tile.row;
stream >> tile.size.rwidth();
stream >> tile.size.rheight();
stream >> tile.rect;
const int bufferSize = frame.pixelSize * tile.size.width() * tile.size.height();
const int bufferSize = frame.pixelSize * tile.rect.width() * tile.rect.height();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(bufferSize <= m_d->pool->chunkSize(frame.pixelSize),
KisFrameDataSerializer::Frame());
......@@ -164,6 +162,11 @@ void KisFrameDataSerializer::forgetFrame(int frameId)
QFile::remove(framePath);
}
KisTextureTileInfoPoolSP KisFrameDataSerializer::tileInfoPool() const
{
return m_d->pool;
}
boost::optional<qreal> KisFrameDataSerializer::estimateFrameUniqueness(const KisFrameDataSerializer::Frame &lhs, const KisFrameDataSerializer::Frame &rhs, qreal portion)
{
if (lhs.pixelSize != rhs.pixelSize) return boost::none;
......@@ -180,13 +183,13 @@ boost::optional<qreal> KisFrameDataSerializer::estimateFrameUniqueness(const Kis
if (lhsTile.col != rhsTile.col ||
lhsTile.row != rhsTile.row ||
lhsTile.size != rhsTile.size) {
lhsTile.rect != rhsTile.rect) {
return boost::none;
}
if (sampleStep > 0) {
const int numPixels = lhsTile.size.width() * lhsTile.size.height();
const int numPixels = lhsTile.rect.width() * lhsTile.rect.height();
for (int j = 0; j < numPixels; j += sampleStep) {
quint8 *lhsDataPtr = lhsTile.data.data() + j * pixelSize;
quint8 *rhsDataPtr = rhsTile.data.data() + j * pixelSize;
......@@ -234,7 +237,7 @@ bool KisFrameDataSerializer::processFrames(KisFrameDataSerializer::Frame &dst, c
const FrameTile &srcTile = src.frameTiles[i];
FrameTile &dstTile = dst.frameTiles[i];
const int numBytes = srcTile.size.width() * srcTile.size.height() * src.pixelSize;
const int numBytes = srcTile.rect.width() * srcTile.rect.height() * src.pixelSize;
const int numQWords = numBytes / 8;
const quint64 *srcDataPtr = reinterpret_cast<const quint64*>(srcTile.data.data());
......
......@@ -36,14 +36,30 @@ public:
struct FrameTile
{
FrameTile(KisTextureTileInfoPoolSP pool) : data(pool) {}
FrameTile(FrameTile &&rhs) = default;
FrameTile& operator=(FrameTile &&rhs) = default;
FrameTile(const FrameTile &rhs) = delete;
FrameTile& operator=(FrameTile &rhs) = delete;
int col = -1;
int row = -1;
QSize size;
QRect rect;
DataBuffer data;
};
struct Frame
{
Frame() = default;
Frame(Frame&&rhs) = default;
Frame& operator=(Frame &&rhs) = default;
Frame(const Frame &rhs) = delete;
Frame& operator=(Frame &rhs) = delete;
int frameId = -1;
int pixelSize = 0;
std::vector<FrameTile> frameTiles;
......@@ -64,6 +80,8 @@ public:
bool hasFrame(int frameId) const;
void forgetFrame(int frameId);
KisTextureTileInfoPoolSP tileInfoPool() const;
static boost::optional<qreal> estimateFrameUniqueness(const Frame &lhs, const Frame &rhs, qreal portion);
static bool subtractFrames(Frame &dst, const Frame &src);
static void addFrames(Frame &dst, const Frame &src);
......@@ -76,7 +94,7 @@ private:
Q_DISABLE_COPY(KisFrameDataSerializer)
struct Private;
QScopedPointer<Private> m_d;
const QScopedPointer<Private> m_d;
};
#endif // KISFRAMEDATASERIALIZER_H
......@@ -17,6 +17,7 @@
*/
#include "KisOpenGLUpdateInfoBuilder.h"
// TODO: conversion options into a separate file!
#include "kis_update_info.h"
#include "opengl/kis_texture_tile_info_pool.h"
......@@ -36,7 +37,7 @@ struct KRITAUI_NO_EXPORT KisOpenGLUpdateInfoBuilder::Private
int selectedChannelIndex = -1;
int textureBorder = 0;
QSize textureSize;
QSize effectiveTextureSize;
KisProofingConfigurationSP proofingConfig;
QScopedPointer<KoColorConversionTransformation> proofingTransform;
......@@ -65,12 +66,18 @@ KisOpenGLUpdateInfoSP KisOpenGLUpdateInfoBuilder::buildUpdateInfo(const QRect &r
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->pool, info);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->conversionOptions.m_destinationColorSpace, info);
auto needCreateProofingTransform =
[this] () {
return !m_d->proofingTransform &&
m_d->proofingConfig &&
m_d->proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::SoftProofing);
};
// lazily create transform
if (convertColorSpace &&
!m_d->proofingTransform && m_d->proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::SoftProofing)) {
if (convertColorSpace && needCreateProofingTransform()) {
QWriteLocker locker(&m_d->lock);
if (!m_d->proofingTransform && m_d->proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::SoftProofing)) {
if (needCreateProofingTransform()) {
const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(m_d->proofingConfig->proofingModel,
m_d->proofingConfig->proofingDepth,
m_d->proofingConfig->proofingProfile);
......@@ -131,12 +138,7 @@ KisOpenGLUpdateInfoSP KisOpenGLUpdateInfoBuilder::buildUpdateInfo(const QRect &r
for (int col = firstColumn; col <= lastColumn; col++) {
for (int row = firstRow; row <= lastRow; row++) {
const QRect tileRect = calculateTileRect(col, row, srcImage);
const QRect tileTextureRect = kisGrowRect(tileRect, m_d->textureBorder);
QRect alignedTileTextureRect = levelOfDetail ?
KisLodTransform::alignedRect(tileTextureRect, levelOfDetail) :
tileTextureRect;
const QRect alignedTileTextureRect = calculatePhysicalTileRect(col, row, srcImage->bounds(), levelOfDetail);
KisTextureTileUpdateInfoSP tileInfo(
new KisTextureTileUpdateInfo(col, row,
......@@ -160,7 +162,7 @@ KisOpenGLUpdateInfoSP KisOpenGLUpdateInfoBuilder::buildUpdateInfo(const QRect &r
info->tileList.append(tileInfo);
}
else {
dbgUI << "Trying to create an empty tileinfo record" << col << row << tileTextureRect << updateRect << srcImage->bounds();
dbgUI << "Trying to create an empty tileinfo record" << col << row << alignedTileTextureRect << updateRect << srcImage->bounds();
}
}
}
......@@ -170,23 +172,36 @@ KisOpenGLUpdateInfoSP KisOpenGLUpdateInfoBuilder::buildUpdateInfo(const QRect &r
return info;
}
QRect KisOpenGLUpdateInfoBuilder::calculateTileRect(int col, int row, KisImageSP image) const
QRect KisOpenGLUpdateInfoBuilder::calculateEffectiveTileRect(int col, int row, const QRect &imageBounds) const
{
return imageBounds &
QRect(col * m_d->effectiveTextureSize.width(),
row * m_d->effectiveTextureSize.height(),
m_d->effectiveTextureSize.width(),
m_d->effectiveTextureSize.height());
}
QRect KisOpenGLUpdateInfoBuilder::calculatePhysicalTileRect(int col, int row, const QRect &imageBounds, int levelOfDetail) const
{
return image->bounds() &
QRect(col * m_d->textureSize.width(),
row * m_d->textureSize.height(),
m_d->textureSize.width(),
m_d->textureSize.height());
const QRect tileRect = calculateEffectiveTileRect(col, row, imageBounds);
const QRect tileTextureRect = kisGrowRect(tileRect, m_d->textureBorder);
const QRect alignedTileTextureRect = levelOfDetail ?
KisLodTransform::alignedRect(tileTextureRect, levelOfDetail) :
tileTextureRect;
return alignedTileTextureRect;
}
int KisOpenGLUpdateInfoBuilder::xToCol(int x) const
{
return x / m_d->textureSize.width();
return x / m_d->effectiveTextureSize.width();
}
int KisOpenGLUpdateInfoBuilder::yToRow(int y) const
{
return y / m_d->textureSize.height();
return y / m_d->effectiveTextureSize.height();
}
const KoColorSpace *KisOpenGLUpdateInfoBuilder::destinationColorSpace() const
......@@ -223,7 +238,7 @@ void KisOpenGLUpdateInfoBuilder::setEffectiveTextureSize(const QSize &size)
{
QWriteLocker lock(&m_d->lock);
m_d->textureSize = size;
m_d->effectiveTextureSize = size;
}
void KisOpenGLUpdateInfoBuilder::setTextureInfoPool(KisTextureTileInfoPoolSP pool)
......
......@@ -41,14 +41,15 @@ class KoColorSpace;
struct ConversionOptions;
class KisOpenGLUpdateInfoBuilder
class KRITAUI_EXPORT KisOpenGLUpdateInfoBuilder
{
public:
KisOpenGLUpdateInfoBuilder();
~KisOpenGLUpdateInfoBuilder();
KisOpenGLUpdateInfoSP buildUpdateInfo(const QRect& rect, KisImageSP srcImage, bool convertColorSpace);
QRect calculateTileRect(int col, int row, KisImageSP image) const;
QRect calculatePhysicalTileRect(int col, int row, const QRect &imageBounds, int levelOfDetail) const;
QRect calculateEffectiveTileRect(int col, int row, const QRect &imageBounds) const;
int xToCol(int x) const;
int yToRow(int y) const;
......
......@@ -210,7 +210,7 @@ void KisOpenGLImageTextures::createImageTextureTiles()
m_textureTiles.reserve((lastRow+1)*m_numCols);
for (int row = 0; row <= lastRow; row++) {
for (int col = 0; col <= lastCol; col++) {
QRect tileRect = m_updateInfoBuilder.calculateTileRect(col, row, m_image);
QRect tileRect = m_updateInfoBuilder.calculateEffectiveTileRect(col, row, m_image->bounds());
KisTextureTile *tile = new KisTextureTile(tileRect,
&m_texturesInfo,
......
......@@ -72,6 +72,11 @@ public:
rhs.m_data = 0;
}
DataBuffer& operator=(DataBuffer &&rhs) {
swap(rhs);
return *this;
}
~DataBuffer() {
if (m_data) {
m_pool->free(m_data, m_pixelSize);
......@@ -92,6 +97,7 @@ public:
void swap(DataBuffer &other) {
std::swap(other.m_pixelSize, m_pixelSize);
std::swap(other.m_data, m_data);
std::swap(other.m_pool, m_pool);
}
int size() const {
......@@ -133,6 +139,8 @@ public:
m_patchLevelOfDetail = levelOfDetail;
if (m_patchLevelOfDetail) {
// TODO: check if isBottommost() works correctly when m_originalPatchRect gets aligned
// and m_currentImageRect has non-aligned size
m_originalPatchRect = KisLodTransform::alignedRect(m_originalPatchRect, m_patchLevelOfDetail);
m_patchRect = KisLodTransform::scaledRect(m_originalPatchRect, m_patchLevelOfDetail);
m_tileRect = KisLodTransform::scaledRect(m_originalTileRect, m_patchLevelOfDetail);
......@@ -270,6 +278,10 @@ public:
return m_patchRect.size();
}
inline QRect realPatchRect() const {
return m_patchRect;
}
inline QSize realTileSize() const {
return m_tileRect.size();
}
......@@ -306,6 +318,10 @@ public:
return m_patchColorSpace->pixelSize();
}
inline const KoColorSpace* patchColorSpace() const {
return m_patchColorSpace;
}
inline quint32 patchPixelsLength() const {
return m_patchPixels.size();
}
......@@ -314,6 +330,15 @@ public:
return m_patchRect.isValid();
}
inline DataBuffer&& takePixelData() {
return std::move(m_patchPixels);
}
inline void putPixelData(DataBuffer &&buffer, const KoColorSpace *colorSpace) {
m_patchPixels = std::move(buffer);
m_patchColorSpace = colorSpace;
}
private:
Q_DISABLE_COPY(KisTextureTileUpdateInfo)
......
......@@ -36,6 +36,10 @@ ecm_add_test( KisFrameSerializerTest.cpp
TEST_NAME krita-ui-KisFrameSerializerTest
LINK_LIBRARIES kritaui kritaimage Qt5::Test)
ecm_add_test( KisFrameCacheStoreTest.cpp
TEST_NAME krita-ui-KisFrameCacheStoreTest
LINK_LIBRARIES kritaui kritaimage Qt5::Test)
ecm_add_test( kis_selection_decoration_test.cpp ../../../sdk/tests/stroke_testing_utils.cpp
TEST_NAME krita-ui-KisSelectionDecorationTest
LINK_LIBRARIES kritaui kritaimage Qt5::Test)
......
/*
* Copyright (c) 2018 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisFrameCacheStoreTest.h"
#include <QTest>
#include <testutil.h>
#include <KoColor.h>
#include "KisAsyncAnimationRendererBase.h"
#include "kis_image_animation_interface.h"
#include "opengl/KisOpenGLUpdateInfoBuilder.h"
#include "KoColorSpaceRegistry.h"
#include "KoColorSpace.h"
// TODO: conversion options into a separate file!
#include "kis_update_info.h"
#include "opengl/kis_texture_tile_update_info.h"
#include "KisFrameCacheStore.h"
static const int maxTileSize = 256;
bool compareTextureTileUpdateInfo(KisTextureTileUpdateInfoSP tile1, KisTextureTileUpdateInfoSP tile2)
{
KIS_COMPARE_RF(tile1->patchLevelOfDetail(), tile2->patchLevelOfDetail());
KIS_COMPARE_RF(tile1->realPatchOffset(), tile2->realPatchOffset());
KIS_COMPARE_RF(tile1->realPatchRect(), tile2->realPatchRect());
KIS_COMPARE_RF(tile1->realTileSize(), tile2->realTileSize());
KIS_COMPARE_RF(tile1->isTopmost(), tile2->isTopmost());
KIS_COMPARE_RF(tile1->isLeftmost(), tile2->isLeftmost());
KIS_COMPARE_RF(tile1->isRightmost(), tile2->isRightmost());
KIS_COMPARE_RF(tile1->isBottommost(), tile2->isBottommost());
KIS_COMPARE_RF(tile1->isEntireTileUpdated(), tile2->isEntireTileUpdated());
KIS_COMPARE_RF(tile1->tileCol(), tile2->tileCol());
KIS_COMPARE_RF(tile1->tileRow(), tile2->tileRow());
KIS_COMPARE_RF(tile1->pixelSize(), tile2->pixelSize());
KIS_COMPARE_RF(tile1->valid(), tile2->valid());
KIS_COMPARE_RF(tile1->patchPixelsLength(), tile2->patchPixelsLength());
const int numRealPixelBytes = tile1->realPatchRect().width() * tile1->realPatchRect().height() * tile1->pixelSize();
if (memcmp(tile1->data(), tile2->data(), numRealPixelBytes) != 0) {
qWarning() << "Tile pixels differ!";
qWarning() << " " << ppVar(tile1->tileCol()) << ppVar(tile1->tileRow());
qWarning() << " " << ppVar(numRealPixelBytes);
quint8 *src = tile1->data();
quint8 *dst = tile2->data();
for (int i = 0; i < numRealPixelBytes; i++) {
if (*src != *dst) {
qDebug() << " " << ppVar(i) << ppVar(*src) << ppVar(*dst);
}
src++;
dst++;
}
return false;
}
return true;
}
bool compareUpdateInfo(KisOpenGLUpdateInfoSP info1, KisOpenGLUpdateInfoSP info2)
{
KIS_COMPARE_RF(info1->dirtyImageRect(), info2->dirtyImageRect());
KIS_COMPARE_RF(info1->levelOfDetail(), info2->levelOfDetail());
KIS_COMPARE_RF(info1->tileList.size(), info2->tileList.size());
for (int i = 0; i < info1->tileList.size(); i++) {
if (!compareTextureTileUpdateInfo(info1->tileList[i], info2->tileList[i])) {
return false;
}
}
return true;
}
class TestFramesRenderer : public KisAsyncAnimationRendererBase
{
Q_OBJECT
public:
TestFramesRenderer()
: m_pool(m_poolRegistry.getPool(maxTileSize, maxTileSize)),
m_store(m_pool)
{
m_updateInfoBuilder.setTextureInfoPool(m_pool);
const KoColorSpace *dstColorSpace = KoColorSpaceRegistry::instance()->rgb8();
m_updateInfoBuilder.setConversionOptions(
ConversionOptions(dstColorSpace,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()));
// TODO: refactor setting texture size in raw values!
m_updateInfoBuilder.setTextureBorder(8);
m_updateInfoBuilder.setEffectiveTextureSize(QSize(256 - 16, 256 - 16));
connect(this, SIGNAL(sigCompleteRegenerationInternal(int)), SLOT(notifyFrameCompleted(int)));
connect(this, SIGNAL(sigCancelRegenerationInternal(int)), SLOT(notifyFrameCancelled(int)));
}
void frameCompletedCallback(int frame) override {
ENTER_FUNCTION() << ppVar(frame);
KisImageSP image = requestedImage();
KIS_SAFE_ASSERT_RECOVER_NOOP(frame == image->animationInterface()->currentTime());
KisOpenGLUpdateInfoSP info = m_updateInfoBuilder.buildUpdateInfo(image->bounds(), image, true);
KIS_ASSERT_RECOVER_NOOP(info);
qDebug() << ppVar(info->tileList.size());
KisOpenGLUpdateInfoSP infoForSave = m_updateInfoBuilder.buildUpdateInfo(image->bounds(), image, true);
m_store.saveFrame(11, infoForSave);
KIS_SAFE_ASSERT_RECOVER_NOOP(m_store.hasFrame(11));
KisOpenGLUpdateInfoSP loadedInfo = m_store.loadFrame(11, m_updateInfoBuilder);
qDebug() << ppVar(loadedInfo->tileList.size());
KIS_SAFE_ASSERT_RECOVER_NOOP(compareUpdateInfo(info, loadedInfo));
emit sigCompleteRegenerationInternal(frame);
}
void frameCancelledCallback(int frame) {