Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_update_job_item.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#ifndef __KIS_UPDATE_JOB_ITEM_H
8#define __KIS_UPDATE_JOB_ITEM_H
9
10#include <atomic>
11
12#include <QRunnable>
13#include <QReadWriteLock>
14
15#include "kis_stroke_job.h"
16#include "kis_spontaneous_job.h"
18#include "kis_async_merger.h"
19#include "kis_updater_context.h"
20#include <KoAlwaysInline.h>
21
22//#define DEBUG_JOBS_SEQUENCE
23
24class KRITAIMAGE_EXPORT KisUpdateJobItem : public QObject, public QRunnable
25{
26 Q_OBJECT
27public:
28 enum class Type : int {
29 EMPTY = 0,
30 WAITING,
31 MERGE,
32 STROKE,
33 SPONTANEOUS
34 };
35
36public:
38 : m_updaterContext(updaterContext)
39 {
40 setAutoDelete(false);
41 KIS_SAFE_ASSERT_RECOVER_NOOP(m_atomicType.is_lock_free());
42 }
44 {
45 delete m_runnableJob;
46 }
47
48 void run() override {
49 runImpl();
50
51 // notify that the job is exiting and wake everybody
52 // waiting on wakeForDone()
53 m_updaterContext->jobThreadExited();
54 }
55
56private:
57
59 if (!isRunning()) return;
60
74 while (1) {
76
77 if(m_exclusive) {
78 m_updaterContext->m_exclusiveJobLock.lockForWrite();
79 } else {
80 m_updaterContext->m_exclusiveJobLock.lockForRead();
81 }
82
83 if(m_atomicType == Type::MERGE) {
84 runMergeJob();
85 } else {
86 KIS_ASSERT(m_atomicType == Type::STROKE ||
87 m_atomicType == Type::SPONTANEOUS);
88
89 if (m_runnableJob) {
90#ifdef DEBUG_JOBS_SEQUENCE
91 if (m_atomicType == Type::STROKE) {
92 qDebug() << "running: stroke" << m_runnableJob->debugName();
93 } else if (m_atomicType == Type::SPONTANEOUS) {
94 qDebug() << "running: spont " << m_runnableJob->debugName();
95 } else {
96 qDebug() << "running: unkn. " << m_runnableJob->debugName();
97 }
98#endif
99
100 m_runnableJob->run();
101 }
102 }
103
104 setDone();
105
106 m_updaterContext->doSomeUsefulWork();
107
108 // may flip the current state from Waiting -> Running again
109 m_updaterContext->jobFinished();
110
111 m_updaterContext->m_exclusiveJobLock.unlock();
112
113 // try to exit the loop. Please note, that no one can flip the state from
114 // WAITING to EMPTY except ourselves!
115 Type expectedValue = Type::WAITING;
116 if (m_atomicType.compare_exchange_strong(expectedValue, Type::EMPTY)) {
117 break;
118 }
119 }
120 }
121
122public:
123
124 inline void runMergeJob() {
125 KIS_SAFE_ASSERT_RECOVER_RETURN(m_atomicType == Type::MERGE);
127 // dbgKrita << "Executing merge job" << m_walker->changeRect()
128 // << "on thread" << QThread::currentThreadId();
129
130#ifdef DEBUG_JOBS_SEQUENCE
131 qDebug() << "running: merge " << m_walker->startNode() << m_walker->changeRect();
132
133#endif
134
135 m_merger.startMerge(*m_walker);
136
137 QRect changeRect = m_walker->changeRect();
138 m_updaterContext->continueUpdate(changeRect);
139 }
140
141 // return true if the thread should actually be started
142 inline bool setWalker(KisBaseRectsWalkerSP walker) {
143 KIS_ASSERT(m_atomicType <= Type::WAITING);
144
145 m_accessRect = walker->accessRect();
146 m_changeRect = walker->changeRect();
147 m_walker = walker;
148
149 m_exclusive = false;
150 m_runnableJob = 0;
151
152 const Type oldState = m_atomicType.exchange(Type::MERGE);
153 return oldState == Type::EMPTY;
154 }
155
156 // return true if the thread should actually be started
157 inline bool setStrokeJob(KisStrokeJob *strokeJob) {
158 KIS_ASSERT(m_atomicType <= Type::WAITING);
159
160 m_runnableJob = strokeJob;
161 m_strokeJobSequentiality = strokeJob->sequentiality();
162
163 m_exclusive = strokeJob->isExclusive();
164 m_walker = 0;
165 m_accessRect = m_changeRect = QRect();
166
167 const Type oldState = m_atomicType.exchange(Type::STROKE);
168 return oldState == Type::EMPTY;
169 }
170
171 // return true if the thread should actually be started
172 inline bool setSpontaneousJob(KisSpontaneousJob *spontaneousJob) {
173 KIS_ASSERT(m_atomicType <= Type::WAITING);
174
175 m_runnableJob = spontaneousJob;
176
177 m_exclusive = spontaneousJob->isExclusive();
178 m_walker = 0;
179 m_accessRect = m_changeRect = QRect();
180
181 const Type oldState = m_atomicType.exchange(Type::SPONTANEOUS);
182 return oldState == Type::EMPTY;
183 }
184
185 inline void setDone() {
186 m_walker = 0;
187 delete m_runnableJob;
188 m_runnableJob = 0;
189 m_atomicType = Type::WAITING;
190 }
191
192 inline bool isRunning() const {
193 return m_atomicType >= Type::MERGE;
194 }
195
196 inline Type type() const {
197 return m_atomicType;
198 }
199
200 inline const QRect& accessRect() const {
201 return m_accessRect;
202 }
203
204 inline const QRect& changeRect() const {
205 return m_changeRect;
206 }
207
209 return m_strokeJobSequentiality;
210 }
211
212private:
218 friend class KisSimpleUpdateQueueTest;
219 friend class KisStrokesQueueTest;
220 friend class KisUpdateSchedulerTest;
221 friend class KisUpdaterContext;
222
224 return m_walker;
225 }
226
227 inline KisStrokeJob* strokeJob() const {
228 KisStrokeJob *job = dynamic_cast<KisStrokeJob*>(m_runnableJob);
229 Q_ASSERT(job);
230
231 return job;
232 }
233
234 inline void testingSetDone() {
235 setDone();
236 }
237
238private:
239 KisUpdaterContext *m_updaterContext {0};
240 bool m_exclusive {false};
241 std::atomic<Type> m_atomicType {Type::EMPTY};
243
248 KisRunnableWithDebugName *m_runnableJob {0};
249
255
262};
263
264
265#endif /* __KIS_UPDATE_JOB_ITEM_H */
#define ALWAYS_INLINE
bool isExclusive() const
KisStrokeJobData::Sequentiality sequentiality() const
const QRect & accessRect() const
void run() override
KisStrokeJob * strokeJob() const
KisAsyncMerger m_merger
KisUpdateJobItem(KisUpdaterContext *updaterContext)
const QRect & changeRect() const
bool setWalker(KisBaseRectsWalkerSP walker)
KisStrokeJobData::Sequentiality strokeJobSequentiality() const
bool setStrokeJob(KisStrokeJob *strokeJob)
ALWAYS_INLINE void runImpl()
bool setSpontaneousJob(KisSpontaneousJob *spontaneousJob)
KisBaseRectsWalkerSP m_walker
KisBaseRectsWalkerSP walker() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define KIS_ASSERT(cond)
Definition kis_assert.h:33