File indexing completed on 2024-05-12 15:58:47

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_UPDATE_SCHEDULER_H
0008 #define __KIS_UPDATE_SCHEDULER_H
0009 
0010 #include <QObject>
0011 #include "kritaimage_export.h"
0012 #include "kis_types.h"
0013 
0014 #include "kis_image_interfaces.h"
0015 #include "kis_stroke_strategy_factory.h"
0016 #include "kis_strokes_queue_undo_result.h"
0017 #include "KisLodPreferences.h"
0018 
0019 class QRect;
0020 class KoProgressProxy;
0021 class KisProjectionUpdateListener;
0022 class KisSpontaneousJob;
0023 class KisPostExecutionUndoAdapter;
0024 
0025 
0026 class KRITAIMAGE_EXPORT KisUpdateScheduler : public QObject, public KisStrokesFacade
0027 {
0028     Q_OBJECT
0029 
0030 public:
0031     KisUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener, QObject *parent = 0);
0032     ~KisUpdateScheduler() override;
0033 
0034     /**
0035      * Set the number of threads used by the scheduler
0036      */
0037     void setThreadsLimit(int value);
0038 
0039     /**
0040      * Return the number of threads available to the scheduler
0041      */
0042     int threadsLimit() const;
0043 
0044     /**
0045      * Sets the proxy that is going to be notified about the progress
0046      * of processing of the queues. If you want to switch the proxy
0047      * on runtime, you should do it under the lock held.
0048      *
0049      * \see lock(), unlock()
0050      */
0051     void setProgressProxy(KoProgressProxy *progressProxy);
0052 
0053     /**
0054      * Blocks processing of the queues.
0055      * The function will wait until all the executing jobs
0056      * are finished.
0057      * NOTE: you may add new jobs while the block held, but they
0058      * will be delayed until unlock() is called.
0059      *
0060      * \see unlock()
0061      */
0062     void immediateLockForReadOnly();
0063 
0064     /**
0065      * Unblocks the process and calls processQueues()
0066      *
0067      * \see processQueues()
0068      */
0069     void unlock(bool resetLodLevels = true);
0070 
0071     /**
0072      * Waits until all the running jobs are finished.
0073      *
0074      * If some other thread adds jobs in parallel, then you may
0075      * wait forever. If you you don't want it, consider lock() instead.
0076      *
0077      * \see lock()
0078      */
0079     void waitForDone();
0080 
0081     /**
0082      * Waits until the queues become empty, then blocks the processing.
0083      * To unblock processing you should use unlock().
0084      *
0085      * If some other thread adds jobs in parallel, then you may
0086      * wait forever. If you you don't want it, consider lock() instead.
0087      *
0088      * \see unlock(), lock()
0089      */
0090     void barrierLock();
0091 
0092 
0093     /**
0094      * Works like barrier lock, but returns false immediately if barrierLock
0095      * can't be acquired.
0096      *
0097      * \see barrierLock()
0098      */
0099     bool tryBarrierLock();
0100 
0101     /**
0102      * Tells if there are no strokes or updates are running at the
0103      * moment. Internally calls to tryBarrierLock(), so it is not O(1).
0104      */
0105     bool isIdle();
0106 
0107     /**
0108      * Blocks all the updates from execution. It doesn't affect
0109      * strokes execution in any way. This type of lock is supposed
0110      * to be held by the strokes themselves when they need a short
0111      * access to some parts of the projection of the image.
0112      *
0113      * From all the other places you should use usual lock()/unlock()
0114      * methods
0115      *
0116      * \see lock(), unlock()
0117      */
0118     void blockUpdates();
0119 
0120     /**
0121      * Unblocks updates from execution previously locked by blockUpdates()
0122      *
0123      * \see blockUpdates()
0124      */
0125     void unblockUpdates();
0126 
0127     void updateProjection(KisNodeSP node, const QVector<QRect> &rects, const QRect &cropRect);
0128     void updateProjection(KisNodeSP node, const QRect &rc, const QRect &cropRect);
0129     void updateProjectionNoFilthy(KisNodeSP node, const QVector<QRect>& rects, const QRect &cropRect);
0130     void updateProjectionNoFilthy(KisNodeSP node, const QRect& rc, const QRect &cropRect);
0131     void fullRefreshAsync(KisNodeSP root, const QVector<QRect>& rc, const QRect &cropRect);
0132     void fullRefreshAsyncNoFilthy(KisNodeSP root, const QVector<QRect>& rects, const QRect &cropRect);
0133     void fullRefresh(KisNodeSP root, const QRect& rc, const QRect &cropRect);
0134     void addSpontaneousJob(KisSpontaneousJob *spontaneousJob);
0135 
0136     bool hasUpdatesRunning() const;
0137 
0138     KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override;
0139     void addJob(KisStrokeId id, KisStrokeJobData *data) override;
0140     void endStroke(KisStrokeId id) override;
0141     bool cancelStroke(KisStrokeId id) override;
0142 
0143     /**
0144      * Sets the desired level of detail preferences on which the strokes should
0145      * work. Please note that this configuration will be applied starting from
0146      * the next stroke. Please also note that this value is not guaranteed to
0147      * coincide with the one returned by currentLevelOfDetail()
0148      */
0149     void setLodPreferences(const KisLodPreferences &value);
0150 
0151     /**
0152      * Return current lod preferences loaded in the strokes queue
0153      */
0154     KisLodPreferences lodPreferences() const;
0155 
0156     /**
0157      * Explicitly start regeneration of LoD planes of all the devices
0158      * in the image. This call should be performed when the user is idle,
0159      * just to make the quality of image updates better.
0160      */
0161     void explicitRegenerateLevelOfDetail();
0162 
0163     /**
0164      * Install a factory of a stroke strategy, that will be started
0165      * every time when the scheduler needs to synchronize LOD caches
0166      * of all the paint devices of the image.
0167      */
0168     void setLod0ToNStrokeStrategyFactory(const KisLodSyncStrokeStrategyFactory &factory);
0169 
0170     /**
0171      * Install a factory of a stroke strategies, that will be started
0172      * every time when the scheduler needs to postpone/resume all the updates
0173      * of the *LOD0* strokes.
0174      */
0175     void setSuspendResumeUpdatesStrokeStrategyFactory(const KisSuspendResumeStrategyPairFactory &factory);
0176 
0177     /**
0178      * Sets a callback that is called by the scheduler in the
0179      * beginning of every stroke that declared the necessity
0180      * of the redo state clearence.
0181      */
0182     void setPurgeRedoStateCallback(const std::function<void()> &callback);
0183 
0184     KisPostExecutionUndoAdapter* lodNPostExecutionUndoAdapter() const;
0185 
0186 
0187     /**
0188      * tryCancelCurrentStrokeAsync() checks whether there is a
0189      * *running* stroke (which is being executed at this very moment)
0190      * which is not still open by the owner (endStroke() or
0191      * cancelStroke() have already been called) and cancels it.
0192      *
0193      * \return true if some stroke has been found and cancelled
0194      *
0195      * \note This method is *not* part of KisStrokesFacade! It is too
0196      *       low level for KisImage.  In KisImage it is combined with
0197      *       more high level requestStrokeCancellation().
0198      */
0199     bool tryCancelCurrentStrokeAsync();
0200 
0201     UndoResult tryUndoLastStrokeAsync();
0202 
0203     bool wrapAroundModeSupported() const;
0204     int currentLevelOfDetail() const;
0205 
0206     void continueUpdate(const QRect &rect);
0207     void doSomeUsefulWork();
0208     void spareThreadAppeared();
0209 
0210 protected:
0211     // Trivial constructor for testing support
0212     KisUpdateScheduler();
0213     void connectSignals();
0214     void processQueues();
0215 
0216 protected Q_SLOTS:
0217     /**
0218      * Called when it is necessary to reread configuration
0219      */
0220     void updateSettings();
0221 
0222 private:
0223     friend class UpdatesBlockTester;
0224     bool haveUpdatesRunning();
0225     void tryProcessUpdatesQueue();
0226     void wakeUpWaitingThreads();
0227 
0228     void progressUpdate();
0229 
0230 protected:
0231     struct Private;
0232     Private * const m_d;
0233 };
0234 
0235 
0236 class KisTestableSimpleUpdateQueue;
0237 class KisUpdaterContext;
0238 
0239 class KRITAIMAGE_EXPORT KisTestableUpdateScheduler : public KisUpdateScheduler
0240 {
0241 public:
0242     KisTestableUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener,
0243                                qint32 threadCount);
0244 
0245     KisUpdaterContext* updaterContext();
0246     using KisUpdateScheduler::processQueues;
0247 };
0248 
0249 #endif /* __KIS_UPDATE_SCHEDULER_H */
0250