Commit 3647fbfb authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implemented KisSequentialIterator

This iterator is an HLineIterator-based substitution for the usual
Rect Iterator, which should get deprecated for several reasons:

1) It is really complicated to implement a Wrapped version of this
   iterator.
2) New KisSequentialIterator is about twice faster than old Rect Iterator
3) We used Rect Iterator quite rarely
parent 94b3f140
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* 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 __KO_ALWAYS_INLINE_H
#define __KO_ALWAYS_INLINE_H
#ifndef ALWAYS_INLINE
#if defined __GNUC__
#define ALWAYS_INLINE inline __attribute__((__always_inline__))
#elif defined _MSC_VER
#define ALWAYS_INLINE __forceinline
#else
#define ALWAYS_INLINE inline
#endif
#endif
#endif /* __KO_ALWAYS_INLINE_H */
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* 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 __KIS_SEQUENTIAL_ITERATOR_H
#define __KIS_SEQUENTIAL_ITERATOR_H
#include <KoAlwaysInline.h>
#include "kis_types.h"
#include "kis_paint_device.h"
#include "kis_iterator_ng.h"
struct ReadOnlyIteratorPolicy {
typedef KisHLineConstIteratorSP IteratorTypeSP;
ReadOnlyIteratorPolicy(KisPaintDeviceSP dev, const QRect &rect) {
m_iter = dev->createHLineConstIteratorNG(rect.x(), rect.y(), rect.width());
}
ALWAYS_INLINE void updatePointersCache() {
m_rawDataConst = m_iter->rawDataConst();
m_oldRawData = m_iter->oldRawData();
}
ALWAYS_INLINE const quint8* rawDataConst() const {
return m_rawDataConst;
}
ALWAYS_INLINE const quint8* oldRawData() const {
return m_oldRawData;
}
IteratorTypeSP m_iter;
private:
const quint8 *m_rawDataConst;
const quint8 *m_oldRawData;
};
struct WritableIteratorPolicy {
typedef KisHLineIteratorSP IteratorTypeSP;
WritableIteratorPolicy(KisPaintDeviceSP dev, const QRect &rect) {
m_iter = dev->createHLineIteratorNG(rect.x(), rect.y(), rect.width());
}
ALWAYS_INLINE void updatePointersCache() {
m_rawData = m_iter->rawData();
m_oldRawData = m_iter->oldRawData();
}
ALWAYS_INLINE quint8* rawData() {
return m_rawData;
}
ALWAYS_INLINE const quint8* rawDataConst() const {
return m_rawData;
}
ALWAYS_INLINE const quint8* oldRawData() const {
return m_oldRawData;
}
IteratorTypeSP m_iter;
private:
quint8 *m_rawData;
const quint8 *m_oldRawData;
};
template <class IteratorPolicy>
class KisSequentialIteratorBase
{
public:
KisSequentialIteratorBase(KisPaintDeviceSP dev, const QRect &rect)
: m_policy(dev, rect),
m_pixelSize(dev->pixelSize()),
m_rowsLeft(rect.height() - 1),
m_columnOffset(0)
{
m_columnsLeft = m_numConseqPixels = m_policy.m_iter->nConseqPixels();
m_policy.updatePointersCache();
}
inline bool nextPixel() {
m_columnsLeft--;
if (m_columnsLeft) {
m_columnOffset += m_pixelSize;
return true;
} else {
bool result = m_policy.m_iter->nextPixels(m_numConseqPixels);
if (result) {
m_columnOffset = 0;
m_columnsLeft = m_numConseqPixels = m_policy.m_iter->nConseqPixels();
m_policy.updatePointersCache();
} if (!result && m_rowsLeft > 0) {
m_rowsLeft--;
m_policy.m_iter->nextRow();
m_columnOffset = 0;
m_columnsLeft = m_numConseqPixels = m_policy.m_iter->nConseqPixels();
m_policy.updatePointersCache();
}
}
return m_columnsLeft > 0;
}
// SFINAE: This method becomes undefined for const version of the
// iterator automatically
ALWAYS_INLINE quint8* rawData() {
return m_policy.rawData() + m_columnOffset;
}
ALWAYS_INLINE const quint8* rawDataConst() const {
return m_policy.rawDataConst() + m_columnOffset;
}
ALWAYS_INLINE const quint8* oldRawData() const {
return m_policy.oldRawData() + m_columnOffset;
}
private:
Q_DISABLE_COPY(KisSequentialIteratorBase);
IteratorPolicy m_policy;
const int m_pixelSize;
int m_rowsLeft;
int m_numConseqPixels;
int m_columnsLeft;
int m_columnOffset;
};
typedef KisSequentialIteratorBase<ReadOnlyIteratorPolicy> KisSequentialConstIterator;
typedef KisSequentialIteratorBase<WritableIteratorPolicy> KisSequentialIterator;
#endif /* __KIS_SEQUENTIAL_ITERATOR_H */
......@@ -29,6 +29,7 @@
#include "kis_random_sub_accessor.h"
#include <kis_iterator_ng.h>
#include <kis_repeat_iterators_pixel.h>
#include <kis_sequential_iterator.h>
#include "kis_paint_device.h"
......@@ -71,6 +72,44 @@ void KisIteratorBenchmark::rectIter(const KoColorSpace * colorSpace)
delete[] bytes;
}
void KisIteratorBenchmark::sequentialIter(const KoColorSpace * colorSpace)
{
KisPaintDeviceSP dev = new KisPaintDevice(colorSpace);
quint8 * bytes = new quint8[colorSpace->pixelSize() * 64*64];
memset(bytes, 128, 64 * 64 * colorSpace->pixelSize());
QTime t;
t.start();
for (int i = 0; i < 3; i++) {
KisSequentialIterator it(dev, QRect(0, 0, TEST_WIDTH, TEST_HEIGHT));
do {
memcpy(it.rawData(), bytes, colorSpace->pixelSize());
} while (it.nextPixel());
qDebug() << "SequentialIterator run " << i << "took" << t.elapsed();
t.restart();
}
t.restart();
for (int i = 0; i < 3; i++) {
KisSequentialConstIterator it(dev, QRect(0, 0, TEST_WIDTH, TEST_HEIGHT));
do {
//memcpy(it.rawData(), bytes, colorSpace->pixelSize());
} while (it.nextPixel());
qDebug() << "SequentialConstIterator run " << i << "took" << t.elapsed();
t.restart();
}
delete[] bytes;
}
void KisIteratorBenchmark::hLineIterNG(const KoColorSpace * colorSpace)
{
KisPaintDevice dev(colorSpace);
......@@ -136,7 +175,7 @@ void KisIteratorBenchmark::vLineIterNG(const KoColorSpace * colorSpace)
KisVLineIteratorSP it = dev.createVLineIteratorNG(0, 0, TEST_HEIGHT);
for (int j = 0; j < TEST_WIDTH; j++) {
do {
//memcpy(it->rawData(), bytes, colorSpace->pixelSize());
memcpy(it->rawData(), bytes, colorSpace->pixelSize());
} while(it->nextPixel());
it->nextColumn();
}
......@@ -226,6 +265,7 @@ void KisIteratorBenchmark::runBenchmark()
hLineIterNG(cs);
vLineIterNG(cs);
rectIter(cs);
sequentialIter(cs);
randomAccessor(cs);
}
......
......@@ -31,6 +31,7 @@ private:
void allCsApplicator(void (KisIteratorBenchmark::* funcPtr)(const KoColorSpace*cs));
void vLineIterNG(const KoColorSpace * cs);
void sequentialIter(const KoColorSpace * colorSpace);
void rectIter(const KoColorSpace * cs);
void hLineIterNG(const KoColorSpace * cs);
void randomAccessor(const KoColorSpace * cs);
......
......@@ -31,6 +31,8 @@
#include "kis_paint_device.h"
#include <kis_iterator_ng.h>
#include "kis_sequential_iterator.h"
void KisIteratorTest::allCsApplicator(void (KisIteratorTest::* funcPtr)(const KoColorSpace*cs))
{
......@@ -41,7 +43,6 @@ void KisIteratorTest::allCsApplicator(void (KisIteratorTest::* funcPtr)(const Ko
qDebug() << "Testing with" << cs->id();
if (cs->id() != "GRAYU16") // No point in testing extend for GRAYU16
(this->*funcPtr)(cs);
}
}
......@@ -180,6 +181,90 @@ void KisIteratorTest::rectIter(const KoColorSpace * colorSpace)
delete[] bytes;
}
void KisIteratorTest::sequentialIter(const KoColorSpace * colorSpace)
{
KisPaintDeviceSP dev = new KisPaintDevice(colorSpace);
QCOMPARE(dev->extent(), QRect(qint32_MAX, qint32_MAX, 0, 0));
// Const does not extend the extent
{
KisSequentialConstIterator it(dev, QRect(0, 0, 128, 128));
while (it.nextPixel());
QCOMPARE(dev->extent(), QRect(qint32_MAX, qint32_MAX, 0, 0));
QCOMPARE(dev->exactBounds(), QRect(qint32_MAX, qint32_MAX, 0, 0));
}
// Non-const does
{
KisSequentialIterator it(dev, QRect(0, 0, 128, 128));
int i = -1;
do {
i++;
KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
memcpy(it.rawData(), c.data(), colorSpace->pixelSize());
} while (it.nextPixel());
QCOMPARE(dev->extent(), QRect(0, 0, 128, 128));
QCOMPARE(dev->exactBounds(), QRect(0, 0, 128, 128));
}
{ // check const iterator
KisSequentialConstIterator it(dev, QRect(0, 0, 128, 128));
int i = -1;
do {
i++;
KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
QVERIFY(memcmp(it.rawDataConst(), c.data(), colorSpace->pixelSize()) == 0);
} while (it.nextPixel());
QCOMPARE(dev->extent(), QRect(0, 0, 128, 128));
QCOMPARE(dev->exactBounds(), QRect(0, 0, 128, 128));
}
dev->clear();
{
KisSequentialIterator it(dev, QRect(10, 10, 128, 128));
int i = -1;
do {
i++;
KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
memcpy(it.rawData(), c.data(), colorSpace->pixelSize());
} while (it.nextPixel());
QCOMPARE(dev->extent(), QRect(0, 0, 3 * 64, 3 * 64));
QCOMPARE(dev->exactBounds(), QRect(10, 10, 128, 128));
}
dev->clear();
dev->setX(10);
dev->setY(-15);
{
KisSequentialIterator it(dev, QRect(10, 10, 128, 128));
int i = -1;
do {
i++;
KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
memcpy(it.rawData(), c.data(), colorSpace->pixelSize());
} while (it.nextPixel());
QCOMPARE(dev->extent(), QRect(10, -15, 128, 192));
QCOMPARE(dev->exactBounds(), QRect(10, 10, 128, 128));
}
{
KisSequentialIterator it(dev, QRect(10, 10, 128, 128));
QCOMPARE(it.rawData(), it.oldRawData());
}
}
void KisIteratorTest::hLineIter(const KoColorSpace * colorSpace)
{
KisPaintDevice dev(colorSpace);
......@@ -363,6 +448,11 @@ void KisIteratorTest::rectIter()
allCsApplicator(&KisIteratorTest::rectIter);
}
void KisIteratorTest::sequentialIter()
{
allCsApplicator(&KisIteratorTest::sequentialIter);
}
void KisIteratorTest::hLineIter()
{
allCsApplicator(&KisIteratorTest::hLineIter);
......
......@@ -36,6 +36,7 @@ private:
void writeBytes(const KoColorSpace * cs);
void fill(const KoColorSpace * cs);
void rectIter(const KoColorSpace * cs);
void sequentialIter(const KoColorSpace * colorSpace);
void hLineIter(const KoColorSpace * cs);
void randomAccessor(const KoColorSpace * cs);
......@@ -44,6 +45,7 @@ private slots:
void vLineIter();
void writeBytes();
void fill();
void sequentialIter();
void rectIter();
void hLineIter();
void randomAccessor();
......
......@@ -23,16 +23,8 @@
#include <Vc/IO>
#include <stdint.h>
#include <KoAlwaysInline.h>
#ifndef ALWAYS_INLINE
#if defined __GNUC__
#define ALWAYS_INLINE inline __attribute__((__always_inline__))
#elif defined _MSC_VER
#define ALWAYS_INLINE __forceinline
#else
#define ALWAYS_INLINE inline
#endif
#endif
template<Vc::Implementation _impl>
struct KoStreamedMath {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment