Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_updater_context.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QThread>
10#include <QThreadPool>
11#include <QMutexLocker>
12
13#include "kis_update_job_item.h"
14#include "kis_stroke_job.h"
15
17
19 : m_scheduler(parent)
20{
21 if(threadCount <= 0) {
22 threadCount = QThread::idealThreadCount();
23 threadCount = threadCount > 0 ? threadCount : 1;
24 }
25
26 setThreadsLimit(threadCount);
27}
28
30{
31 m_threadPool.waitForDone();
32
33 if (m_testingMode) {
34 clear();
35 }
36
37 qDeleteAll(m_jobs);
38}
39
40void KisUpdaterContext::getJobsSnapshot(qint32 &numMergeJobs,
41 qint32 &numStrokeJobs)
42{
43 numMergeJobs = 0;
44 numStrokeJobs = 0;
45
52 for (const KisUpdateJobItem *item : std::as_const(m_jobs)) {
53
54 if(item->type() == KisUpdateJobItem::Type::MERGE ||
56 numMergeJobs++;
57 }
58 else if(item->type() == KisUpdateJobItem::Type::STROKE) {
59 numStrokeJobs++;
60 }
61 }
62}
63
64KisUpdaterContextSnapshotEx KisUpdaterContext::getContextSnapshotEx() const
65{
66 KisUpdaterContextSnapshotEx state = ContextEmpty;
67
74 for (const KisUpdateJobItem *item : std::as_const(m_jobs)) {
75 if (item->type() == KisUpdateJobItem::Type::MERGE ||
77 state |= HasMergeJob;
78 } else if(item->type() == KisUpdateJobItem::Type::STROKE) {
79 switch (item->strokeJobSequentiality()) {
81 state |= HasSequentialJob;
82 break;
84 state |= HasConcurrentJob;
85 break;
87 state |= HasBarrierJob;
88 break;
91 break;
92 }
93 }
94 }
95
96 return state;
97}
98
103
105{
106 bool found = false;
107
114 for (const KisUpdateJobItem *item : std::as_const(m_jobs)) {
115 if(!item->isRunning()) {
116 found = true;
117 break;
118 }
119 }
120 return found;
121}
122
124{
125 int lod = this->currentLevelOfDetail();
126 if (lod >= 0 && walker->levelOfDetail() != lod) return false;
127
128 bool intersects = false;
129
136 for (const KisUpdateJobItem *item : std::as_const(m_jobs)) {
137 if(item->isRunning() && walkerIntersectsJob(walker, item)) {
138 intersects = true;
139 break;
140 }
141 }
142
143 return !intersects;
144}
145
147{
148 {
149 QMutexLocker l(&m_runningThreadsMutex);
151 }
152
153 m_threadPool.start(m_jobs[index]);
154}
155
165{
167 qint32 jobIndex = findSpareThread();
168 Q_ASSERT(jobIndex >= 0);
169
170 const bool shouldStartThread = m_jobs[jobIndex]->setWalker(walker);
171
172 // it might happen that we call this function from within
173 // the thread itself, right when it finished its work
174 if (shouldStartThread && !m_testingMode) {
175 startThread(jobIndex);
176 }
177}
178
180{
181 m_lodCounter.addLod(strokeJob->levelOfDetail());
182 qint32 jobIndex = findSpareThread();
183 Q_ASSERT(jobIndex >= 0);
184
185 const bool shouldStartThread = m_jobs[jobIndex]->setStrokeJob(strokeJob);
186
187 // it might happen that we call this function from within
188 // the thread itself, right when it finished its work
189 if (shouldStartThread && !m_testingMode) {
190 startThread(jobIndex);
191 }
192}
193
195{
196 m_lodCounter.addLod(spontaneousJob->levelOfDetail());
197 qint32 jobIndex = findSpareThread();
198 Q_ASSERT(jobIndex >= 0);
199
200 const bool shouldStartThread = m_jobs[jobIndex]->setSpontaneousJob(spontaneousJob);
201
202 // it might happen that we call this function from within
203 // the thread itself, right when it finished its work
204 if (shouldStartThread && !m_testingMode) {
205 startThread(jobIndex);
206 }
207}
208
210{
211 QMutexLocker l(&m_runningThreadsMutex);
212
213 while(m_numRunningThreads > 0) {
214 m_waitForDoneCondition.wait(l.mutex());
215 }
216}
217
219 const KisUpdateJobItem* job)
220{
227 return walker->accessRect().intersects(job->accessRect());
228}
229
231{
232 for(qint32 i=0; i < m_jobs.size(); i++)
233 if(!m_jobs[i]->isRunning())
234 return i;
235
236 return -1;
237}
238
240{
241 m_lock.lock();
242}
243
245{
246 m_lock.unlock();
247}
248
250{
251 m_threadPool.setMaxThreadCount(value);
252
253 for (int i = 0; i < m_jobs.size(); i++) {
254 KIS_SAFE_ASSERT_RECOVER_RETURN(!m_jobs[i]->isRunning());
255 // don't delete the jobs until all of them are checked!
256 }
257
258 for (int i = 0; i < m_jobs.size(); i++) {
259 delete m_jobs[i];
260 }
261
262 m_jobs.resize(value);
263
264 for(qint32 i = 0; i < m_jobs.size(); i++) {
265 m_jobs[i] = new KisUpdateJobItem(this);
266 }
267}
268
270{
271 KIS_SAFE_ASSERT_RECOVER_NOOP(m_jobs.size() == m_threadPool.maxThreadCount());
272 return m_jobs.size();
273}
274
276{
278}
279
284
290
301
306
311
313{
314 Q_FOREACH (KisUpdateJobItem *item, m_jobs) {
315 item->testingSetDone();
316 }
317
319}
320
321
323 : KisUpdaterContext(threadCount)
324{
325 setTestingMode(true);
326}
327
float value(const T *src, size_t ch)
virtual int levelOfDetail() const =0
int levelOfDetail() const
KisTestableUpdaterContext(qint32 threadCount)
const QRect & accessRect() const
KisUpdaterContextSnapshotEx getContextSnapshotEx() const
void getJobsSnapshot(qint32 &numMergeJobs, qint32 &numStrokeJobs)
KisLockFreeLodCounter m_lodCounter
void addStrokeJob(KisStrokeJob *strokeJob)
friend class KisUpdateJobItem
bool isJobAllowed(KisBaseRectsWalkerSP walker)
void startThread(int index)
void setThreadsLimit(int value)
void addMergeJob(KisBaseRectsWalkerSP walker)
void addSpontaneousJob(KisSpontaneousJob *spontaneousJob)
void setTestingMode(bool value)
void continueUpdate(const QRect &rc)
QVector< KisUpdateJobItem * > m_jobs
static bool walkerIntersectsJob(KisBaseRectsWalkerSP walker, const KisUpdateJobItem *job)
const QVector< KisUpdateJobItem * > getJobs()
KisUpdaterContext(qint32 threadCount=useIdealThreadCountTag, KisUpdateScheduler *parent=0)
static const int useIdealThreadCountTag
KisUpdateScheduler * m_scheduler
QWaitCondition m_waitForDoneCondition
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
void continueUpdate(const QRect &rect)