(Vector) Support SYNCHRONOUS_LOADING
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-animation-task.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/math/math-utils.h>
24 #include <dali/public-api/object/property-array.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
28 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
29 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
30
31 namespace Dali
32 {
33 namespace Toolkit
34 {
35 namespace Internal
36 {
37 namespace
38 {
39 constexpr auto LOOP_FOREVER = -1;
40 constexpr auto MICROSECONDS_PER_SECOND(1e+6);
41
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
44 #endif
45
46 } // unnamed namespace
47
48 VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
49 : mUrl(),
50   mVectorRenderer(VectorAnimationRenderer::New()),
51   mAnimationData(),
52   mVectorAnimationThread(factoryCache.GetVectorAnimationManager().GetVectorAnimationThread()),
53   mConditionalWait(),
54   mResourceReadySignal(),
55   mAnimationFinishedTrigger(),
56   mLoadCompletedTrigger(new EventThreadCallback(MakeCallback(this, &VectorAnimationTask::OnLoadCompleted))),
57   mPlayState(PlayState::STOPPED),
58   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
59   mLoopingMode(DevelImageVisual::LoopingMode::RESTART),
60   mNextFrameStartTime(),
61   mFrameDurationMicroSeconds(MICROSECONDS_PER_SECOND / 60.0f),
62   mFrameRate(60.0f),
63   mCurrentFrame(0),
64   mTotalFrame(0),
65   mStartFrame(0),
66   mEndFrame(0),
67   mDroppedFrames(0),
68   mWidth(0),
69   mHeight(0),
70   mAnimationDataIndex(0),
71   mLoopCount(LOOP_FOREVER),
72   mCurrentLoop(0),
73   mForward(true),
74   mUpdateFrameNumber(false),
75   mNeedAnimationFinishedTrigger(true),
76   mAnimationDataUpdated(false),
77   mDestroyTask(false),
78   mLoadRequest(false),
79   mLoadFailed(false)
80 {
81   mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted);
82 }
83
84 VectorAnimationTask::~VectorAnimationTask()
85 {
86   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this);
87 }
88
89 void VectorAnimationTask::Finalize()
90 {
91   ConditionalWait::ScopedLock lock(mConditionalWait);
92
93   // Release some objects in the main thread
94   if(mAnimationFinishedTrigger)
95   {
96     mAnimationFinishedTrigger.reset();
97   }
98   if(mLoadCompletedTrigger)
99   {
100     mLoadCompletedTrigger.reset();
101   }
102
103   mVectorRenderer.Finalize();
104
105   mDestroyTask = true;
106 }
107
108 bool VectorAnimationTask::Load(bool synchronousLoading)
109 {
110   if(!mVectorRenderer.Load(mUrl))
111   {
112     DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mUrl.c_str());
113     mLoadRequest = false;
114     mLoadFailed  = true;
115     if(!synchronousLoading)
116     {
117       mLoadCompletedTrigger->Trigger();
118     }
119     return false;
120   }
121
122   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
123
124   mEndFrame = mTotalFrame - 1;
125
126   mFrameRate                 = mVectorRenderer.GetFrameRate();
127   mFrameDurationMicroSeconds = MICROSECONDS_PER_SECOND / mFrameRate;
128
129   mLoadRequest = false;
130   if(!synchronousLoading)
131   {
132     mLoadCompletedTrigger->Trigger();
133   }
134
135   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Load: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this);
136
137   return true;
138 }
139
140 void VectorAnimationTask::SetRenderer(Renderer renderer)
141 {
142   ConditionalWait::ScopedLock lock(mConditionalWait);
143
144   mVectorRenderer.SetRenderer(renderer);
145
146   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this);
147 }
148
149 void VectorAnimationTask::RequestLoad(const std::string& url, bool synchronousLoading)
150 {
151   mUrl = url;
152
153   if(!synchronousLoading)
154   {
155     mLoadRequest = true;
156
157     mVectorAnimationThread.AddTask(this);
158   }
159   else
160   {
161     Load(true);
162
163     OnLoadCompleted();
164   }
165 }
166
167 bool VectorAnimationTask::IsLoadRequested() const
168 {
169   return mLoadRequest;
170 }
171
172 void VectorAnimationTask::SetAnimationData(const AnimationData& data)
173 {
174   ConditionalWait::ScopedLock lock(mConditionalWait);
175
176   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this);
177
178   uint32_t index = mAnimationDataIndex == 0 ? 1 : 0; // Use the other buffer
179
180   mAnimationData[index] = data;
181   mAnimationDataUpdated = true;
182
183   if(data.resendFlag & VectorAnimationTask::RESEND_SIZE)
184   {
185     // The size should be changed in the main thread.
186     SetSize(data.width, data.height);
187   }
188
189   mVectorAnimationThread.AddTask(this);
190 }
191
192 void VectorAnimationTask::SetSize(uint32_t width, uint32_t height)
193 {
194   if(mWidth != width || mHeight != height)
195   {
196     mVectorRenderer.SetSize(width, height);
197
198     mWidth  = width;
199     mHeight = height;
200
201     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this);
202   }
203 }
204
205 void VectorAnimationTask::PlayAnimation()
206 {
207   if(mPlayState != PlayState::PLAYING)
208   {
209     mNeedAnimationFinishedTrigger = true;
210     mUpdateFrameNumber            = false;
211     mPlayState                    = PlayState::PLAYING;
212
213     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this);
214   }
215 }
216
217 void VectorAnimationTask::StopAnimation()
218 {
219   if(mPlayState != PlayState::STOPPING)
220   {
221     mNeedAnimationFinishedTrigger = false;
222     mPlayState                    = PlayState::STOPPING;
223
224     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this);
225   }
226 }
227
228 void VectorAnimationTask::PauseAnimation()
229 {
230   if(mPlayState == PlayState::PLAYING)
231   {
232     mPlayState = PlayState::PAUSED;
233
234     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this);
235   }
236 }
237
238 void VectorAnimationTask::SetAnimationFinishedCallback(EventThreadCallback* callback)
239 {
240   ConditionalWait::ScopedLock lock(mConditionalWait);
241   if(callback)
242   {
243     mAnimationFinishedTrigger = std::unique_ptr<EventThreadCallback>(callback);
244   }
245 }
246
247 void VectorAnimationTask::SetLoopCount(int32_t count)
248 {
249   if(mLoopCount != count)
250   {
251     mLoopCount   = count;
252     mCurrentLoop = 0;
253
254     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this);
255   }
256 }
257
258 void VectorAnimationTask::SetPlayRange(const Property::Array& playRange)
259 {
260   bool     valid      = false;
261   uint32_t startFrame = 0, endFrame = 0;
262   size_t   count = playRange.Count();
263
264   if(count >= 2)
265   {
266     int32_t start = 0, end = 0;
267     if(playRange.GetElementAt(0).Get(start) && playRange.GetElementAt(1).Get(end))
268     {
269       startFrame = static_cast<uint32_t>(start);
270       endFrame   = static_cast<uint32_t>(end);
271       valid      = true;
272     }
273     else
274     {
275       std::string startMarker, endMarker;
276       if(playRange.GetElementAt(0).Get(startMarker) && playRange.GetElementAt(1).Get(endMarker))
277       {
278         if(mVectorRenderer)
279         {
280           uint32_t frame; // We don't use this later
281           if(mVectorRenderer.GetMarkerInfo(startMarker, startFrame, frame) && mVectorRenderer.GetMarkerInfo(endMarker, frame, endFrame))
282           {
283             valid = true;
284           }
285         }
286       }
287     }
288   }
289   else if(count == 1)
290   {
291     std::string marker;
292     if(playRange.GetElementAt(0).Get(marker))
293     {
294       if(mVectorRenderer && mVectorRenderer.GetMarkerInfo(marker, startFrame, endFrame))
295       {
296         valid = true;
297       }
298     }
299   }
300
301   if(!valid)
302   {
303     DALI_LOG_ERROR("VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this);
304     return;
305   }
306
307   // Make sure the range specified is between 0 and the total frame number
308   startFrame = std::min(startFrame, mTotalFrame - 1);
309   endFrame   = std::min(endFrame, mTotalFrame - 1);
310
311   // If the range is not in order swap values
312   if(startFrame > endFrame)
313   {
314     uint32_t temp = startFrame;
315     startFrame    = endFrame;
316     endFrame      = temp;
317   }
318
319   if(startFrame != mStartFrame || endFrame != mEndFrame)
320   {
321     mStartFrame = startFrame;
322     mEndFrame   = endFrame;
323
324     // If the current frame is out of the range, change the current frame also.
325     if(mStartFrame > mCurrentFrame)
326     {
327       mCurrentFrame = mStartFrame;
328     }
329     else if(mEndFrame < mCurrentFrame)
330     {
331       mCurrentFrame = mEndFrame;
332     }
333
334     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mUrl.c_str(), this);
335   }
336 }
337
338 void VectorAnimationTask::GetPlayRange(uint32_t& startFrame, uint32_t& endFrame)
339 {
340   startFrame = mStartFrame;
341   endFrame   = mEndFrame;
342 }
343
344 void VectorAnimationTask::SetCurrentFrameNumber(uint32_t frameNumber)
345 {
346   if(mCurrentFrame == frameNumber)
347   {
348     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this);
349     return;
350   }
351
352   if(frameNumber >= mStartFrame && frameNumber <= mEndFrame)
353   {
354     mCurrentFrame      = frameNumber;
355     mUpdateFrameNumber = false;
356
357     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this);
358   }
359   else
360   {
361     DALI_LOG_ERROR("Invalid frame number [%d (%d, %d)] [%p]\n", frameNumber, mStartFrame, mEndFrame, this);
362   }
363 }
364
365 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
366 {
367   return mCurrentFrame;
368 }
369
370 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
371 {
372   return mTotalFrame;
373 }
374
375 void VectorAnimationTask::GetDefaultSize(uint32_t& width, uint32_t& height) const
376 {
377   mVectorRenderer.GetDefaultSize(width, height);
378 }
379
380 void VectorAnimationTask::SetStopBehavior(DevelImageVisual::StopBehavior::Type stopBehavior)
381 {
382   mStopBehavior = stopBehavior;
383
384   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this);
385 }
386
387 void VectorAnimationTask::SetLoopingMode(DevelImageVisual::LoopingMode::Type loopingMode)
388 {
389   mLoopingMode = loopingMode;
390
391   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this);
392 }
393
394 void VectorAnimationTask::GetLayerInfo(Property::Map& map) const
395 {
396   mVectorRenderer.GetLayerInfo(map);
397 }
398
399 VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReadySignal()
400 {
401   return mResourceReadySignal;
402 }
403
404 bool VectorAnimationTask::Rasterize(bool& keepAnimation)
405 {
406   bool     stopped = false;
407   uint32_t currentFrame;
408   keepAnimation = false;
409
410   {
411     ConditionalWait::ScopedLock lock(mConditionalWait);
412     if(mDestroyTask)
413     {
414       // The task will be destroyed. We don't need rasterization.
415       return false;
416     }
417   }
418
419   if(mLoadRequest)
420   {
421     return Load(false);
422   }
423
424   if(mLoadFailed)
425   {
426     return false;
427   }
428
429   ApplyAnimationData();
430
431   if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber)
432   {
433     mCurrentFrame = mForward ? mCurrentFrame + mDroppedFrames + 1 : (mCurrentFrame > mDroppedFrames ? mCurrentFrame - mDroppedFrames - 1 : 0);
434     Dali::ClampInPlace(mCurrentFrame, mStartFrame, mEndFrame);
435   }
436
437   currentFrame = mCurrentFrame;
438
439   mUpdateFrameNumber = true;
440
441   if(mPlayState == PlayState::STOPPING)
442   {
443     mCurrentFrame = GetStoppedFrame(mStartFrame, mEndFrame, mCurrentFrame);
444     currentFrame  = mCurrentFrame;
445     stopped       = true;
446   }
447   else if(mPlayState == PlayState::PLAYING)
448   {
449     bool animationFinished = false;
450
451     if(currentFrame >= mEndFrame) // last frame
452     {
453       if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE)
454       {
455         mForward = false;
456       }
457       else
458       {
459         if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop
460         {
461           mCurrentFrame      = mStartFrame;
462           mUpdateFrameNumber = false;
463         }
464         else
465         {
466           animationFinished = true; // end of animation
467         }
468       }
469     }
470     else if(currentFrame == mStartFrame && !mForward) // first frame
471     {
472       if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop
473       {
474         mForward = true;
475       }
476       else
477       {
478         animationFinished = true; // end of animation
479       }
480     }
481
482     if(animationFinished)
483     {
484       if(mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME)
485       {
486         stopped = true;
487       }
488       else
489       {
490         mPlayState = PlayState::STOPPING;
491       }
492     }
493   }
494
495   // Rasterize
496   bool renderSuccess = false;
497   if(mVectorRenderer)
498   {
499     renderSuccess = mVectorRenderer.Render(currentFrame);
500     if(!renderSuccess)
501     {
502       DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this);
503       mUpdateFrameNumber = false;
504     }
505   }
506
507   if(stopped && renderSuccess)
508   {
509     mPlayState   = PlayState::STOPPED;
510     mForward     = true;
511     mCurrentLoop = 0;
512
513     // Animation is finished
514     {
515       ConditionalWait::ScopedLock lock(mConditionalWait);
516       if(mNeedAnimationFinishedTrigger && mAnimationFinishedTrigger)
517       {
518         mAnimationFinishedTrigger->Trigger();
519       }
520     }
521
522     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this);
523   }
524
525   if(mPlayState != PlayState::PAUSED && mPlayState != PlayState::STOPPED)
526   {
527     keepAnimation = true;
528   }
529
530   return true;
531 }
532
533 uint32_t VectorAnimationTask::GetStoppedFrame(uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame)
534 {
535   uint32_t frame = currentFrame;
536
537   switch(mStopBehavior)
538   {
539     case DevelImageVisual::StopBehavior::FIRST_FRAME:
540     {
541       frame = startFrame;
542       break;
543     }
544     case DevelImageVisual::StopBehavior::LAST_FRAME:
545     {
546       if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE)
547       {
548         frame = startFrame;
549       }
550       else
551       {
552         frame = endFrame;
553       }
554       break;
555     }
556     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
557     {
558       frame = currentFrame;
559       break;
560     }
561   }
562
563   return frame;
564 }
565
566 VectorAnimationTask::TimePoint VectorAnimationTask::CalculateNextFrameTime(bool renderNow)
567 {
568   // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::steady_clock supported
569   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
570   // is casted to use the default duration.
571   mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
572   auto current        = std::chrono::steady_clock::now();
573   mDroppedFrames      = 0;
574
575   if(renderNow)
576   {
577     mNextFrameStartTime = current;
578   }
579   else if(mNextFrameStartTime < current)
580   {
581     uint32_t droppedFrames = 0;
582
583     while(current > std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)) && droppedFrames < mTotalFrame)
584     {
585       droppedFrames++;
586       mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
587     }
588
589     mNextFrameStartTime = current;
590     mDroppedFrames      = droppedFrames;
591   }
592
593   return mNextFrameStartTime;
594 }
595
596 VectorAnimationTask::TimePoint VectorAnimationTask::GetNextFrameTime()
597 {
598   return mNextFrameStartTime;
599 }
600
601 void VectorAnimationTask::ApplyAnimationData()
602 {
603   uint32_t index;
604
605   {
606     ConditionalWait::ScopedLock lock(mConditionalWait);
607
608     if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].resendFlag != 0)
609     {
610       // Data is not updated or the previous data is not applied yet.
611       return;
612     }
613
614     mAnimationDataIndex   = mAnimationDataIndex == 0 ? 1 : 0; // Swap index
615     mAnimationDataUpdated = false;
616
617     index = mAnimationDataIndex;
618   }
619
620   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT)
621   {
622     SetLoopCount(mAnimationData[index].loopCount);
623   }
624
625   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE)
626   {
627     SetPlayRange(mAnimationData[index].playRange);
628   }
629
630   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR)
631   {
632     SetStopBehavior(mAnimationData[index].stopBehavior);
633   }
634
635   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE)
636   {
637     SetLoopingMode(mAnimationData[index].loopingMode);
638   }
639
640   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME)
641   {
642     SetCurrentFrameNumber(mAnimationData[index].currentFrame);
643   }
644
645   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
646   {
647     mVectorRenderer.InvalidateBuffer();
648   }
649
650   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY)
651   {
652     for(auto&& iter : mAnimationData[index].dynamicProperties)
653     {
654       mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast<VectorAnimationRenderer::VectorProperty>(iter.property), iter.callback, iter.id);
655     }
656   }
657
658   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
659   {
660     if(mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING)
661     {
662       PlayAnimation();
663     }
664     else if(mAnimationData[index].playState == DevelImageVisual::PlayState::PAUSED)
665     {
666       PauseAnimation();
667     }
668     else if(mAnimationData[index].playState == DevelImageVisual::PlayState::STOPPED)
669     {
670       StopAnimation();
671     }
672   }
673
674   // reset data
675   mAnimationData[index].dynamicProperties.clear();
676   mAnimationData[index].resendFlag = 0;
677 }
678
679 void VectorAnimationTask::OnUploadCompleted()
680 {
681   mResourceReadySignal.Emit(ResourceStatus::READY);
682 }
683
684 void VectorAnimationTask::OnLoadCompleted()
685 {
686   if(!mLoadFailed)
687   {
688     mResourceReadySignal.Emit(ResourceStatus::LOADED);
689   }
690   else
691   {
692     mResourceReadySignal.Emit(ResourceStatus::FAILED);
693   }
694 }
695 } // namespace Internal
696
697 } // namespace Toolkit
698
699 } // namespace Dali