1 /*
2  *  Copyright (c) 2018 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 #include "KisFrameCacheStoreTest.h"
19 
20 #include <QTest>
21 #include <testutil.h>
22 
23 #include <KoColor.h>
24 #include "KisAsyncAnimationRendererBase.h"
25 #include "kis_image_animation_interface.h"
26 #include "opengl/KisOpenGLUpdateInfoBuilder.h"
27 
28 #include "KoColorSpaceRegistry.h"
29 #include "KoColorSpace.h"
30 
31 // TODO: conversion options into a separate file!
32 #include "kis_update_info.h"
33 
34 #include "opengl/kis_texture_tile_update_info.h"
35 
36 
37 #include "KisFrameCacheStore.h"
38 
39 static const int maxTileSize = 256;
40 
compareTextureTileUpdateInfo(KisTextureTileUpdateInfoSP tile1,KisTextureTileUpdateInfoSP tile2)41 bool compareTextureTileUpdateInfo(KisTextureTileUpdateInfoSP tile1, KisTextureTileUpdateInfoSP tile2)
42 {
43     KIS_COMPARE_RF(tile1->patchLevelOfDetail(), tile2->patchLevelOfDetail());
44     KIS_COMPARE_RF(tile1->realPatchOffset(), tile2->realPatchOffset());
45     KIS_COMPARE_RF(tile1->realPatchRect(), tile2->realPatchRect());
46     KIS_COMPARE_RF(tile1->realTileSize(), tile2->realTileSize());
47     KIS_COMPARE_RF(tile1->isTopmost(), tile2->isTopmost());
48     KIS_COMPARE_RF(tile1->isLeftmost(), tile2->isLeftmost());
49     KIS_COMPARE_RF(tile1->isRightmost(), tile2->isRightmost());
50     KIS_COMPARE_RF(tile1->isBottommost(), tile2->isBottommost());
51     KIS_COMPARE_RF(tile1->isEntireTileUpdated(), tile2->isEntireTileUpdated());
52 
53     KIS_COMPARE_RF(tile1->tileCol(), tile2->tileCol());
54     KIS_COMPARE_RF(tile1->tileRow(), tile2->tileRow());
55     KIS_COMPARE_RF(tile1->pixelSize(), tile2->pixelSize());
56     KIS_COMPARE_RF(tile1->valid(), tile2->valid());
57 
58     KIS_COMPARE_RF(tile1->patchPixelsLength(), tile2->patchPixelsLength());
59 
60 
61     const uint numRealPixelBytes = static_cast<uint>(tile1->realPatchRect().width() * tile1->realPatchRect().height() * tile1->pixelSize());
62 
63     if (memcmp(tile1->data(), tile2->data(), numRealPixelBytes) != 0) {
64         qWarning() << "Tile pixels differ!";
65         qWarning() << "    " << ppVar(tile1->tileCol()) << ppVar(tile1->tileRow());
66         qWarning() << "    " << ppVar(numRealPixelBytes);
67 
68         quint8 *src = tile1->data();
69         quint8 *dst = tile2->data();
70 
71         for (uint i = 0; i < numRealPixelBytes; i++) {
72             if (*src != *dst) {
73                 qDebug() << "    " << ppVar(i) << ppVar(*src) << ppVar(*dst);
74             }
75 
76             src++;
77             dst++;
78         }
79 
80         return false;
81     }
82 
83     return true;
84 }
85 
86 
compareUpdateInfo(KisOpenGLUpdateInfoSP info1,KisOpenGLUpdateInfoSP info2)87 bool compareUpdateInfo(KisOpenGLUpdateInfoSP info1, KisOpenGLUpdateInfoSP info2)
88 {
89     KIS_COMPARE_RF(info1->dirtyImageRect(), info2->dirtyImageRect());
90     KIS_COMPARE_RF(info1->levelOfDetail(), info2->levelOfDetail());
91     KIS_COMPARE_RF(info1->tileList.size(), info2->tileList.size());
92 
93     for (int i = 0; i < info1->tileList.size(); i++) {
94         if (!compareTextureTileUpdateInfo(info1->tileList[i], info2->tileList[i])) {
95             return false;
96         }
97     }
98 
99     return true;
100 }
101 
102 
103 class TestFramesRenderer : public KisAsyncAnimationRendererBase
104 {
105     Q_OBJECT
106 
107 public:
TestFramesRenderer()108     TestFramesRenderer()
109         : m_pool(m_poolRegistry.getPool(maxTileSize, maxTileSize))
110     {
111         m_updateInfoBuilder.setTextureInfoPool(m_pool);
112 
113         const KoColorSpace *dstColorSpace = KoColorSpaceRegistry::instance()->rgb8();
114         m_updateInfoBuilder.setConversionOptions(
115             ConversionOptions(dstColorSpace,
116                               KoColorConversionTransformation::internalRenderingIntent(),
117                               KoColorConversionTransformation::internalConversionFlags()));
118 
119         // TODO: refactor setting texture size in raw values!
120         m_updateInfoBuilder.setTextureBorder(8);
121         m_updateInfoBuilder.setEffectiveTextureSize(QSize(256 - 16, 256 - 16));
122 
123         connect(this, SIGNAL(sigCompleteRegenerationInternal(int)), SLOT(notifyFrameCompleted(int)));
124         connect(this, SIGNAL(sigCancelRegenerationInternal(int)), SLOT(notifyFrameCancelled(int)));
125     }
126 
frameCompletedCallback(int frame,const KisRegion & requestedRegion)127     void frameCompletedCallback(int frame, const KisRegion &requestedRegion) override {
128         KisImageSP image = requestedImage();
129         KIS_SAFE_ASSERT_RECOVER_NOOP(frame == image->animationInterface()->currentTime());
130 
131         // by default we request update for the entire image
132         KIS_SAFE_ASSERT_RECOVER_NOOP(requestedRegion == image->bounds());
133 
134         KisOpenGLUpdateInfoSP info = m_updateInfoBuilder.buildUpdateInfo(image->bounds(), image, true);
135 
136         KIS_ASSERT_RECOVER_NOOP(info);
137         qDebug() << ppVar(info->tileList.size());
138 
139         KisOpenGLUpdateInfoSP infoForSave = m_updateInfoBuilder.buildUpdateInfo(image->bounds(), image, true);
140         m_store.saveFrame(11, infoForSave, image->bounds());
141 
142         KIS_SAFE_ASSERT_RECOVER_NOOP(m_store.hasFrame(11));
143 
144         KisOpenGLUpdateInfoSP loadedInfo = m_store.loadFrame(11, m_updateInfoBuilder);
145 
146         qDebug() << ppVar(loadedInfo->tileList.size());
147 
148         KIS_SAFE_ASSERT_RECOVER_NOOP(compareUpdateInfo(info, loadedInfo));
149 
150 
151         emit sigCompleteRegenerationInternal(frame);
152     }
153 
frameCancelledCallback(int frame)154     void frameCancelledCallback(int frame) override {
155         emit sigCancelRegenerationInternal(frame);
156     }
157 
158 Q_SIGNALS:
159     void sigCompleteRegenerationInternal(int frame);
160     void sigCancelRegenerationInternal(int frame);
161 
162 private:
163     KisOpenGLUpdateInfoBuilder m_updateInfoBuilder;
164     KisTextureTileInfoPoolRegistry m_poolRegistry;
165     KisTextureTileInfoPoolSP m_pool;
166     KisFrameCacheStore m_store;
167 };
168 
169 
170 
171 
test()172 void KisFrameCacheStoreTest::test()
173 {
174     QRect refRect(QRect(0,0,512,512));
175     TestUtil::MaskParent p(refRect);
176     const KoColor fillColor(Qt::red, p.image->colorSpace());
177 
178     KisPaintLayerSP layer1 = p.layer;
179     layer1->paintDevice()->fill(QRect(100,100,300,300), fillColor);
180 
181     TestFramesRenderer renderer;
182     renderer.startFrameRegeneration(p.image, 10);
183 
184 
185     p.image->waitForDone();
186 
187     while (renderer.isActive()) {
188         QTest::qWait(500);
189     }
190 
191 }
192 
193 QTEST_MAIN(KisFrameCacheStoreTest)
194 
195 #include "KisFrameCacheStoreTest.moc"
196