[krita] libs/image: Implement exactBoundsAmortized() method for paint devices

Dmitry Kazakov dimula73 at gmail.com
Fri Apr 22 09:50:02 UTC 2016


Git commit eeb0a5b91c1bcfa961b1fee7cf57560e998f9e51 by Dmitry Kazakov.
Committed on 22/04/2016 at 09:48.
Pushed by dkazakov into branch 'master'.

Implement exactBoundsAmortized() method for paint devices

This method is supposed to be used in hot-spot places
where exactBounds() is desirable, but extensive calculations
may affect the performace. It returns exactBounds() of the
device, but limits expensive exact bounds recalculations
(if needed) to happen not more often than once a second.
If the cache is dirty and we recalculated it too recently,
exactBoundsAmortized() will return extent() of the paint
device, which is perfectly fine in a lot of cases.

It allows using exactBoundsAmortized() in the projection
merging code, where this method can be called for the
device being painted at the moment, which exact bounds
changes constantly.

CC:kimageshop at kde.org

M  +17   -0    libs/image/kis_lock_free_cache.h
M  +5    -0    libs/image/kis_paint_device.cc
M  +9    -0    libs/image/kis_paint_device.h
M  +22   -0    libs/image/kis_paint_device_cache.h
M  +28   -0    libs/image/tests/kis_paint_device_test.cpp
M  +1    -0    libs/image/tests/kis_paint_device_test.h

http://commits.kde.org/krita/eeb0a5b91c1bcfa961b1fee7cf57560e998f9e51

diff --git a/libs/image/kis_lock_free_cache.h b/libs/image/kis_lock_free_cache.h
index 4ceb328..b0a3904 100644
--- a/libs/image/kis_lock_free_cache.h
+++ b/libs/image/kis_lock_free_cache.h
@@ -148,6 +148,23 @@ public:
         }
     }
 
+    bool tryGetValue(T &result) const {
+        KisCacheStateValue::SeqValue seqValue;
+        bool isValid = false;
+        T newValue;
+
+        if (m_state.startRead(&seqValue)) {
+            newValue = m_value;
+            isValid = m_state.endRead(seqValue);
+        }
+
+        if (isValid) {
+            result = newValue;
+        }
+
+        return isValid;
+    }
+
 protected:
     /**
      * Calculate the value. Used by the cache
diff --git a/libs/image/kis_paint_device.cc b/libs/image/kis_paint_device.cc
index 7661e3e..cc241a0 100644
--- a/libs/image/kis_paint_device.cc
+++ b/libs/image/kis_paint_device.cc
@@ -1030,6 +1030,11 @@ QRect KisPaintDevice::exactBounds() const
     return m_d->cache()->exactBounds();
 }
 
+QRect KisPaintDevice::exactBoundsAmortized() const
+{
+    return m_d->cache()->exactBoundsAmortized();
+}
+
 namespace Impl {
 
 struct CheckFullyTransparent
diff --git a/libs/image/kis_paint_device.h b/libs/image/kis_paint_device.h
index eb180b5..738df2f 100644
--- a/libs/image/kis_paint_device.h
+++ b/libs/image/kis_paint_device.h
@@ -208,6 +208,15 @@ public:
     QRect exactBounds() const;
 
     /**
+     * Relaxed version of the exactBounds() that can be used in tight
+     * loops.  If the exact bounds value is present in the paint
+     * device cache, returns this value.  If the cache is invalidated,
+     * returns extent() and tries to recalculate the exact bounds not
+     * faster than once in 1000 ms.
+     */
+    QRect exactBoundsAmortized() const;
+
+    /**
      * Retuns exact rectangle of the paint device that contains
      * non-default pixels. For paint devices with fully transparent
      * default pixel is equivalent to exactBounds().
diff --git a/libs/image/kis_paint_device_cache.h b/libs/image/kis_paint_device_cache.h
index 1986818..f72370f 100644
--- a/libs/image/kis_paint_device_cache.h
+++ b/libs/image/kis_paint_device_cache.h
@@ -20,6 +20,7 @@
 #define __KIS_PAINT_DEVICE_CACHE_H
 
 #include "kis_lock_free_cache.h"
+#include <QElapsedTimer>
 
 
 class KisPaintDeviceCache
@@ -56,6 +57,26 @@ public:
         return m_exactBoundsCache.getValue();
     }
 
+    QRect exactBoundsAmortized() {
+        QRect bounds;
+        bool result = m_exactBoundsCache.tryGetValue(bounds);
+
+        const int msecThreshold = 1000;
+
+        if (!result) {
+            if (!m_lastCalculatedExactBounds.isValid() ||
+                m_lastCalculatedExactBounds.elapsed() > msecThreshold) {
+
+                m_lastCalculatedExactBounds.restart();
+                bounds = exactBounds();
+            } else {
+                bounds = m_paintDevice->extent();
+            }
+        }
+
+        return bounds;
+    }
+
     QRect nonDefaultPixelArea() {
         return m_nonDefaultPixelAreaCache.getValue();
     }
@@ -133,6 +154,7 @@ private:
     ExactBoundsCache m_exactBoundsCache;
     NonDefaultPixelCache m_nonDefaultPixelAreaCache;
     RegionCache m_regionCache;
+    QElapsedTimer m_lastCalculatedExactBounds;
 
     bool m_thumbnailsValid;
     QMap<int, QMap<int, QImage> > m_thumbnails;
diff --git a/libs/image/tests/kis_paint_device_test.cpp b/libs/image/tests/kis_paint_device_test.cpp
index 1818506..f825d8c 100644
--- a/libs/image/tests/kis_paint_device_test.cpp
+++ b/libs/image/tests/kis_paint_device_test.cpp
@@ -722,6 +722,34 @@ void KisPaintDeviceTest::benchmarkExactBoundsNullDefaultPixel()
     QCOMPARE(measuredRect, fillRect);
 }
 
+void KisPaintDeviceTest::testAmortizedExactBounds()
+{
+    const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
+    KisPaintDeviceSP dev = new KisPaintDevice(cs);
+
+    QVERIFY(dev->exactBounds().isEmpty());
+
+    QRect fillRect(60,60, 833, 833);
+    QRect extent(0,0,896,896);
+
+    dev->fill(fillRect, KoColor(Qt::white, cs));
+
+    QCOMPARE(dev->exactBounds(), fillRect);
+    QCOMPARE(dev->extent(), extent);
+
+    QCOMPARE(dev->exactBoundsAmortized(), fillRect);
+
+    dev->setDirty();
+    QCOMPARE(dev->exactBoundsAmortized(), fillRect);
+
+    dev->setDirty();
+    QCOMPARE(dev->exactBoundsAmortized(), extent);
+
+    QTest::qSleep(1100);
+
+    QCOMPARE(dev->exactBoundsAmortized(), fillRect);
+}
+
 void KisPaintDeviceTest::testNonDefaultPixelArea()
 {
     const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
diff --git a/libs/image/tests/kis_paint_device_test.h b/libs/image/tests/kis_paint_device_test.h
index 11e039a..ae4b89c 100644
--- a/libs/image/tests/kis_paint_device_test.h
+++ b/libs/image/tests/kis_paint_device_test.h
@@ -49,6 +49,7 @@ private Q_SLOTS:
     void testOpacity();
     void testExactBoundsWeirdNullAlphaCase();
     void benchmarkExactBoundsNullDefaultPixel();
+    void testAmortizedExactBounds();
     void testNonDefaultPixelArea();
     void testExactBoundsNonTransparent();
 



More information about the kimageshop mailing list