1 /*
2  *  Copyright (c) 2010 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 
19 //#include "kis_debug.h"
20 #include "kis_swapped_data_store.h"
21 #include "kis_memory_window.h"
22 #include "kis_image_config.h"
23 
24 #include "kis_tile_compressor_2.h"
25 
26 //#define COMPRESSOR_VERSION 2
27 
KisSwappedDataStore()28 KisSwappedDataStore::KisSwappedDataStore()
29     : m_memoryMetric(0)
30 {
31     KisImageConfig config(true);
32     const quint64 maxSwapSize = config.maxSwapSize() * MiB;
33     const quint64 swapSlabSize = config.swapSlabSize() * MiB;
34     const quint64 swapWindowSize = config.swapWindowSize() * MiB;
35 
36     m_allocator = new KisChunkAllocator(swapSlabSize, maxSwapSize);
37     m_swapSpace = new KisMemoryWindow(config.swapDir(), swapWindowSize);
38 
39     // FIXME: use a factory after the patch is committed
40     m_compressor = new KisTileCompressor2();
41 }
42 
~KisSwappedDataStore()43 KisSwappedDataStore::~KisSwappedDataStore()
44 {
45     delete m_compressor;
46     delete m_swapSpace;
47     delete m_allocator;
48 }
49 
numTiles() const50 quint64 KisSwappedDataStore::numTiles() const
51 {
52     // We are not acquiring the lock here...
53     // Hope QLinkedList will ensure atomic access to it's size...
54 
55     return m_allocator->numChunks();
56 }
57 
trySwapOutTileData(KisTileData * td)58 bool KisSwappedDataStore::trySwapOutTileData(KisTileData *td)
59 {
60     Q_ASSERT(td->data());
61     QMutexLocker locker(&m_lock);
62 
63     /**
64      * We are expecting that the lock of KisTileData
65      * has already been taken by the caller for us.
66      * So we can modify the tile data freely.
67      */
68 
69     const qint32 expectedBufferSize = m_compressor->tileDataBufferSize(td);
70     if(m_buffer.size() < expectedBufferSize)
71         m_buffer.resize(expectedBufferSize);
72 
73     qint32 bytesWritten;
74     m_compressor->compressTileData(td, (quint8*) m_buffer.data(), m_buffer.size(), bytesWritten);
75 
76     KisChunk chunk = m_allocator->getChunk(bytesWritten);
77     quint8 *ptr = m_swapSpace->getWriteChunkPtr(chunk);
78     if (!ptr) {
79         qWarning() << "swap out of tile failed";
80         return false;
81     }
82     memcpy(ptr, m_buffer.data(), bytesWritten);
83 
84     td->releaseMemory();
85     td->setSwapChunk(chunk);
86 
87     m_memoryMetric += td->pixelSize();
88 
89     return true;
90 }
91 
swapInTileData(KisTileData * td)92 void KisSwappedDataStore::swapInTileData(KisTileData *td)
93 {
94     Q_ASSERT(!td->data());
95     QMutexLocker locker(&m_lock);
96 
97     // see comment in swapOutTileData()
98 
99     KisChunk chunk = td->swapChunk();
100 
101     td->allocateMemory();
102     td->setSwapChunk(KisChunk());
103 
104     quint8 *ptr = m_swapSpace->getReadChunkPtr(chunk);
105     Q_ASSERT(ptr);
106     m_compressor->decompressTileData(ptr, chunk.size(), td);
107     m_allocator->freeChunk(chunk);
108 
109     m_memoryMetric -= td->pixelSize();
110 }
111 
forgetTileData(KisTileData * td)112 void KisSwappedDataStore::forgetTileData(KisTileData *td)
113 {
114     QMutexLocker locker(&m_lock);
115 
116     m_allocator->freeChunk(td->swapChunk());
117     td->setSwapChunk(KisChunk());
118 
119     m_memoryMetric -= td->pixelSize();
120 }
121 
totalMemoryMetric() const122 qint64 KisSwappedDataStore::totalMemoryMetric() const
123 {
124     return m_memoryMetric;
125 }
126 
debugStatistics()127 void KisSwappedDataStore::debugStatistics()
128 {
129     m_allocator->sanityCheck();
130     m_allocator->debugFragmentation();
131 }
132