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