File indexing completed on 2024-05-12 15:58:48
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_UPDATER_CONTEXT_H 0008 #define __KIS_UPDATER_CONTEXT_H 0009 0010 #include <QMutex> 0011 #include <QReadWriteLock> 0012 #include <QThreadPool> 0013 #include <QWaitCondition> 0014 0015 #include "kis_base_rects_walker.h" 0016 #include "kis_async_merger.h" 0017 #include "kis_lock_free_lod_counter.h" 0018 0019 #include "KisUpdaterContextSnapshotEx.h" 0020 #include "kis_update_scheduler.h" 0021 0022 class KisUpdateJobItem; 0023 class KisSpontaneousJob; 0024 class KisStrokeJob; 0025 class KisUpdateScheduler; 0026 0027 class KRITAIMAGE_EXPORT KisUpdaterContext 0028 { 0029 public: 0030 static const int useIdealThreadCountTag; 0031 0032 public: 0033 KisUpdaterContext(qint32 threadCount = useIdealThreadCountTag, KisUpdateScheduler *parent = 0); 0034 ~KisUpdaterContext(); 0035 0036 0037 /** 0038 * Returns the number of currently running jobs of each type. 0039 * To use this information you should lock the context beforehand. 0040 * 0041 * \see lock() 0042 */ 0043 void getJobsSnapshot(qint32 &numMergeJobs, qint32 &numStrokeJobs); 0044 0045 KisUpdaterContextSnapshotEx getContextSnapshotEx() const; 0046 0047 /** 0048 * Returns the current level of detail of all the running jobs in the 0049 * context. If there are no jobs, returns -1. 0050 */ 0051 int currentLevelOfDetail() const; 0052 0053 /** 0054 * Check whether there is a spare thread for running 0055 * one more job 0056 */ 0057 bool hasSpareThread(); 0058 0059 /** 0060 * Checks whether the walker intersects with any 0061 * of currently executing walkers. If it does, 0062 * it is not allowed to go in. It should be called 0063 * with the lock held. 0064 * 0065 * \see lock() 0066 */ 0067 bool isJobAllowed(KisBaseRectsWalkerSP walker); 0068 0069 /** 0070 * Registers the job and starts executing it. 0071 * The caller must ensure that the context is locked 0072 * with lock(), job is allowed with isWalkerAllowed() and 0073 * there is a spare thread for running it with hasSpareThread() 0074 * 0075 * \see lock() 0076 * \see isWalkerAllowed() 0077 * \see hasSpareThread() 0078 */ 0079 void addMergeJob(KisBaseRectsWalkerSP walker); 0080 0081 /** 0082 * Adds a stroke job to the context. The prerequisites are 0083 * the same as for addMergeJob() 0084 * \see addMergeJob() 0085 */ 0086 void addStrokeJob(KisStrokeJob *strokeJob); 0087 0088 0089 /** 0090 * Adds a spontaneous job to the context. The prerequisites are 0091 * the same as for addMergeJob() 0092 * \see addMergeJob() 0093 */ 0094 void addSpontaneousJob(KisSpontaneousJob *spontaneousJob); 0095 0096 /** 0097 * Block execution of the caller until all the jobs are finished 0098 */ 0099 void waitForDone(); 0100 0101 /** 0102 * Locks the context to guarantee an exclusive access 0103 * to the context 0104 */ 0105 void lock(); 0106 0107 /** 0108 * Unlocks the context 0109 * 0110 * \see lock() 0111 */ 0112 void unlock(); 0113 0114 /** 0115 * Set the number of threads available for this updater context 0116 * WARNING: one cannot change the number of threads if there is 0117 * at least one job running in the context! So before 0118 * calling this method make sure you do two things: 0119 * 1) barrierLock() the update scheduler 0120 * 2) lock() the context 0121 */ 0122 void setThreadsLimit(int value); 0123 0124 /** 0125 * Return the number of available threads in the context. Make sure you 0126 * lock the context before calling this function! 0127 */ 0128 int threadsLimit() const; 0129 0130 void continueUpdate(const QRect& rc); 0131 void doSomeUsefulWork(); 0132 void jobFinished(); 0133 void jobThreadExited(); 0134 0135 void setTestingMode(bool value); 0136 0137 protected: 0138 static bool walkerIntersectsJob(KisBaseRectsWalkerSP walker, 0139 const KisUpdateJobItem* job); 0140 qint32 findSpareThread(); 0141 0142 protected: 0143 /** 0144 * The lock is shared by all the child update job items. 0145 * When an item wants to run a usual (non-exclusive) job, 0146 * it locks the lock for read access. When an exclusive 0147 * access is requested, it locks it for write 0148 */ 0149 QReadWriteLock m_exclusiveJobLock; 0150 0151 QMutex m_lock; 0152 QMutex m_runningThreadsMutex; 0153 int m_numRunningThreads = 0; 0154 QWaitCondition m_waitForDoneCondition; 0155 QVector<KisUpdateJobItem*> m_jobs; 0156 QThreadPool m_threadPool; 0157 KisLockFreeLodCounter m_lodCounter; 0158 KisUpdateScheduler *m_scheduler; 0159 bool m_testingMode = false; 0160 0161 private: 0162 0163 friend class KisUpdaterContextTest; 0164 friend class KisUpdateSchedulerTest; 0165 friend class KisStrokesQueueTest; 0166 friend class KisSimpleUpdateQueueTest; 0167 friend class KisUpdateJobItem; 0168 0169 const QVector<KisUpdateJobItem*> getJobs(); 0170 void clear(); 0171 0172 void startThread(int index); 0173 0174 }; 0175 0176 class KRITAIMAGE_EXPORT KisTestableUpdaterContext : public KisUpdaterContext 0177 { 0178 public: 0179 /** 0180 * Creates an explicit number of threads 0181 */ 0182 KisTestableUpdaterContext(qint32 threadCount); 0183 }; 0184 0185 0186 #endif /* __KIS_UPDATER_CONTEXT_H */ 0187 0188 0189