[calligra/calligra/2.9] krita/image: Make painting below Adjustment Layers up to 10 times faster! :)

Dmitry Kazakov dimula73 at gmail.com
Thu Jun 18 12:12:05 UTC 2015


Git commit 5062bd98936d9e7f5735a892dab9b58051dead05 by Dmitry Kazakov.
Committed on 18/06/2015 at 12:11.
Pushed by dkazakov into branch 'calligra/2.9'.

Make painting below Adjustment Layers up to 10 times faster! :)

We used to spend a lot of time on creation and update of progress
reporters. Now we use a specially factored class KisBusyProgressIndicator
that just shows a progress bar for 200ms and hides it if no further updates
happened. Usage of atomic integers allows us avoid expensive synchronisations
between threads.

So now painting below Adjustment layers is significantly faster!

CC:kimageshop at kde.org

M  +1    -0    krita/image/CMakeLists.txt
M  +5    -10   krita/image/kis_async_merger.cpp
A  +93   -0    krita/image/kis_busy_progress_indicator.cpp     [License: GPL (v2+)]
A  +50   -0    krita/image/kis_busy_progress_indicator.h     [License: GPL (v2+)]
M  +20   -1    krita/image/kis_node.cpp
M  +3    -0    krita/image/kis_node.h
M  +2    -0    krita/image/kis_node_progress_proxy.cpp

http://commits.kde.org/calligra/5062bd98936d9e7f5735a892dab9b58051dead05

diff --git a/krita/image/CMakeLists.txt b/krita/image/CMakeLists.txt
index 2ce5684..9e49f63 100644
--- a/krita/image/CMakeLists.txt
+++ b/krita/image/CMakeLists.txt
@@ -197,6 +197,7 @@ set(kritaimage_LIB_SRCS
    kis_node.cpp
    kis_node_facade.cpp
    kis_node_progress_proxy.cpp
+   kis_busy_progress_indicator.cpp
    kis_node_visitor.cpp
    kis_paint_device.cc
    kis_fixed_paint_device.cpp
diff --git a/krita/image/kis_async_merger.cpp b/krita/image/kis_async_merger.cpp
index 8c92fcf..bf142bc 100644
--- a/krita/image/kis_async_merger.cpp
+++ b/krita/image/kis_async_merger.cpp
@@ -42,7 +42,7 @@
 #include "kis_selection.h"
 #include "kis_clone_layer.h"
 #include "kis_processing_information.h"
-#include "kis_node_progress_proxy.h"
+#include "kis_busy_progress_indicator.h"
 
 
 #include "kis_merge_walker.h"
@@ -113,12 +113,6 @@ public:
         KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name());
         if (!filter) return false;
 
-        Q_ASSERT(layer->nodeProgressProxy());
-
-        KoProgressUpdater updater(layer->nodeProgressProxy());
-        updater.start(100, filter->name());
-        QPointer<KoUpdater> updaterPtr = updater.startSubtask();
-
         KisPaintDeviceSP dstDevice = originalDevice;
 
         if (selection) {
@@ -126,8 +120,11 @@ public:
         }
 
         if (!filterRect.isEmpty()) {
+            KIS_ASSERT_RECOVER_NOOP(layer->busyProgressIndicator());
+            layer->busyProgressIndicator()->update();
+
             // We do not create a transaction here, as srcDevice != dstDevice
-            filter->process(m_projection, dstDevice, 0, filterRect, filterConfig.data(), updaterPtr);
+            filter->process(m_projection, dstDevice, 0, filterRect, filterConfig.data(), 0);
         }
 
         if (selection) {
@@ -135,8 +132,6 @@ public:
             KisPainter::copyAreaOptimized(filterRect.topLeft(), dstDevice, originalDevice, filterRect, selection);
         }
 
-        updaterPtr->setProgress(100);
-
         return true;
     }
 
