Krita Source Code Documentation
Loading...
Searching...
No Matches
KisTiledExtentManager.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
3 * SPDX-FileCopyrightText: 2018 Andrey Kamakin <a.kamakin@icloud.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
9
10#include <QVector>
12#include "kis_assert.h"
13#include "kis_global.h"
14#include "kis_debug.h"
15
17 : m_min(qint32_MAX), m_max(qint32_MIN), m_count(0)
18{
19 QWriteLocker lock(&m_migrationLock);
21 m_offset = 1;
22 m_buffer = new QAtomicInt[m_capacity];
23}
24
26{
27 QWriteLocker lock(&m_migrationLock);
28 delete[] m_buffer;
29}
30
32{
33 QReadLocker lock(&m_migrationLock);
34 qint32 currentIndex = m_offset + index;
35
36 if (currentIndex < 0 || currentIndex >= m_capacity) {
37 lock.unlock();
38 migrate(index);
39 lock.relock();
40 currentIndex = m_offset + index;
41 }
42
43 KIS_ASSERT_RECOVER_NOOP(m_buffer[currentIndex].loadAcquire() >= 0);
44 bool needsUpdateExtent = false;
45
46 while (true) {
47 QReadLocker rl(&m_extentLock);
48
49 int oldValue = m_buffer[currentIndex].loadAcquire();
50 if (oldValue == 0) {
51 rl.unlock();
52 QWriteLocker wl(&m_extentLock);
53
54 if ((oldValue = m_buffer[currentIndex].loadAcquire()) == 0) {
55
56 if (m_min > index) m_min = index;
57 if (m_max < index) m_max = index;
58
59 ++m_count;
60 needsUpdateExtent = true;
61
62 m_buffer[currentIndex].storeRelease(1);
63 } else {
64 m_buffer[currentIndex].storeRelease(oldValue + 1);
65 }
66
67 break;
68 } else if (m_buffer[currentIndex].testAndSetOrdered(oldValue, oldValue + 1)) {
69 break;
70 }
71 }
72
73 return needsUpdateExtent;
74}
75
77{
78 QReadLocker lock(&m_migrationLock);
79 qint32 currentIndex = m_offset + index;
80
81 bool needsUpdateExtent = false;
82 QReadLocker rl(&m_extentLock);
83
84 const int oldValue = m_buffer[currentIndex].fetchAndAddAcquire(-1);
85
93 KIS_SAFE_ASSERT_RECOVER(oldValue > 0) {
94 m_buffer[currentIndex].storeRelaxed(0);
95 return false;
96 }
97
98 if (oldValue == 1) {
99 rl.unlock();
100 QWriteLocker wl(&m_extentLock);
101
102 if (m_min == index) updateMin();
103 if (m_max == index) updateMax();
104
105 --m_count;
106 needsUpdateExtent = true;
107 }
108
109 return needsUpdateExtent;
110}
111
113{
114 QWriteLocker lock(&m_migrationLock);
115 QWriteLocker l(&m_extentLock);
116
117 for (qint32 i = 0; i < m_capacity; ++i) {
118 m_buffer[i].storeRelaxed(0);
119 }
120
121 m_min = qint32_MAX;
122 m_max = qint32_MIN;
123 m_count = 0;
124
125 Q_FOREACH (const qint32 index, indexes) {
126 unsafeAdd(index);
127 }
128}
129
131{
132 QWriteLocker lock(&m_migrationLock);
133 QWriteLocker l(&m_extentLock);
134
135 for (qint32 i = 0; i < m_capacity; ++i) {
136 m_buffer[i].storeRelaxed(0);
137 }
138
139 m_min = qint32_MAX;
140 m_max = qint32_MIN;
141 m_count = 0;
142}
143
145{
146 return m_count == 0;
147}
148
150{
151 return m_min;
152}
153
155{
156 return m_max;
157}
158
160{
161 qint32 currentIndex = m_offset + index;
162
163 if (currentIndex < 0 || currentIndex >= m_capacity) {
164 unsafeMigrate(index);
165 currentIndex = m_offset + index;
166 }
167
168 if (!m_buffer[currentIndex].fetchAndAddRelaxed(1)) {
169 if (m_min > index) m_min = index;
170 if (m_max < index) m_max = index;
171 ++m_count;
172 }
173}
174
176{
177 qint32 oldCapacity = m_capacity;
178 qint32 oldOffset = m_offset;
179 qint32 currentIndex = m_offset + index;
180
181 while (currentIndex < 0 || currentIndex >= m_capacity) {
182 m_capacity <<= 1;
183
184 if (currentIndex < 0) {
185 m_offset <<= 1;
186 currentIndex = m_offset + index;
187 }
188 }
189
190 if (m_capacity != oldCapacity) {
191 QAtomicInt *newBuffer = new QAtomicInt[m_capacity];
192 qint32 start = m_offset - oldOffset;
193
194 for (qint32 i = 0; i < oldCapacity; ++i) {
195 newBuffer[start + i].storeRelaxed(m_buffer[i].loadRelaxed());
196 }
197
198 delete[] m_buffer;
199 m_buffer = newBuffer;
200 }
201}
202
204{
205 QWriteLocker lock(&m_migrationLock);
206 unsafeMigrate(index);
207}
208
210{
212
213 qint32 start = m_min + m_offset;
214
215 for (qint32 i = start; i < m_capacity; ++i) {
216 qint32 current = m_buffer[i].loadRelaxed();
217
218 if (current > 0) {
219 m_min = i - m_offset;
220 return;
221 }
222 }
223
224 m_min = qint32_MAX;
225}
226
228{
230
231 qint32 start = m_max + m_offset;
232
233 for (qint32 i = start; i >= 0; --i) {
234 qint32 current = m_buffer[i].loadRelaxed();
235
236 if (current > 0) {
237 m_max = i - m_offset;
238 return;
239 }
240 }
241
242 m_max = qint32_MIN;
243}
244
246{
247 QWriteLocker l(&m_extentLock);
248 m_currentExtent = QRect();
249}
250
251void KisTiledExtentManager::notifyTileAdded(qint32 col, qint32 row)
252{
253 bool needsUpdateExtent = false;
254
255 needsUpdateExtent |= m_colsData.add(col);
256 needsUpdateExtent |= m_rowsData.add(row);
257
258 if (needsUpdateExtent) {
259 updateExtent();
260 }
261}
262
264{
265 bool needsUpdateExtent = false;
266
267 needsUpdateExtent |= m_colsData.remove(col);
268 needsUpdateExtent |= m_rowsData.remove(row);
269
270 if (needsUpdateExtent) {
271 updateExtent();
272 }
273}
274
276{
277 QVector<qint32> colsIndexes;
278 QVector<qint32> rowsIndexes;
279
280 Q_FOREACH (const QPoint &index, indexes) {
281 colsIndexes.append(index.x());
282 rowsIndexes.append(index.y());
283 }
284
285 m_colsData.replace(colsIndexes);
286 m_rowsData.replace(rowsIndexes);
287 updateExtent();
288}
289
291{
294
295 QWriteLocker lock(&m_extentLock);
296 m_currentExtent = QRect();
297}
298
300{
301 QReadLocker lock(&m_extentLock);
302 return m_currentExtent;
303}
304
306{
307 qint32 minX, width, minY, height;
308
309 {
310 QReadLocker cl(&m_colsData.m_extentLock);
311
312 if (m_colsData.isEmpty()) {
313 minX = 0;
314 width = 0;
315 } else {
317 width = (m_colsData.max() + 1) * KisTileData::WIDTH - minX;
318 }
319 }
320
321 {
322 QReadLocker rl(&m_rowsData.m_extentLock);
323
324 if (m_rowsData.isEmpty()) {
325 minY = 0;
326 height = 0;
327 } else {
329 height = (m_rowsData.max() + 1) * KisTileData::HEIGHT - minY;
330 }
331 }
332
333 QWriteLocker lock(&m_extentLock);
334 m_currentExtent = QRect(minX, minY, width, height);
335}
static const qint32 HEIGHT
static const qint32 WIDTH
void replace(const QVector< qint32 > &indexes)
static const qint32 InitialBufferSize
void notifyTileAdded(qint32 col, qint32 row)
void replaceTileStats(const QVector< QPoint > &indexes)
void notifyTileRemoved(qint32 col, qint32 row)
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
const qint32 qint32_MIN
Definition kis_global.h:30
const qint32 qint32_MAX
Definition kis_global.h:29