Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAnimationCachePopulator::Private Struct Reference

Public Types

enum  RegenerationRequestResult { RequestSuccessful = 0 , RequestRejected , RequestPostponed }
 
enum  State { NotWaitingForAnything , WaitingForIdle , WaitingForFrame , BetweenFrames }
 

Public Member Functions

QString debugStateToString (State newState)
 
void enterState (State newState)
 
void generateIfIdle ()
 
 Private (KisAnimationCachePopulator *_q, KisPart *_part)
 
RegenerationRequestResult regenerate (KisAnimationFrameCacheSP cache, int frame)
 
void timerTimeout ()
 
RegenerationRequestResult tryRequestGeneration ()
 
RegenerationRequestResult tryRequestGeneration (KisAnimationFrameCacheSP cache, KisTimeSpan skipRange, int priorityFrame)
 

Public Attributes

bool calculateAnimationCacheInBackground = true
 
int idleCounter
 
KisPartpart
 
QStack< QPair< KisImageWSP, int > > priorityFrames
 
KisAnimationCachePopulatorq
 
KisAsyncAnimationCacheRenderer regenerator
 
State state
 
QTimer timer
 

Static Public Attributes

static const int BETWEEN_FRAMES_INTERVAL = 10
 
static const int IDLE_CHECK_INTERVAL = 500
 
static const int IDLE_COUNT_THRESHOLD = 4
 

Detailed Description

Definition at line 36 of file kis_animation_cache_populator.cpp.

Member Enumeration Documentation

◆ RegenerationRequestResult

◆ State

Constructor & Destructor Documentation

◆ Private()

Member Function Documentation

◆ debugStateToString()

QString KisAnimationCachePopulator::Private::debugStateToString ( State newState)
inline

Definition at line 282 of file kis_animation_cache_populator.cpp.

282 {
283 QString str = "<unknown>";
284
285 switch (newState) {
286 case WaitingForIdle:
287 str = "WaitingForIdle";
288 break;
289 case WaitingForFrame:
290 str = "WaitingForFrame";
291 break;
293 str = "NotWaitingForAnything";
294 break;
295 case BetweenFrames:
296 str = "BetweenFrames";
297 break;
298 }
299
300 return str;
301 }

References BetweenFrames, NotWaitingForAnything, WaitingForFrame, and WaitingForIdle.

◆ enterState()

void KisAnimationCachePopulator::Private::enterState ( State newState)
inline

Definition at line 303 of file kis_animation_cache_populator.cpp.

304 {
305 //ENTER_FUNCTION() << debugStateToString(state) << "->" << debugStateToString(newState);
306
307 state = newState;
308 int timerTimeout = -1;
309
310 switch (state) {
311 case WaitingForIdle:
313 break;
314 case WaitingForFrame:
315 // the timeout is handled by the regenerator now
316 timerTimeout = -1;
317 break;
319 // frame conversion cannot be cancelled,
320 // so there is no timeout
321 timerTimeout = -1;
322 break;
323 case BetweenFrames:
325 break;
326 }
327
328 if (timerTimeout >= 0) {
329 timer.start(timerTimeout);
330 } else {
331 timer.stop();
332 }
333 }

References BETWEEN_FRAMES_INTERVAL, BetweenFrames, IDLE_CHECK_INTERVAL, NotWaitingForAnything, state, timer, timerTimeout(), WaitingForFrame, and WaitingForIdle.

◆ generateIfIdle()

void KisAnimationCachePopulator::Private::generateIfIdle ( )
inline

◆ regenerate()

RegenerationRequestResult KisAnimationCachePopulator::Private::regenerate ( KisAnimationFrameCacheSP cache,
int frame )
inline

We should enter the state before the frame is requested. Otherwise the signal may come earlier than we enter it.

Definition at line 253 of file kis_animation_cache_populator.cpp.

