Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_async_merger.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.0-or-later
4 */
5
6#include "kis_async_merger.h"
7
8
9#include <kis_debug.h>
10
11#include <KoChannelInfo.h>
13
14#include "kis_node_visitor.h"
15#include "kis_painter.h"
16#include "kis_layer.h"
17#include "kis_group_layer.h"
21#include "kis_paint_layer.h"
22#include "filter/kis_filter.h"
25#include "kis_selection.h"
26#include "kis_clone_layer.h"
29
30
31#include "kis_merge_walker.h"
33
35
36
37//#define DEBUG_MERGER
38
39#ifdef DEBUG_MERGER
40#define DEBUG_NODE_ACTION(message, type, leaf, rect) \
41 qDebug() << message << type << ":" << leaf->node()->name() << rect << "rendered:" << leaf->shouldBeRendered()
42#else
43#define DEBUG_NODE_ACTION(message, type, leaf, rect)
44#endif
45
46
48{
49public:
50 KisUpdateOriginalVisitor(const QRect &updateRect, KisPaintDeviceSP projection)
51 : m_updateRect(updateRect),
52 m_projection(projection)
53 {
54 }
55
57 }
58
59public:
61
62 bool visit(KisAdjustmentLayer* layer) override {
63 if (!layer->visible()) return true;
64
65 if (!m_projection) {
66 warnImage << "ObligeChild mechanism has been activated for "
67 "an adjustment layer! Do nothing...";
68 layer->original()->clear();
69 return true;
70 }
71
72 const QRect originalUpdateRect =
73 layer->projectionPlane()->needRectForOriginal(m_updateRect);
74
75 KisPaintDeviceSP originalDevice = layer->original();
76 originalDevice->clear(originalUpdateRect);
77
78 const QRect applyRect = originalUpdateRect & m_projection->extent();
79
80 // If the intersection of the updaterect and the projection extent is
81 // null, we are finish here.
82 if(applyRect.isNull()) return true;
83
84 KisFilterConfigurationSP filterConfig = layer->filter();
85 if (!filterConfig) {
91 KisPainter::copyAreaOptimized(applyRect.topLeft(), m_projection, originalDevice, applyRect);
92 return true;
93 }
94
95 KisSelectionSP selection = layer->fetchComposedInternalSelection(applyRect);
96 const QRect filterRect = selection ? applyRect & selection->selectedRect() : applyRect;
97
98 KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name());
99 if (!filter) return false;
100
101 KisPaintDeviceSP dstDevice = originalDevice;
102
103 if (selection) {
104 dstDevice = new KisPaintDevice(originalDevice->colorSpace());
105 }
106
107 if (!filterRect.isEmpty()) {
109 layer->busyProgressIndicator()->update();
110
111 // We do not create a transaction here, as srcDevice != dstDevice
112 filter->process(m_projection, dstDevice, 0, filterRect, filterConfig.data(), 0);
113 }
114
115 if (selection) {
116 KisPainter::copyAreaOptimized(applyRect.topLeft(), m_projection, originalDevice, applyRect);
117 KisPainter::copyAreaOptimized(filterRect.topLeft(), dstDevice, originalDevice, filterRect, selection);
118 }
119
120 return true;
121 }
122
123 bool visit(KisExternalLayer*) override {
124 return true;
125 }
126
127 bool visit(KisGeneratorLayer*) override {
128 return true;
129 }
130
131 bool visit(KisPaintLayer*) override {
132 return true;
133 }
134
135 bool visit(KisGroupLayer*) override {
136 return true;
137 }
138
139 bool visit(KisCloneLayer*) override {
140 return true;
141 }
142
143 bool visit(KisNode*) override {
144 return true;
145 }
146 bool visit(KisFilterMask*) override {
147 return true;
148 }
149 bool visit(KisTransformMask*) override {
150 return true;
151 }
152 bool visit(KisTransparencyMask*) override {
153 return true;
154 }
155 bool visit(KisSelectionMask*) override {
156 return true;
157 }
158 bool visit(KisColorizeMask*) override {
159 return true;
160 }
161
162private:
165};
166
167
168/*********************************************************************/
169/* KisAsyncMerger */
170/*********************************************************************/
171
172void KisAsyncMerger::startMerge(KisBaseRectsWalker &walker, bool notifyClones) {
173 KisMergeWalker::LeafStack &leafStack = walker.leafStack();
174
175 const bool useTempProjections = walker.needRectVaries();
176
177 while(!leafStack.isEmpty()) {
178 KisMergeWalker::JobItem item = leafStack.pop();
179 KisProjectionLeafSP currentLeaf = item.m_leaf;
180
187 KIS_SAFE_ASSERT_RECOVER_RETURN(currentLeaf->node());
188
189 // All the masks should be filtered by the walkers
190 KIS_SAFE_ASSERT_RECOVER_RETURN(currentLeaf->isLayer());
191
192 QRect applyRect = item.m_applyRect;
193
194 if (currentLeaf->isRoot()) {
195 currentLeaf->projectionPlane()->recalculate(applyRect, walker.startNode(), item.m_renderFlags);
196 continue;
197 }
198
200 // The type of layers that will not go to projection.
201
202 DEBUG_NODE_ACTION("Updating", "N_EXTRA", currentLeaf, applyRect);
203 KisUpdateOriginalVisitor originalVisitor(applyRect,
205 currentLeaf->accept(originalVisitor);
206 currentLeaf->projectionPlane()->recalculate(applyRect, currentLeaf->node(), item.m_renderFlags);
207
208 continue;
209 }
210
211
212 if (!m_currentProjection) {
213 setupProjection(currentLeaf, applyRect, useTempProjections);
214 }
215
216 KisUpdateOriginalVisitor originalVisitor(applyRect,
218
220 DEBUG_NODE_ACTION("Updating", "N_FILTHY", currentLeaf, applyRect);
221 if (currentLeaf->shouldBeRendered()) {
222 currentLeaf->accept(originalVisitor);
223 currentLeaf->projectionPlane()->recalculate(applyRect, walker.startNode(), item.m_renderFlags);
224 }
225 }
227 DEBUG_NODE_ACTION("Updating", "N_ABOVE_FILTHY", currentLeaf, applyRect);
228 if(currentLeaf->dependsOnLowerNodes()) {
229 if (currentLeaf->shouldBeRendered()) {
230 currentLeaf->accept(originalVisitor);
231 currentLeaf->projectionPlane()->recalculate(applyRect, currentLeaf->node(), item.m_renderFlags);
232 }
233 }
234 }
236 DEBUG_NODE_ACTION("Updating", "N_FILTHY_PROJECTION", currentLeaf, applyRect);
237 if (currentLeaf->shouldBeRendered()) {
238 currentLeaf->projectionPlane()->recalculate(applyRect, walker.startNode(), item.m_renderFlags);
239 }
240 }
241 else /*if(item.m_position & KisMergeWalker::N_BELOW_FILTHY)*/ {
242 DEBUG_NODE_ACTION("Updating", "N_BELOW_FILTHY", currentLeaf, applyRect);
243 /* nothing to do */
244 }
245
246 compositeWithProjection(currentLeaf, applyRect);
247
249 writeProjection(currentLeaf, useTempProjections, applyRect);
251 }
252
253 // FIXME: remove it from the inner loop and/or change to a warning!
254 Q_ASSERT(currentLeaf->projection()->defaultBounds()->currentLevelOfDetail() ==
255 walker.levelOfDetail());
256 }
257
258 if(notifyClones) {
259 doNotifyClones(walker);
260 }
261
263 warnImage << "BUG: The walker hasn't reached the root layer!";
264 warnImage << " Start node:" << walker.startNode() << "Requested rect:" << walker.requestedRect();
265 warnImage << " An inconsistency in the walkers occurred!";
266 warnImage << " Please report a bug describing how you got this message.";
267 // reset projection to avoid artifacts in next merges and allow people to work further
269 }
270}
271
276
277void KisAsyncMerger::setupProjection(KisProjectionLeafSP currentLeaf, const QRect& rect, bool useTempProjection) {
278 KisPaintDeviceSP parentOriginal = currentLeaf->parent()->lazyDestinationForSubtreeComposition();
279
280 if (parentOriginal) {
281 if (useTempProjection) {
283 m_cachedPaintDevice = new KisPaintDevice(parentOriginal->colorSpace());
285 m_currentProjection->prepareClone(parentOriginal);
286 m_finalProjection = parentOriginal;
287 }
288 else {
289 parentOriginal->clear(rect);
290 m_finalProjection = m_currentProjection = parentOriginal;
291 }
292 }
293 else {
301 /* NOP */
302 }
303}
304
305void KisAsyncMerger::writeProjection(KisProjectionLeafSP topmostLeaf, bool useTempProjection, const QRect &rect) {
306 Q_UNUSED(useTempProjection);
307 Q_UNUSED(topmostLeaf);
308 if (!m_currentProjection) return;
309
312 }
313 DEBUG_NODE_ACTION("Writing projection", "", topmostLeaf->parent(), rect);
314}
315
317
318 if (!m_currentProjection) return true;
319 if (!leaf->visible()) return true;
320
322 leaf->projectionPlane()->apply(&gc, rect);
323
324 DEBUG_NODE_ACTION("Compositing projection", "", leaf, rect);
325 return true;
326}
327
330 walker.cloneNotifications();
331
332 KisBaseRectsWalker::CloneNotificationsVector::iterator it;
333
334 for(it = vector.begin(); it != vector.end(); ++it) {
335 (*it).notify();
336 }
337}
void doNotifyClones(KisBaseRectsWalker &walker)
KisPaintDeviceSP m_finalProjection
bool compositeWithProjection(KisProjectionLeafSP leaf, const QRect &rect)
void startMerge(KisBaseRectsWalker &walker, bool notifyClones=true)
KisPaintDeviceSP m_currentProjection
void writeProjection(KisProjectionLeafSP topmostLeaf, bool useTempProjection, const QRect &rect)
KisPaintDeviceSP m_cachedPaintDevice
void setupProjection(KisProjectionLeafSP currentLeaf, const QRect &rect, bool useTempProjection)
KisNodeSP startNode() const
CloneNotificationsVector & cloneNotifications()
static KisFilterRegistry * instance()
void process(const KisPaintDeviceSP src, KisPaintDeviceSP dst, KisSelectionSP selection, const QRect &applyRect, const KisFilterConfigurationSP config, KoUpdater *progressUpdater=0) const
Definition kis_filter.cc:41
virtual KisFilterConfigurationSP filter() const
virtual bool visit(KisNode *node)=0
virtual void clear()
QRect extent() const
const KoColorSpace * colorSpace() const
void prepareClone(KisPaintDeviceSP src)
static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
bool visit(KisSelectionMask *) override
bool visit(KisPaintLayer *) override
bool visit(KisExternalLayer *) override
bool visit(KisAdjustmentLayer *layer) override
bool visit(KisGeneratorLayer *) override
bool visit(KisNode *) override
bool visit(KisFilterMask *) override
bool visit(KisGroupLayer *) override
KisUpdateOriginalVisitor(const QRect &updateRect, KisPaintDeviceSP projection)
bool visit(KisTransparencyMask *) override
bool visit(KisTransformMask *) override
bool visit(KisColorizeMask *) override
bool visit(KisCloneLayer *) override
const T value(const QString &id) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define DEBUG_NODE_ACTION(message, type, leaf, rect)
#define warnImage
Definition kis_debug.h:88
virtual bool visible(bool recursive=false) const
KisLayerProjectionPlaneSP projectionPlane
Definition kis_layer.cc:174
KisBusyProgressIndicator * busyProgressIndicator
Definition kis_node.cpp:90
KisSelectionSP fetchComposedInternalSelection(const QRect &rect) const
KisPaintDeviceSP original() const override
QRect selectedRect() const