koffice/krita/image

Dmitry Kazakov dimula73 at gmail.com
Mon Jun 28 11:41:33 CEST 2010


SVN commit 1143606 by dkazakov:

Added a high-level interface for fastBitBlt.

Now you can use it in you tools, paintops and everywhere! =)

Well, what is it? FastBitBlt is supposed to optimize usage of
temporary paint devices. How did you have to do before:

KisPaintDevice originalDevice;
KisPaintDevice temporaryDevice;

/// ... paint smth on originalDevice...
temporaryDevice.clear();
KisPainter gc(temporaryDevice);
gc.bitBlt(originalDevice, interestRect);
/// ... repeat ...

This was not very efficient, because you had to deep-copy tiles'
data. So from now on, you have a new way of doing things:

KisPaintDevice originalDevice;
KisPaintDevice temporaryDevice;

/// ... paint smth on originalDevice...
temporaryDevice.makeCloneFrom(originalDevice, interestRect);
/// ... repeat ...

This new way has several advantages:
1) It doesn't copy tiles! It shares them.
2) It adjusts x,y shift of temporary device to coinside source
   device's shift
3) It switches colorspace, if needed.
4) It changes default pixel, if needed.

And the most important feature - makeCloneFromRough()!

You can use it in case you are not worried about what is painted
outside interestRect. This function will share a bit bigger area than
was requested in interestRect, but will do it much faster, because
interestRect will be aligned on tiles borders.

So if you are going to read from temporaryDevice withing
interestRect only, use makeCloneFromRough() freely!
CCMAIL:kimageshop at kde.org



 M  +43 -4     kis_paint_device.cc  
 M  +30 -0     kis_paint_device.h  
 M  +35 -0     tests/kis_paint_device_test.cpp  
 M  +1 -0      tests/kis_paint_device_test.h  


--- trunk/koffice/krita/image/kis_paint_device.cc #1143605:1143606
@@ -233,11 +233,12 @@
         }
         m_d->x = rhs.m_d->x;
         m_d->y = rhs.m_d->y;
+
         m_d->colorSpace = KoColorSpaceRegistry::instance()->grabColorSpace(rhs.m_d->colorSpace);
-
         m_d->pixelSize = rhs.m_d->pixelSize;
+        m_d->nChannels = rhs.m_d->nChannels;
 
-        m_d->nChannels = rhs.m_d->nChannels;
+        setDefaultBounds(rhs.defaultBounds());
     }
 }
 
@@ -247,6 +248,44 @@
     delete m_d;
 }
 
+void KisPaintDevice::prepareClone(KisPaintDeviceSP src)
+{
+    clear();
+    m_d->parent = 0;
+    m_d->x = src->x();
+    m_d->y = src->y();
+
+    setDefaultBounds(src->defaultBounds());
+
+    if(!(*colorSpace() == *src->colorSpace())) {
+        KoColorSpaceRegistry::instance()->releaseColorSpace(m_d->colorSpace);
+        m_d->colorSpace = KoColorSpaceRegistry::instance()->grabColorSpace(src->colorSpace());
+        m_d->nChannels = m_d->colorSpace->channelCount();
+
+        if (m_d->pixelSize != m_d->colorSpace->pixelSize()) {
+            m_datamanager = 0;
+            m_datamanager = new KisDataManager(src->pixelSize(), src->defaultPixel());
+            m_d->pixelSize = src->pixelSize();
+        }
+        else {
+            setDefaultPixel(src->defaultPixel());
+        }
+    }
+    Q_ASSERT(fastBitBltPossible(src));
+}
+
+void KisPaintDevice::makeCloneFrom(KisPaintDeviceSP src, const QRect &rect)
+{
+    prepareClone(src);
+    fastBitBlt(src, rect);
+}
+
+void KisPaintDevice::makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
+{
+    prepareClone(src);
+    fastBitBltRough(src, minimalRect);
+}
+
 void KisPaintDevice::setDirty(const QRect & rc)
 {
     m_d->cache.invalidate();
@@ -1023,7 +1062,7 @@
 {
     Q_ASSERT(fastBitBltPossible(src));
 
-    m_datamanager->bitBlt(src->dataManager(), rect);
+    m_datamanager->bitBlt(src->dataManager(), rect.translated(-m_d->x, -m_d->y));
     m_d->cache.invalidate();
 }
 
@@ -1031,7 +1070,7 @@
 {
     Q_ASSERT(fastBitBltPossible(src));
 
-    m_datamanager->bitBltRough(src->dataManager(), rect);
+    m_datamanager->bitBltRough(src->dataManager(), rect.translated(-m_d->x, -m_d->y));
     m_d->cache.invalidate();
 }
 
--- trunk/koffice/krita/image/kis_paint_device.h #1143605:1143606
@@ -221,7 +221,37 @@
     void fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel);
 
 public:
