9#include "klocalizedstring.h"
21#include <QReadWriteLock>
28#define DEBUG_BALANCING_METRICS(decidedFirst, excl) \
29 dbgKrita << "Balance decision:" << decidedFirst \
30 << "(" << excl << ")" \
31 << "updates:" << m_d->updatesQueue.sizeMetric() \
32 << "strokes:" << m_d->strokesQueue.sizeMetric()
34#define DEBUG_BALANCING_METRICS(decidedFirst, excl)
42 , projectionUpdateListener(
p)
50 bool processingBlocked =
false;
51 qreal defaultBalancingRatio = 1.0;
61 return strokeRatioOverride > 0 ? strokeRatioOverride : defaultBalancingRatio;
67 m_d(new
Private(this, projectionUpdateListener))
80 delete m_d->progressUpdater;
94 m_d->updaterContext.lock();
95 m_d->updaterContext.setThreadsLimit(
value);
96 m_d->updaterContext.unlock();
102 std::lock_guard<KisUpdaterContext> l(
m_d->updaterContext);
103 return m_d->updaterContext.threadsLimit();
114 delete m_d->progressUpdater;
115 m_d->progressUpdater = progressProxy ?
121 if (!
m_d->progressUpdater)
return;
123 if(!
m_d->strokesQueue.hasOpenedStrokes()) {
124 QString jobName =
m_d->strokesQueue.currentStrokeName().toString();
125 if(jobName.isEmpty()) {
126 jobName = i18n(
"Updating...");
129 int sizeMetric =
m_d->strokesQueue.sizeMetric();
131 sizeMetric =
m_d->updatesQueue.sizeMetric();
134 m_d->progressUpdater->updateProgress(sizeMetric, jobName);
137 m_d->progressUpdater->hide();
165 m_d->updatesQueue.addSpontaneousJob(spontaneousJob);
171 return !
m_d->updatesQueue.isEmpty();
183 m_d->strokesQueue.addJob(
id, data);
189 m_d->strokesQueue.endStroke(
id);
195 bool result =
m_d->strokesQueue.cancelStroke(
id);
202 return m_d->strokesQueue.tryCancelCurrentStrokeAsync();
207 return m_d->strokesQueue.tryUndoLastStrokeAsync();
212 return m_d->strokesQueue.wrapAroundModeSupported();
217 m_d->strokesQueue.setLodPreferences(
value);
229 return m_d->strokesQueue.lodPreferences();
234 m_d->strokesQueue.explicitRegenerateLevelOfDetail();
242 int levelOfDetail =
m_d->updaterContext.currentLevelOfDetail();
244 if (levelOfDetail < 0) {
246 levelOfDetail =
m_d->updatesQueue.overrideLevelOfDetail();
249 if (levelOfDetail < 0) {
253 return levelOfDetail;
258 m_d->strokesQueue.setLod0ToNStrokeStrategyFactory(factory);
263 m_d->strokesQueue.setSuspendResumeUpdatesStrokeStrategyFactory(factory);
268 m_d->strokesQueue.setPurgeRedoStateCallback(callback);
273 m_d->strokesQueue.setPostSyncLod0GUIPlaneRequestForResumeCallback(callback);
278 return m_d->strokesQueue.lodNPostExecutionUndoAdapter();
283 m_d->updatesQueue.updateSettings();
291 m_d->processingBlocked =
true;
292 m_d->updaterContext.waitForDone();
297 if (resetLodLevels) {
302 m_d->strokesQueue.notifyUFOChangedImage();
305 m_d->processingBlocked =
false;
325 m_d->updaterContext.waitForDone();
326 }
while(!
m_d->updatesQueue.isEmpty() || !
m_d->strokesQueue.isEmpty());
331 if(!
m_d->updatesQueue.isEmpty() || !
m_d->strokesQueue.isEmpty()) {
335 m_d->processingBlocked =
true;
336 m_d->updaterContext.waitForDone();
337 if(!
m_d->updatesQueue.isEmpty() || !
m_d->strokesQueue.isEmpty()) {
338 m_d->processingBlocked =
false;
349 m_d->processingBlocked =
false;
351 m_d->processingBlocked =
true;
352 m_d->updaterContext.waitForDone();
353 }
while(!
m_d->updatesQueue.isEmpty() || !
m_d->strokesQueue.isEmpty());
360 if(
m_d->processingBlocked)
return;
362 if(
m_d->strokesQueue.needsExclusiveAccess()) {
364 m_d->strokesQueue.processQueue(
m_d->updaterContext,
365 !
m_d->updatesQueue.isEmpty());
367 if(!
m_d->strokesQueue.needsExclusiveAccess()) {
371 else if(
m_d->balancingRatio() *
m_d->strokesQueue.sizeMetric() >
m_d->updatesQueue.sizeMetric()) {
373 m_d->strokesQueue.processQueue(
m_d->updaterContext,
374 !
m_d->updatesQueue.isEmpty());
380 m_d->strokesQueue.processQueue(
m_d->updaterContext,
381 !
m_d->updatesQueue.isEmpty());
390 m_d->updatesFinishedCondition.initWaiting();
392 m_d->updatesLockCounter.ref();
394 m_d->updatesFinishedCondition.wait();
397 m_d->updatesFinishedCondition.endWaiting();
402 m_d->updatesLockCounter.deref();
409 m_d->updatesFinishedCondition.wakeAll();
415 QReadLocker locker(&
m_d->updatesStartLock);
416 if(
m_d->updatesLockCounter)
return;
418 m_d->updatesQueue.processQueue(
m_d->updaterContext);
423 QWriteLocker locker(&
m_d->updatesStartLock);
425 qint32 numMergeJobs, numStrokeJobs;
426 m_d->updaterContext.getJobsSnapshot(numMergeJobs, numStrokeJobs);
433 Q_ASSERT(
m_d->projectionUpdateListener);
434 m_d->projectionUpdateListener->notifyProjectionUpdated(
rect);
439 m_d->updatesQueue.optimize();
454 m_d->updaterContext.setTestingMode(
true);
461 return &
m_d->updaterContext;
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
static KisImageConfigNotifier * instance()
qreal schedulerBalancingRatio() const
int maxNumberOfThreads(bool defaultValue=false) const
KisUpdaterContext * updaterContext()
KisTestableUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener, qint32 threadCount)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
std::function< std::pair< KisSuspendResumePair, KisSuspendResumePair >()> KisSuspendResumeStrategyPairFactory
std::function< KisLodSyncPair(bool)> KisLodSyncStrokeStrategyFactory
#define DEBUG_BALANCING_METRICS(decidedFirst, excl)
qreal balancingRatioOverride
UndoResult tryUndoLastStrokeAsync()
void unlock(bool resetLodLevels=true)
void addJob(KisStrokeId id, KisStrokeJobData *data) override
void setPostSyncLod0GUIPlaneRequestForResumeCallback(const std::function< void()> &callback)
void setProgressProxy(KoProgressProxy *progressProxy)
~KisUpdateScheduler() override
QReadWriteLock updatesStartLock
void updateProjection(KisNodeSP node, const QVector< QRect > &rects, const QRect &cropRect, KisProjectionUpdateFlags flags)
void setSuspendResumeUpdatesStrokeStrategyFactory(const KisSuspendResumeStrategyPairFactory &factory)
void wakeUpWaitingThreads()
void addSpontaneousJob(KisSpontaneousJob *spontaneousJob)
void spareThreadAppeared()
KisStrokesQueue strokesQueue
KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override
bool tryCancelCurrentStrokeAsync()
void immediateLockForReadOnly()
void tryProcessUpdatesQueue()
void setLodPreferences(const KisLodPreferences &value)
int currentLevelOfDetail() const
KisLazyWaitCondition updatesFinishedCondition
bool hasUpdatesRunning() const
void setLod0ToNStrokeStrategyFactory(const KisLodSyncStrokeStrategyFactory &factory)
void continueUpdate(const QRect &rect)
void endStroke(KisStrokeId id) override
void explicitRegenerateLevelOfDetail()
KisLodPreferences lodPreferences() const
qreal balancingRatio() const
KisUpdaterContext updaterContext
bool wrapAroundModeSupported() const
void setThreadsLimit(int value)
KisPostExecutionUndoAdapter * lodNPostExecutionUndoAdapter() const
QAtomicInt updatesLockCounter
bool haveUpdatesRunning()
KisSimpleUpdateQueue updatesQueue
Private(KisUpdateScheduler *_q, KisProjectionUpdateListener *p)
void setPurgeRedoStateCallback(const std::function< void()> &callback)
bool cancelStroke(KisStrokeId id) override
void fullRefreshAsync(KisNodeSP root, const QVector< QRect > &rects, const QRect &cropRect, KisProjectionUpdateFlags flags)
KisProjectionUpdateListener * projectionUpdateListener