Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAsyncAnimationRendererBase.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QTimer>
10#include <QThread>
11
12#include "KisMpl.h"
13#include "kis_image.h"
16#include "kis_image_config.h"
18
20 qRegisterMetaType<KisAsyncAnimationRendererBase::CancelReason>("KisAsyncAnimationRendererBase::CancelReason");
21}
22
34
36 : QObject(parent),
37 m_d(new Private())
38{
39 connect(&m_d->regenerationTimeout, SIGNAL(timeout()), SLOT(slotFrameRegenerationTimedOut()));
40
41 KisImageConfig cfg(true);
42
43 m_d->regenerationTimeout.setSingleShot(true);
44 m_d->regenerationTimeout.setInterval(cfg.frameRenderingTimeout());
45}
46
51
52void KisAsyncAnimationRendererBase::startFrameRegeneration(KisImageSP image, int frame, const KisRegion &regionOfInterest, Flags flags, KisLockFrameGenerationLock &&frameGenerationLock)
53{
54 KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() == this->thread());
55
56 m_d->requestedImage = image;
57 m_d->requestedFrame = frame;
58 m_d->isCancelled = false;
59 m_d->requestedRegion = !regionOfInterest.isEmpty() ? regionOfInterest : image->bounds();
60
61 KisImageAnimationInterface *animation = m_d->requestedImage->animationInterface();
62
63 m_d->imageRequestConnections.clear();
64 m_d->imageRequestConnections.addConnection(
65 animation, SIGNAL(sigFrameReady(int)),
66 this, SLOT(slotFrameRegenerationFinished(int)),
67 Qt::DirectConnection);
68
69 m_d->imageRequestConnections.addConnection(
70 animation, SIGNAL(sigFrameCancelled()),
72 Qt::AutoConnection);
73
74 m_d->regenerationTimeout.start();
75 animation->requestFrameRegeneration(m_d->requestedFrame, m_d->requestedRegion, flags & Cancellable, std::move(frameGenerationLock));
76}
77
78void KisAsyncAnimationRendererBase::startFrameRegeneration(KisImageSP image, int frame, Flags flags, KisLockFrameGenerationLock &&frameGenerationLock)
79{
80 startFrameRegeneration(image, frame, KisRegion(), flags, std::move(frameGenerationLock));
81}
82
84{
85 return m_d->requestedImage;
86}
87
89{
90 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedImage);
91 frameCancelledCallback(m_d->requestedFrame, cancelReason);
92}
93
95{
96 // the cancel can arrive in async way
97 if (!m_d->requestedImage) return;
99}
100
102{
103 // the timeout can arrive in async way
104 if (!m_d->requestedImage) return;
106}
107
109{
110 // We might have already cancelled the regeneration. We don't check
111 // isCancelled flag here because this code runs asynchronously.
112 if (!m_d->requestedImage) return;
113
114 // WARNING: executed in the context of image worker thread!
115
116 // probably a bit too strict...
117 KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() != this->thread());
118
119 frameCompletedCallback(frame, m_d->requestedRegion);
120}
121
123{
124 KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() == this->thread());
125
126 // the image events can come with a delay, even after
127 // the processing was cancelled
128 if (m_d->isCancelled) return;
129
130 {
131 // clean state right after the assert checks
132 auto cleanup = kismpl::finally([&] () {
134 });
135
136 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedImage);
137 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedFrame == frame);
138 }
139
140
141 Q_EMIT sigFrameCompleted(frame);
142}
143
145{
146 KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() == this->thread());
147
148 // the image events can come with a delay, even after
149 // the processing was cancelled
150 if (m_d->isCancelled) return;
151
152 {
153 // clean state right after the assert checks
154 auto cleanup = kismpl::finally([&] () {
156 });
157
158 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedImage);
159 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedFrame == frame);
160 }
161
162 Q_EMIT sigFrameCancelled(frame, cancelReason);
163}
164
166{
167 // TODO: for some reason we mark the process as cancelled in any case, and it
168 // seem to be a correct behavior
169 Q_UNUSED(isCancelled);
170
171 m_d->imageRequestConnections.clear();
172 m_d->requestedImage = 0;
173 m_d->requestedFrame = -1;
174 m_d->regenerationTimeout.stop();
175 m_d->isCancelled = true;
176 m_d->requestedRegion = KisRegion();
177}
178
180{
181 return m_d->requestedImage;
182}
183
184
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void requestFrameRegeneration(int frameId, const KisRegion &dirtyRegion, bool isCancellable, KisLockFrameGenerationLock &&lock)
int frameRenderingTimeout(bool defaultValue=false) const
QRect bounds() const override
bool isEmpty() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
void sigFrameCancelled(int frame, KisAsyncAnimationRendererBase::CancelReason cancelReason)
void notifyFrameCancelled(int frame, KisAsyncAnimationRendererBase::CancelReason cancelReason)
virtual void frameCancelledCallback(int frame, CancelReason cancelReason)=0
frameCancelledCallback is called when the rendering of the frame was cancelled.
KisSignalAutoConnectionsStore imageRequestConnections
virtual void clearFrameRegenerationState(bool isCancelled)
virtual void frameCompletedCallback(int frame, const KisRegion &requestedRegion)=0
frameCompletedCallback is called by the renderer when a new frame becomes ready
const QScopedPointer< Private > m_d
void startFrameRegeneration(KisImageSP image, int frame, const KisRegion &regionOfInterest, Flags flags, KisLockFrameGenerationLock &&frameGenerationLock)
void sigFrameCompleted(int frame)
void cancelCurrentFrameRendering(CancelReason cancelReason)
cancels current rendering operation