+
     /**
+     * Make this device to become a clone of \a src. It will have the same
+     * x,y shifts, colorspace and will share pixels inside \a rect.
+     * After calling this function:
+     * (this->extent() >= this->exactBounds() == rect).
+     */
+    void makeCloneFrom(KisPaintDeviceSP src, const QRect &rect);
+
+    /**
+     * Make this device to become a clone of \a src. It will have the same
+     * x,y shifts, colorspace and will share pixels inside \a rect.
+     * Be careful, this function will copy *at least* \a rect
+     * of pixels. Actual copy area will be a bigger - it will
+     * be aligned by tiles borders. So after calling this function:
+     * (this->extent() == this->exactBounds() >= rect).
+     */
+    void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect);
+
+
+protected:
+    friend class KisPaintDeviceTest;
+
+    /**
+     * Prepares the device for fastBitBlt opreration. It switches
+     * x,y shifts and colorspace if needed. After this call
+     * fastBitBlt will return true
+     */
+    void prepareClone(KisPaintDeviceSP src);
+
+    /**
      * Checks whether a src paint device can be used as source
      * of fast bitBlt operation. The result of the check may
      * depend on whether color spaces coinside, whether there is
--- trunk/koffice/krita/image/tests/kis_paint_device_test.cpp #1143605:1143606
@@ -314,6 +314,41 @@
     QVERIFY(!dstDev->fastBitBltPossible(srcDev));
 }
 
+void KisPaintDeviceTest::testMakeClone()
+{
+    QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png");
+
+    const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
+    KisPaintDeviceSP srcDev = new KisPaintDevice(cs);
+    srcDev->convertFromQImage(image, "");
+    srcDev->move(10,10);
+
+    const KoColorSpace * weirdCS = KoColorSpaceRegistry::instance()->lab16();
+    KisPaintDeviceSP dstDev = new KisPaintDevice(weirdCS);
+    dstDev->move(1000,1000);
+
+    QVERIFY(!dstDev->fastBitBltPossible(srcDev));
+
+    QRect cloneRect(100,100,200,200);
+    QPoint errpoint;
+
+    dstDev->makeCloneFrom(srcDev, cloneRect);
+
+    QVERIFY(*dstDev->colorSpace() == *srcDev->colorSpace());
+    QCOMPARE(dstDev->pixelSize(), srcDev->pixelSize());
+    QCOMPARE(dstDev->x(), srcDev->x());
+    QCOMPARE(dstDev->y(), srcDev->y());
+    QCOMPARE(dstDev->exactBounds(), cloneRect);
+
+    QImage srcImage = srcDev->convertToQImage(0, cloneRect.x(), cloneRect.y(),
+                                              cloneRect.width(), cloneRect.height());
+    QImage dstImage = dstDev->convertToQImage(0, cloneRect.x(), cloneRect.y(),
+                                              cloneRect.width(), cloneRect.height());
+    if (!TestUtil::compareQImages(errpoint, dstImage, srcImage)) {
+        QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toAscii());
+    }
+}
+
 void KisPaintDeviceTest::testThumbnail()
 {
     QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png");
--- trunk/koffice/krita/image/tests/kis_paint_device_test.h #1143605:1143606
@@ -40,6 +40,7 @@
     void testPlanarReadWrite();
     void testRoundtripConversion();
     void testFastBitBlt();
+    void testMakeClone();
     void testBltPerformance();
     void testColorSpaceConversion();
     void testDeviceDuplication();


More information about the kimageshop mailing list