diff --git a/libs/image/tiles3/KisTiledExtentManager.cpp b/libs/image/tiles3/KisTiledExtentManager.cpp index 8d2b203181..71aeac3370 100644 --- a/libs/image/tiles3/KisTiledExtentManager.cpp +++ b/libs/image/tiles3/KisTiledExtentManager.cpp @@ -1,197 +1,205 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * 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 "KisTiledExtentManager.h" #include #include #include "kis_tile_data_interface.h" #include "kis_assert.h" #include "kis_global.h" +#include "kis_debug.h" -namespace { +KisTiledExtentManager::Data::Data() + : m_min(INT_MAX), m_max(INT_MIN) +{ + QWriteLocker l(&m_lock); + m_capacity = InitialBufferSize; + m_offset = m_capacity >> 1; + m_buffer = new QAtomicInt[m_capacity]; +} + +KisTiledExtentManager::Data::~Data() +{ + QWriteLocker l(&m_lock); + delete m_buffer; +} -inline bool addTileToMap(int index, QAtomicInt array[], - QAtomicInt &min, QAtomicInt &max, QReadWriteLock &lock) +inline bool KisTiledExtentManager::Data::add(int index) { - QReadLocker l(&lock); - KIS_ASSERT_RECOVER_NOOP(array[512 + index].loadAcquire() >= 0); + QReadLocker l(&m_lock); + int currentIndex = m_offset + index; + KIS_ASSERT_RECOVER_NOOP(m_buffer[currentIndex].loadAcquire() >= 0); bool needsUpdateExtent = false; - if (min > index) min.storeRelease(index); - if (max < index) max.storeRelease(index); - if (!array[512 + index].fetchAndAddOrdered(1)) { - array[0].ref(); + if (m_min > index) m_min.storeRelease(index); + if (m_max < index) m_max.storeRelease(index); + + if (!m_buffer[currentIndex].fetchAndAddOrdered(1)) { + m_count.ref(); needsUpdateExtent = true; } return needsUpdateExtent; } -void updateMin(QAtomicInt array[], QAtomicInt &min) +inline bool KisTiledExtentManager::Data::remove(int index) { - for (int i = 1; i < 1024; ++i) { - if (array[i] > 0) { - min.storeRelease(array[i]); - break; - } + QReadLocker l(&m_lock); + int currentIndex = m_offset + index; + + KIS_ASSERT_RECOVER_NOOP(m_buffer[currentIndex].loadAcquire() >= 0); + bool needsUpdateExtent = false; + + if (!m_buffer[currentIndex].fetchAndSubOrdered(1)) { + if (m_min == index) updateMin(); + if (m_max == index) updateMax(); + + m_count.deref(); + needsUpdateExtent = true; } + + return needsUpdateExtent; } -void updateMax(QAtomicInt array[], QAtomicInt &max) +void KisTiledExtentManager::Data::clear() { - for (int i = 1023; i > 0; ++i) { - if (array[i] > 0) { - max.storeRelease(array[i]); - break; - } + m_count.storeRelease(0); + QWriteLocker l(&m_lock); + + for (int i = 0; i < m_capacity; ++i) { + m_buffer[i] = 0; } } -inline bool removeTileFromMap(int index, QAtomicInt array[], - QAtomicInt &min, QAtomicInt &max, QReadWriteLock &lock) +bool KisTiledExtentManager::Data::isEmpty() { - QReadLocker l(&lock); - KIS_ASSERT_RECOVER_NOOP(array[512 + index].loadAcquire() >= 0); + return m_count.loadAcquire() == 0; +} - bool needsUpdateExtent = false; - array[512 + index].deref(); +int KisTiledExtentManager::Data::min() +{ + return m_min.loadAcquire(); +} - if (!array[512 + index].loadAcquire()) { - if (min == index) { - updateMin(array, min); - } +int KisTiledExtentManager::Data::max() +{ + return m_max.loadAcquire(); +} - if (max == index) { - updateMax(array, max); +void KisTiledExtentManager::Data::updateMin() +{ + for (int i = 0; i < m_capacity; ++i) { + if (m_buffer[i] > 0) { + m_min.storeRelease(m_buffer[i]); + break; } - - array[0].deref(); - needsUpdateExtent = true; } - - return needsUpdateExtent; } - +void KisTiledExtentManager::Data::updateMax() +{ + for (int i = m_capacity - 1; i >= 0; ++i) { + if (m_buffer[i] > 0) { + m_max.storeRelease(m_buffer[i]); + break; + } + } } KisTiledExtentManager::KisTiledExtentManager() - : m_minCol(INT_MAX), - m_maxCol(INT_MIN), - m_minRow(INT_MAX), - m_maxRow(INT_MIN) { } void KisTiledExtentManager::notifyTileAdded(int col, int row) { bool needsUpdateExtent = false; - needsUpdateExtent |= addTileToMap(col, m_colArray, m_minCol, m_maxCol, m_colArrayLock); - needsUpdateExtent |= addTileToMap(row, m_rowArray, m_minRow, m_maxRow, m_rowArrayLock); + needsUpdateExtent |= m_colsData.add(col); + needsUpdateExtent |= m_rowsData.add(row); if (needsUpdateExtent) { updateExtent(); } } void KisTiledExtentManager::notifyTileRemoved(int col, int row) { bool needsUpdateExtent = false; - needsUpdateExtent |= removeTileFromMap(col, m_colArray, m_minCol, m_maxCol, m_colArrayLock); - needsUpdateExtent |= removeTileFromMap(row, m_rowArray, m_minRow, m_maxRow, m_rowArrayLock); + needsUpdateExtent |= m_colsData.remove(col); + needsUpdateExtent |= m_rowsData.remove(row); if (needsUpdateExtent) { updateExtent(); } } -void clearArray(QAtomicInt array[], QReadWriteLock &lock) -{ - QWriteLocker l(&lock); - - for (int i = 0; i < 1024; ++i) { - array[i] = 0; - } -} - void KisTiledExtentManager::replaceTileStats(const QVector &indexes) { - clearArray(m_colArray, m_colArrayLock); - clearArray(m_rowArray, m_rowArrayLock); + m_colsData.clear(); + m_rowsData.clear(); Q_FOREACH (const QPoint &index, indexes) { - addTileToMap(index.x(), m_colArray, m_minCol, m_maxCol, m_colArrayLock); - addTileToMap(index.y(), m_rowArray, m_minRow, m_maxRow, m_rowArrayLock); + m_colsData.add(index.x()); + m_rowsData.add(index.y()); } updateExtent(); } void KisTiledExtentManager::clear() { - clearArray(m_colArray, m_colArrayLock); - clearArray(m_rowArray, m_rowArrayLock); + m_colsData.clear(); + m_rowsData.clear(); QWriteLocker l(&m_mutex); m_currentExtent = QRect(qint32_MAX, qint32_MAX, 0, 0); } QRect KisTiledExtentManager::extent() const { QReadLocker l(&m_mutex); return m_currentExtent; } void KisTiledExtentManager::updateExtent() { - bool colArrayEmpty = false; - bool rowArrayEmpty = false; - { - QReadLocker l(&m_colArrayLock); - colArrayEmpty = m_colArray[0] == 0; - } - { - QReadLocker l(&m_rowArrayLock); - rowArrayEmpty = m_rowArray[0] == 0; - } + bool colsEmpty = m_colsData.isEmpty(); + bool rowsEmpty = m_rowsData.isEmpty(); - KIS_ASSERT_RECOVER_RETURN(colArrayEmpty == rowArrayEmpty); + KIS_ASSERT_RECOVER_RETURN(colsEmpty == rowsEmpty); - // here we check for only one map for efficiency reasons - if (colArrayEmpty && rowArrayEmpty) { + if (colsEmpty && rowsEmpty) { QWriteLocker l(&m_mutex); m_currentExtent = QRect(qint32_MAX, qint32_MAX, 0, 0); } else { - const int minX = m_minCol.loadAcquire() * KisTileData::WIDTH; - const int maxPlusOneX = (m_maxCol.loadAcquire() + 1) * KisTileData::WIDTH; - const int minY = m_minRow.loadAcquire() * KisTileData::HEIGHT; - const int maxPlusOneY = (m_maxRow.loadAcquire() + 1) * KisTileData::HEIGHT; + const int minX = m_colsData.min() * KisTileData::WIDTH; + const int maxPlusOneX = (m_colsData.max() + 1) * KisTileData::WIDTH; + const int minY = m_rowsData.min() * KisTileData::HEIGHT; + const int maxPlusOneY = (m_rowsData.max() + 1) * KisTileData::HEIGHT; QWriteLocker l(&m_mutex); m_currentExtent = QRect(minX, minY, maxPlusOneX - minX, maxPlusOneY - minY); } } - diff --git a/libs/image/tiles3/KisTiledExtentManager.h b/libs/image/tiles3/KisTiledExtentManager.h index 6ef2980821..202dd420b1 100644 --- a/libs/image/tiles3/KisTiledExtentManager.h +++ b/libs/image/tiles3/KisTiledExtentManager.h @@ -1,60 +1,81 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * 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 KISTILEDEXTENTMANAGER_H #define KISTILEDEXTENTMANAGER_H #include #include #include #include #include "kritaimage_export.h" class KRITAIMAGE_EXPORT KisTiledExtentManager { + static const int InitialBufferSize = 4096; + + class Data + { + public: + Data(); + ~Data(); + + inline bool add(int index); + inline bool remove(int index); + void clear(); + bool isEmpty(); + int min(); + int max(); + + private: + void updateMin(); + void updateMax(); + + private: + QAtomicInt m_min; + QAtomicInt m_max; + int m_offset; + int m_capacity; + QAtomicInt m_count; + QAtomicInt *m_buffer; + QReadWriteLock m_lock; + }; + public: KisTiledExtentManager(); void notifyTileAdded(int col, int row); void notifyTileRemoved(int col, int row); void replaceTileStats(const QVector &indexes); void clear(); QRect extent() const; private: void updateExtent(); private: mutable QReadWriteLock m_mutex; QRect m_currentExtent; - - QAtomicInt m_minCol; - QAtomicInt m_maxCol; - QAtomicInt m_colArray[1024]; - QReadWriteLock m_colArrayLock; - - QAtomicInt m_minRow; - QAtomicInt m_maxRow; - QAtomicInt m_rowArray[1024]; - QReadWriteLock m_rowArrayLock; + Data m_colsData; + Data m_rowsData; }; #endif // KISTILEDEXTENTMANAGER_H