254 {
255 if (state == WaitingForFrame) {
256 // Already busy, deny request
257 return RequestRejected;
258 }
259
260 KisLockFrameGenerationLock lock(cache->image()->animationInterface(), std::try_to_lock);
261
262 if (!lock.owns_lock()) {
263 return RequestPostponed;
264 }
265
272
274
275 // if we ever decide to add ROI to background cache
276 // regeneration, it should be added here :)
278
279 return RequestSuccessful;
280 }
void setFrameCache(KisAnimationFrameCacheSP cache)
KisImageAnimationInterface * animationInterface() const
void startFrameRegeneration(KisImageSP image, int frame, const KisRegion &regionOfInterest, Flags flags, KisLockFrameGenerationLock &&frameGenerationLock)

References KisImage::animationInterface(), KisAsyncAnimationRendererBase::Cancellable, enterState(), KisAnimationFrameCache::image(), regenerator, RequestPostponed, RequestRejected, RequestSuccessful, KisAsyncAnimationCacheRenderer::setFrameCache(), KisAsyncAnimationRendererBase::startFrameRegeneration(), state, and WaitingForFrame.

◆ timerTimeout()

void KisAnimationCachePopulator::Private::timerTimeout ( )
inline

Definition at line 79 of file kis_animation_cache_populator.cpp.

79 {
80 switch (state) {
81 case WaitingForIdle:
82 case BetweenFrames:
84 break;
85 case WaitingForFrame:
86 KIS_ASSERT_RECOVER_NOOP(0 && "WaitingForFrame cannot have a timeout. Just skip this message and report a bug");
87 break;
89 KIS_ASSERT_RECOVER_NOOP(0 && "NotWaitingForAnything cannot have a timeout. Just skip this message and report a bug");
90 break;
91 }
92 }
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97

References BetweenFrames, generateIfIdle(), KIS_ASSERT_RECOVER_NOOP, NotWaitingForAnything, state, WaitingForFrame, and WaitingForIdle.

◆ tryRequestGeneration() [1/2]

RegenerationRequestResult KisAnimationCachePopulator::Private::tryRequestGeneration ( )
inline

We have just upgraded the image pointer to the strong pointer, let's check if it is still valid.

It may happen that the view (and the canvas) of this image has already been removed. Hence the cache does not exist anymore. So we should just skip this stinking image.

The frame got cached in the meantime, so skip its recalculation

Definition at line 118 of file kis_animation_cache_populator.cpp.