diff --git a/krita/image/kis_busy_progress_indicator.cpp b/krita/image/kis_busy_progress_indicator.cpp
new file mode 100644
index 0000000..d1d5e56
--- /dev/null
+++ b/krita/image/kis_busy_progress_indicator.cpp
@@ -0,0 +1,93 @@
+/*
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73 at 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.
+ */
+
+#include "kis_busy_progress_indicator.h"
+
+#include <QTimer>
+#include <QAtomicInt>
+
+#include "KoProgressProxy.h"
+
+
+struct KisBusyProgressIndicator::Private
+{
+    Private() : numEmptyTicks(0) {}
+
+    QTimer timer;
+    int numEmptyTicks;
+    QAtomicInt numUpdates;
+    QAtomicInt timerStarted;
+    KoProgressProxy *progressProxy;
+
+    void startProgressReport() {
+        progressProxy->setRange(0, 0);
+    }
+
+    void stopProgressReport() {
+        progressProxy->setRange(0, 100);
+        progressProxy->setValue(100);
+    }
+};
+
+
+KisBusyProgressIndicator::KisBusyProgressIndicator(KoProgressProxy *progressProxy)
+    : m_d(new Private)
+{
+    connect(&m_d->timer, SIGNAL(timeout()), SLOT(timerFinished()));
+    connect(this, SIGNAL(sigStartTimer()), SLOT(slotStartTimer()));
+    m_d->timer.setInterval(200);
+    m_d->progressProxy = progressProxy;
+}
+
+KisBusyProgressIndicator::~KisBusyProgressIndicator()
+{
+    m_d->stopProgressReport();
+}
+
+void KisBusyProgressIndicator::timerFinished()
+{
+    int value = m_d->numUpdates.fetchAndStoreOrdered(0);
+
+    if (!value) {
+        m_d->numEmptyTicks++;
+
+        if (m_d->numEmptyTicks > 2) {
+            m_d->timerStarted = 0;
+            m_d->timer.stop();
+            m_d->stopProgressReport();
+        }
+    } else {
+        m_d->numEmptyTicks = 0;
+    }
+}
+
+void KisBusyProgressIndicator::update()
+{
+    m_d->numUpdates.ref();
+
+    if (!m_d->timerStarted) {
+        emit sigStartTimer();
+    }
+}
+
+void KisBusyProgressIndicator::slotStartTimer()
+{
+    m_d->timerStarted.ref();
+    m_d->timer.start();
+    m_d->startProgressReport();
+}
diff --git a/krita/image/kis_busy_progress_indicator.h b/krita/image/kis_busy_progress_indicator.h
new file mode 100644
index 0000000..8a390bb
--- /dev/null
+++ b/krita/image/kis_busy_progress_indicator.h
@@ -0,0 +1,50 @@
+/*
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73 at 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_BUSY_PROGRESS_INDICATOR_H
+#define __KIS_BUSY_PROGRESS_INDICATOR_H
+
+#include <QObject>
+#include <QScopedPointer>
+
+class KoProgressProxy;
+
+
+class KisBusyProgressIndicator : public QObject
+{
+    Q_OBJECT
+public:
+    KisBusyProgressIndicator(KoProgressProxy *progressProxy);
+    ~KisBusyProgressIndicator();
+
+public Q_SLOTS:
+    void update();
+
+private Q_SLOTS:
+    void slotStartTimer();
+    void timerFinished();
+
+Q_SIGNALS:
+    void sigStartTimer();
+
+private:
+    struct Private;
+    const QScopedPointer<Private> m_d;
+};
+
+#endif /* __KIS_BUSY_PROGRESS_INDICATOR_H */
diff --git a/krita/image/kis_node.cpp b/krita/image/kis_node.cpp
index 4966c95..3b8076b 100644
--- a/krita/image/kis_node.cpp
+++ b/krita/image/kis_node.cpp
@@ -32,6 +32,7 @@
 #include "kis_node_visitor.h"
 #include "kis_processing_visitor.h"
 #include "kis_node_progress_proxy.h"
+#include "kis_busy_progress_indicator.h"
 
 #include "kis_clone_layer.h"
 
@@ -81,6 +82,7 @@ public:
     Private(KisNode *node)
             : graphListener(0)
             , nodeProgressProxy(0)
+            , busyProgressIndicator(0)
             , projectionLeaf(new KisProjectionLeaf(node))
     {
     }
@@ -89,6 +91,7 @@ public:
     KisNodeGraphListener *graphListener;
     KisSafeReadNodeList nodes;
     KisNodeProgressProxy *nodeProgressProxy;
+    KisBusyProgressIndicator *busyProgressIndicator;
     QReadWriteLock nodeSubgraphLock;
 
 
@@ -193,8 +196,13 @@ KisNode::KisNode(const KisNode & rhs)
 
 KisNode::~KisNode()
 {
-    if (m_d->nodeProgressProxy)
+    if (m_d->busyProgressIndicator) {
+        m_d->busyProgressIndicator->deleteLater();
+    }
+
+    if (m_d->nodeProgressProxy) {
         m_d->nodeProgressProxy->deleteLater();
+    }
 
     {
         QWriteLocker l(&m_d->nodeSubgraphLock);
@@ -494,10 +502,21 @@ KisNodeProgressProxy* KisNode::nodeProgressProxy() const
     return 0;
 }
 
+KisBusyProgressIndicator* KisNode::busyProgressIndicator() const
+{
+    if (m_d->busyProgressIndicator) {
+        return m_d->busyProgressIndicator;
+    } else if (parent()) {
+        return parent()->busyProgressIndicator();
+    }
+    return 0;
+}
+
 void KisNode::createNodeProgressProxy()
 {
     if (!m_d->nodeProgressProxy) {
         m_d->nodeProgressProxy = new KisNodeProgressProxy(this);
+        m_d->busyProgressIndicator = new KisBusyProgressIndicator(m_d->nodeProgressProxy);
     }
 }
 
diff --git a/krita/image/kis_node.h b/krita/image/kis_node.h
index bf8c233..f51211e 100644
--- a/krita/image/kis_node.h
+++ b/krita/image/kis_node.h
@@ -35,6 +35,7 @@ class KoProperties;
 class KisNodeVisitor;
 class KisNodeGraphListener;
 class KisNodeProgressProxy;
+class KisBusyProgressIndicator;
 class KisAbstractProjectionPlane;
 class KisProjectionLeaf;
 
@@ -298,6 +299,8 @@ public:
      */
     KisNodeProgressProxy* nodeProgressProxy() const;
 
+    KisBusyProgressIndicator* busyProgressIndicator() const;
+
 private:
 
     /**
diff --git a/krita/image/kis_node_progress_proxy.cpp b/krita/image/kis_node_progress_proxy.cpp
index 2915459..f4fab64 100644
--- a/krita/image/kis_node_progress_proxy.cpp
+++ b/krita/image/kis_node_progress_proxy.cpp
@@ -34,6 +34,8 @@ struct KisNodeProgressProxy::Private {
         int old_percentage = percentage;
         if (value == maximum) {
             percentage = -1;
+        } else if (minimum == maximum && minimum == 0) {
+            percentage = 0;
         } else {
             percentage = (100 * (value - minimum)) / (maximum - minimum);
             percentage = qBound(0, percentage, 100);



More information about the kimageshop mailing list