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