119 {
120 while (!priorityFrames.isEmpty()) {
121 KisImageSP image = priorityFrames.top().first;
122 const int priorityFrame = priorityFrames.top().second;
123 priorityFrames.pop();
124
129 if (!image) continue;
130
131 if (!image->animationInterface()->hasAnimation()) continue;
133
140 if (!cache) {
141 // a small sanity check that our guess it right...
143 auto it = std::find_if(views.constBegin(), views.constEnd(),
144 [image] (QPointer<KisView> view) {
145 return view && KisImageSP(view->image()) == image;
146 });
147 const bool foundExistingViewForImage = it != views.constEnd();
148
149 KIS_SAFE_ASSERT_RECOVER(!foundExistingViewForImage) {
150 priorityFrames.erase(
151 std::remove_if(priorityFrames.begin(), priorityFrames.end(),
152 [image] (auto requestPair) {
153 return KisImageSP(requestPair.first) == image;
154 }), priorityFrames.end());
155 }
156
157 continue;
158 }
159
163 if (cache->frameStatus(priorityFrame) == KisAnimationFrameCache::Cached) {
164 continue;
165 }
166
168 tryRequestGeneration(cache, KisTimeSpan(), priorityFrame);
169 if (result == RequestSuccessful) return result;
170 }
171
172 // Prioritize the active document
173 KisAnimationFrameCacheSP activeDocumentCache = KisAnimationFrameCacheSP(0);
174
175 KisMainWindow *activeWindow = part->currentMainwindow();
176 if (activeWindow && activeWindow->activeView()) {
177 KisCanvas2 *activeCanvas = activeWindow->activeView()->canvasBase();
178
179 if (activeCanvas && activeCanvas->frameCache() &&
180 activeCanvas->image()->animationInterface()->hasAnimation()) {
181
182 activeDocumentCache = activeCanvas->frameCache();
183
184 // Let's skip frames affected by changes to the active node (on the active document)
185 // This avoids constant invalidation and regeneration while drawing
186 KisNodeSP activeNode = activeCanvas->viewManager()->nodeManager()->activeNode();
187 KisTimeSpan skipRange;
188 if (activeNode) {
189 const int currentTime = activeCanvas->currentImage()->animationInterface()->currentUITime();
190
191 if (!activeNode->keyframeChannels().isEmpty()) {
192 Q_FOREACH (const KisKeyframeChannel *channel, activeNode->keyframeChannels()) {
193 skipRange |= channel->affectedFrames(currentTime);
194 }
195 } else {
196 skipRange = KisTimeSpan::infinite(0);
197 }
198 }
199
201 tryRequestGeneration(activeDocumentCache, skipRange, -1);
202 if (result == RequestSuccessful) return result;
203 }
204 }
205
208 Q_FOREACH (cache, caches) {
209 if (cache == activeDocumentCache.data()) {
210 // We already handled this one...
211 continue;
212 }
213
214 if (!cache->image()->animationInterface()->hasAnimation()) {
215 // This image is not animated
216 continue;
217 }
218
220 tryRequestGeneration(cache, KisTimeSpan(), -1);
221 if (result == RequestSuccessful) return result;
222 }
223
224 return RequestRejected;
225 }
static const QList< KisAnimationFrameCache * > caches()
CacheStatus frameStatus(int time) const
static const KisAnimationFrameCacheSP cacheForImage(KisImageWSP image)
KisAnimationFrameCacheSP frameCache
KisImageWSP currentImage() const
KisImageWSP image() const
KisViewManager * viewManager() const
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
virtual KisTimeSpan affectedFrames(int time) const
Get the set of frames affected by any changes to the value or content of the active keyframe at the g...
Main window for Krita.
QPointer< KisView > activeView
KisNodeSP activeNode()
Convenience function to get the active layer or mask.
static KisPart * instance()
Definition KisPart.cpp:131
KisMainWindow * currentMainwindow() const
Definition KisPart.cpp:483
QList< QPointer< KisView > > views
Definition KisPart.cpp:106
static KisTimeSpan infinite(int start)
KisNodeManager * nodeManager() const
The node manager handles everything about nodes.
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
KisSharedPtr< KisAnimationFrameCache > KisAnimationFrameCacheSP
Definition kis_types.h:185
QMap< QString, KisKeyframeChannel * > keyframeChannels

References KisNodeManager::activeNode(), KisMainWindow::activeView, KisKeyframeChannel::affectedFrames(), KisImage::animationInterface(), KisImageAnimationInterface::backgroundFrameGenerationBlocked(), KisAnimationFrameCache::Cached, KisAnimationFrameCache::cacheForImage(), KisAnimationFrameCache::caches(), KisCanvas2::currentImage(), KisPart::currentMainwindow(), KisImageAnimationInterface::currentUITime(), KisSharedPtr< T >::data(), KisCanvas2::frameCache, KisAnimationFrameCache::frameStatus(), KisImageAnimationInterface::hasAnimation(), KisAnimationFrameCache::image(), KisCanvas2::image(), KisTimeSpan::infinite(), KisPart::instance(), KisBaseNode::keyframeChannels, KIS_SAFE_ASSERT_RECOVER, KisViewManager::nodeManager(), part, priorityFrames, RequestRejected, RequestSuccessful, tryRequestGeneration(), KisCanvas2::viewManager(), and KisPart::views.

