Commit 4319cea3 authored by Dmitry Kazakov's avatar Dmitry Kazakov

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@kde.org
parent 24308ed8
......@@ -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
......
......@@ -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;
}
......
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@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();
}
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@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 */
......@@ -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);
}
}
......
......@@ -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:
/**
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment