[krita/akamakin/T8628-multithreading-optimization] libs/image: Optimize Fill Layers to not regenerate stuff when not needed

Andrey Kamakin null at kde.org
Tue Jun 26 15:02:15 UTC 2018


Git commit 2e998dfb7429b13bff4a58e4c57e573053e02ae3 by Andrey Kamakin, on behalf of Dmitry Kazakov.
Committed on 26/06/2018 at 14:18.
Pushed by akamakin into branch 'akamakin/T8628-multithreading-optimization'.

Optimize Fill Layers to not regenerate stuff when not needed

With this patch one can use Fill Layer as an overlay for
colored draft lines. Painting works almost at the same speed
as painting on a normal layer.

Such usecase was suggested by David Revoy at Krita Sprint 2018

To Deevad: it would be nice to have a short video about that :)

CC:kimageshop at kde.org

M  +35   -12   libs/image/generator/kis_generator_layer.cpp
M  +2    -0    libs/image/generator/kis_generator_layer.h
M  +1    -1    libs/image/kis_selection_based_layer.h

https://commits.kde.org/krita/2e998dfb7429b13bff4a58e4c57e573053e02ae3

diff --git a/libs/image/generator/kis_generator_layer.cpp b/libs/image/generator/kis_generator_layer.cpp
index bd8a3bc2cd2..a83515c8854 100644
--- a/libs/image/generator/kis_generator_layer.cpp
+++ b/libs/image/generator/kis_generator_layer.cpp
@@ -44,6 +44,8 @@ struct Q_DECL_HIDDEN KisGeneratorLayer::Private
     }
 
     KisThreadSafeSignalCompressor updateSignalCompressor;
+    QRect preparedRect;
+    KisFilterConfigurationSP preparedForFilter;
 };
 
 
@@ -72,6 +74,7 @@ KisGeneratorLayer::~KisGeneratorLayer()
 void KisGeneratorLayer::setFilter(KisFilterConfigurationSP filterConfig)
 {
     KisSelectionBasedLayer::setFilter(filterConfig);
+    m_d->preparedRect = QRect();
     update();
 }
 
@@ -93,32 +96,43 @@ void KisGeneratorLayer::slotDelayedStaticUpdate()
 
 void KisGeneratorLayer::update()
 {
+    KisImageSP image = this->image().toStrongRef();
+    const QRect updateRect = extent() | image->bounds();
+
     KisFilterConfigurationSP filterConfig = filter();
+    KIS_SAFE_ASSERT_RECOVER_RETURN(filterConfig);
 
-    if (!filterConfig) {
-        warnImage << "BUG: No Filter configuration in KisGeneratorLayer";
-        return;
+    if (filterConfig != m_d->preparedForFilter) {
+        resetCache();
     }
 
+    const QRegion processRegion(QRegion(updateRect) - m_d->preparedRect);
+    if (processRegion.isEmpty()) return;
+
     KisGeneratorSP f = KisGeneratorRegistry::instance()->value(filterConfig->name());
-    if (!f) return;
+    KIS_SAFE_ASSERT_RECOVER_RETURN(f);
 
-    QRect processRect = exactBounds();
+    KisPaintDeviceSP originalDevice = original();
 
-    resetCache();
+    QVector<QRect> dirtyRegion;
 
-    KisPaintDeviceSP originalDevice = original();
+    Q_FOREACH (const QRect &rc, processRegion) {
+        KisProcessingInformation dstCfg(originalDevice,
+                                        rc.topLeft(),
+                                        KisSelectionSP());
+
+        f->generate(dstCfg, rc.size(), filterConfig.data());
 
-    KisProcessingInformation dstCfg(originalDevice,
-                                    processRect.topLeft(),
-                                    KisSelectionSP());
+        dirtyRegion << rc;
 
-    f->generate(dstCfg, processRect.size(), filterConfig.data());
+    }
 
+    m_d->preparedRect = updateRect;
+    m_d->preparedForFilter = filterConfig;
 
     // HACK ALERT!!!
     // this avoids cyclic loop with KisRecalculateGeneratorLayerJob::run()
-    KisSelectionBasedLayer::setDirty(QVector<QRect>() << extent());
+    KisSelectionBasedLayer::setDirty(dirtyRegion);
 }
 
 bool KisGeneratorLayer::accept(KisNodeVisitor & v)
@@ -150,12 +164,21 @@ KisBaseNode::PropertyList KisGeneratorLayer::sectionModelProperties() const
 void KisGeneratorLayer::setX(qint32 x)
 {
     KisSelectionBasedLayer::setX(x);
+    m_d->preparedRect = QRect();
     m_d->updateSignalCompressor.start();
 }
 
 void KisGeneratorLayer::setY(qint32 y)
 {
     KisSelectionBasedLayer::setY(y);
+    m_d->preparedRect = QRect();
+    m_d->updateSignalCompressor.start();
+}
+
+void KisGeneratorLayer::resetCache()
+{
+    KisSelectionBasedLayer::resetCache();
+    m_d->preparedRect = QRect();
     m_d->updateSignalCompressor.start();
 }
 
diff --git a/libs/image/generator/kis_generator_layer.h b/libs/image/generator/kis_generator_layer.h
index 757b464d52b..a0ed0545d82 100644
--- a/libs/image/generator/kis_generator_layer.h
+++ b/libs/image/generator/kis_generator_layer.h
@@ -72,6 +72,8 @@ public:
     void setX(qint32 x) override;
     void setY(qint32 y) override;
 
+    void resetCache() override;
+
 private Q_SLOTS:
     void slotDelayedStaticUpdate();
 
diff --git a/libs/image/kis_selection_based_layer.h b/libs/image/kis_selection_based_layer.h
index aa8a9448d9c..cc57a750747 100644
--- a/libs/image/kis_selection_based_layer.h
+++ b/libs/image/kis_selection_based_layer.h
@@ -73,7 +73,7 @@ public:
      * resets cached projection of lower layer to a new device
      * @return void
      */
-    void resetCache();
+    virtual void resetCache();
 
     /**
      * for KisLayer::setDirty(const QRegion&)



More information about the kimageshop mailing list