◆ tryRequestGeneration() [2/2]

RegenerationRequestResult KisAnimationCachePopulator::Private::tryRequestGeneration ( KisAnimationFrameCacheSP cache,
KisTimeSpan skipRange,
int priorityFrame )
inline

Definition at line 227 of file kis_animation_cache_populator.cpp.

228 {
229 KisImageSP image = cache->image();
230 if (!image) return RequestRejected;
231
233
234 if (animation->backgroundFrameGenerationBlocked()) {
235 return RequestPostponed;
236 }
237
238 // the higher levels of code should have caught the case when
239 // the image is not animated
241
242 KisTimeSpan currentRange = animation->documentPlaybackRange();
243
244 const int frame = priorityFrame >= 0 ? priorityFrame : KisAsyncAnimationCacheRenderDialog::calcFirstDirtyFrame(cache, currentRange, skipRange);
245
246 if (frame >= 0) {
247 return regenerate(cache, frame);
248 }
249
250 return RequestRejected;
251 }
static int calcFirstDirtyFrame(KisAnimationFrameCacheSP cache, const KisTimeSpan &playbackRange, const KisTimeSpan &skipRange)
const KisTimeSpan & documentPlaybackRange() const
documentPlaybackRange
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
RegenerationRequestResult regenerate(KisAnimationFrameCacheSP cache, int frame)

References KisImage::animationInterface(), KisImageAnimationInterface::backgroundFrameGenerationBlocked(), KisAsyncAnimationCacheRenderDialog::calcFirstDirtyFrame(), KisImageAnimationInterface::documentPlaybackRange(), KisImageAnimationInterface::hasAnimation(), KisAnimationFrameCache::image(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, regenerate(), RequestPostponed, and RequestRejected.

Member Data Documentation

◆ BETWEEN_FRAMES_INTERVAL

const int KisAnimationCachePopulator::Private::BETWEEN_FRAMES_INTERVAL = 10
static

Definition at line 50 of file kis_animation_cache_populator.cpp.

◆ calculateAnimationCacheInBackground

bool KisAnimationCachePopulator::Private::calculateAnimationCacheInBackground = true

Definition at line 53 of file kis_animation_cache_populator.cpp.

◆ IDLE_CHECK_INTERVAL

const int KisAnimationCachePopulator::Private::IDLE_CHECK_INTERVAL = 500
static

Definition at line 49 of file kis_animation_cache_populator.cpp.

◆ IDLE_COUNT_THRESHOLD

const int KisAnimationCachePopulator::Private::IDLE_COUNT_THRESHOLD = 4
static

Definition at line 48 of file kis_animation_cache_populator.cpp.

◆ idleCounter

int KisAnimationCachePopulator::Private::idleCounter

Counts up the number of subsequent times Krita has been detected idle.

Definition at line 46 of file kis_animation_cache_populator.cpp.

◆ part

KisPart* KisAnimationCachePopulator::Private::part

Definition at line 39 of file kis_animation_cache_populator.cpp.

◆ priorityFrames

QStack<QPair<KisImageWSP, int> > KisAnimationCachePopulator::Private::priorityFrames

Definition at line 47 of file kis_animation_cache_populator.cpp.

◆ q

KisAnimationCachePopulator* KisAnimationCachePopulator::Private::q

Definition at line 38 of file kis_animation_cache_populator.cpp.

◆ regenerator

KisAsyncAnimationCacheRenderer KisAnimationCachePopulator::Private::regenerator

Definition at line 52 of file kis_animation_cache_populator.cpp.

◆ state

State KisAnimationCachePopulator::Private::state

Definition at line 61 of file kis_animation_cache_populator.cpp.

◆ timer

QTimer KisAnimationCachePopulator::Private::timer

Definition at line 41 of file kis_animation_cache_populator.cpp.


The documentation for this struct was generated from the following file: