[krita] libs/image: Optimize Fill Layers to not regenerate stuff when not needed

Dmitry Kazakov null at kde.org
Thu Jun 7 09:20:44 UTC 2018


Git commit 56b7bbc9d9f8fc5a2b92b34c9bcb5f349f2f6728 by Dmitry Kazakov.
Committed on 07/06/2018 at 09:20.
Pushed by dkazakov into branch 'master'.

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/56b7bbc9d9f8fc5a2b92b34c9bcb5f349f2f6728

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