c5f207cc8b1bcbafed47bd97cc41a31164843902
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-rasterize-thread.cpp
1 /*
2  * Copyright (c) 2019 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-rasterize-thread.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/thread-settings.h>
23 #include <dali/integration-api/adaptors/adaptor.h>
24 #include <dali/integration-api/debug.h>
25 #include <chrono>
26 #include <thread>
27
28 namespace Dali
29 {
30
31 namespace Toolkit
32 {
33
34 namespace Internal
35 {
36
37 namespace
38 {
39
40 constexpr auto LOOP_FOREVER = -1;
41 constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
42
43 #if defined(DEBUG_ENABLED)
44 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
45 #endif
46
47 inline void ResetValue( bool& updated, uint32_t& value, uint32_t newValue, ConditionalWait& conditionalWait )
48 {
49   ConditionalWait::ScopedLock lock( conditionalWait );
50   if( !updated )
51   {
52     value = newValue;
53     updated = true;
54   }
55 }
56
57 } // unnamed namespace
58
59 VectorRasterizeThread::VectorRasterizeThread( const std::string& url )
60 : mUrl( url ),
61   mVectorRenderer(),
62   mConditionalWait(),
63   mAnimationFinishedTrigger(),
64   mPlayState( PlayState::STOPPED ),
65   mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
66   mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
67   mFrameDurationNanoSeconds( 0 ),
68   mFrameRate( 60.0f ),
69   mCurrentFrame( 0 ),
70   mTotalFrame( 0 ),
71   mStartFrame( 0 ),
72   mEndFrame( 0 ),
73   mWidth( 0 ),
74   mHeight( 0 ),
75   mLoopCount( LOOP_FOREVER ),
76   mCurrentLoop( 0 ),
77   mNeedRender( false ),
78   mDestroyThread( false ),
79   mResourceReady( false ),
80   mCurrentFrameUpdated( false ),
81   mForward( true ),
82   mUpdateFrameNumber( false ),
83   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
84 {
85   Initialize();
86 }
87
88 VectorRasterizeThread::~VectorRasterizeThread()
89 {
90   // Stop the thread
91   {
92     ConditionalWait::ScopedLock lock( mConditionalWait );
93     mDestroyThread = true;
94     mConditionalWait.Notify( lock );
95   }
96
97   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join [%p]\n", this );
98
99   Join();
100 }
101
102 void VectorRasterizeThread::Run()
103 {
104   SetThreadName( "VectorImageThread" );
105   mLogFactory.InstallLogFunction();
106
107   while( !mDestroyThread )
108   {
109     Rasterize();
110   }
111
112   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Run: End of thread [%p]\n", this );
113 }
114
115 void VectorRasterizeThread::SetRenderer( Renderer renderer )
116 {
117   ConditionalWait::ScopedLock lock( mConditionalWait );
118
119   mVectorRenderer.SetRenderer( renderer );
120
121   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer [%p]\n", this );
122 }
123
124 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
125 {
126   if( mWidth != width || mHeight != height )
127   {
128     ConditionalWait::ScopedLock lock( mConditionalWait );
129     mVectorRenderer.SetSize( width, height );
130
131     mWidth = width;
132     mHeight = height;
133
134     mResourceReady = false;
135
136     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d [%p]\n", width, height, this );
137   }
138 }
139
140 void VectorRasterizeThread::PlayAnimation()
141 {
142   ConditionalWait::ScopedLock lock( mConditionalWait );
143
144   if( mPlayState != PlayState::PLAYING )
145   {
146     mNeedRender = true;
147     mUpdateFrameNumber = false;
148     mPlayState = PlayState::PLAYING;
149     mConditionalWait.Notify( lock );
150
151     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Play [%p]\n", this );
152   }
153 }
154
155 void VectorRasterizeThread::StopAnimation()
156 {
157   ConditionalWait::ScopedLock lock( mConditionalWait );
158   if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
159   {
160     mNeedRender = true;
161     mPlayState = PlayState::STOPPING;
162     mConditionalWait.Notify( lock );
163
164     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop [%p]\n", this );
165   }
166 }
167
168 void VectorRasterizeThread::PauseAnimation()
169 {
170   ConditionalWait::ScopedLock lock( mConditionalWait );
171   if( mPlayState == PlayState::PLAYING )
172   {
173     mPlayState = PlayState::PAUSED;
174
175     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause [%p]\n", this );
176   }
177 }
178
179 void VectorRasterizeThread::RenderFrame()
180 {
181   ConditionalWait::ScopedLock lock( mConditionalWait );
182
183   if( !mResourceReady )
184   {
185     mNeedRender = true;
186     mConditionalWait.Notify( lock );
187
188     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render [%p]\n", this );
189   }
190 }
191
192 void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback )
193 {
194   ConditionalWait::ScopedLock lock( mConditionalWait );
195   mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
196 }
197
198 void VectorRasterizeThread::SetLoopCount( int32_t count )
199 {
200   if( mLoopCount != count )
201   {
202     ConditionalWait::ScopedLock lock( mConditionalWait );
203
204     mLoopCount = count;
205
206     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetLoopCount: [%d] [%p]\n", count, this );
207   }
208 }
209
210 void VectorRasterizeThread::SetPlayRange( uint32_t startFrame, uint32_t endFrame )
211 {
212   // Make sure the range specified is between 0 and the total frame number
213   if( ( startFrame < mTotalFrame ) && ( endFrame < mTotalFrame ) )
214   {
215     // If the range is not in order swap values
216     if( startFrame > endFrame )
217     {
218       uint32_t temp = startFrame;
219       startFrame = endFrame;
220       endFrame = temp;
221     }
222
223     if( startFrame != mStartFrame || endFrame != mEndFrame )
224     {
225       ConditionalWait::ScopedLock lock( mConditionalWait );
226
227       mStartFrame = startFrame;
228       mEndFrame = endFrame;
229
230       // If the current frame is out of the range, change the current frame also.
231       if( mStartFrame > mCurrentFrame )
232       {
233         mCurrentFrame = mStartFrame;
234
235         mCurrentFrameUpdated = true;
236         mResourceReady = false;
237       }
238       else if( mEndFrame < mCurrentFrame )
239       {
240         mCurrentFrame = mEndFrame;
241
242         mCurrentFrameUpdated = true;
243         mResourceReady = false;
244       }
245
246       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
247     }
248   }
249 }
250
251 DevelImageVisual::PlayState::Type VectorRasterizeThread::GetPlayState() const
252 {
253   DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
254
255   switch( mPlayState )
256   {
257     case PlayState::PLAYING:
258     {
259       state = DevelImageVisual::PlayState::PLAYING;
260       break;
261     }
262     case PlayState::PAUSED:
263     {
264       state = DevelImageVisual::PlayState::PAUSED;
265       break;
266     }
267     case PlayState::STOPPING:
268     case PlayState::STOPPED:
269     {
270       state = DevelImageVisual::PlayState::STOPPED;
271       break;
272     }
273   }
274
275   return state;
276 }
277
278 bool VectorRasterizeThread::IsResourceReady() const
279 {
280   return mResourceReady;
281 }
282
283 void VectorRasterizeThread::SetCurrentFrameNumber( uint32_t frameNumber )
284 {
285   ConditionalWait::ScopedLock lock( mConditionalWait );
286
287   if( mCurrentFrame == frameNumber )
288   {
289     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
290     return;
291   }
292
293   if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
294   {
295     mCurrentFrame = frameNumber;
296     mCurrentFrameUpdated = true;
297
298     mResourceReady = false;
299
300     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
301   }
302   else
303   {
304     DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
305   }
306 }
307
308 uint32_t VectorRasterizeThread::GetCurrentFrameNumber() const
309 {
310   return mCurrentFrame;
311 }
312
313 uint32_t VectorRasterizeThread::GetTotalFrameNumber() const
314 {
315   return mTotalFrame;
316 }
317
318 void VectorRasterizeThread::GetDefaultSize( uint32_t& width, uint32_t& height ) const
319 {
320   mVectorRenderer.GetDefaultSize( width, height );
321 }
322
323 void VectorRasterizeThread::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
324 {
325   ConditionalWait::ScopedLock lock( mConditionalWait );
326   mStopBehavior = stopBehavior;
327
328   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
329 }
330
331 void VectorRasterizeThread::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
332 {
333   ConditionalWait::ScopedLock lock( mConditionalWait );
334   mLoopingMode = loopingMode;
335
336   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
337 }
338
339 VectorRasterizeThread::UploadCompletedSignalType& VectorRasterizeThread::UploadCompletedSignal()
340 {
341   return mVectorRenderer.UploadCompletedSignal();
342 }
343
344 void VectorRasterizeThread::Initialize()
345 {
346   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
347
348   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
349
350   mEndFrame = mTotalFrame - 1;
351
352   mFrameRate = mVectorRenderer.GetFrameRate();
353   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
354
355   uint32_t width, height;
356   mVectorRenderer.GetDefaultSize( width, height );
357
358   SetSize( width, height );
359
360   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
361 }
362
363 void VectorRasterizeThread::Rasterize()
364 {
365   bool stopped = false;
366   uint32_t currentFrame, startFrame, endFrame;
367   int32_t loopCount;
368
369   {
370     ConditionalWait::ScopedLock lock( mConditionalWait );
371
372     if( ( mPlayState == PlayState::PAUSED || mPlayState == PlayState::STOPPED ) && !mNeedRender && !mDestroyThread )
373     {
374       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Wait [%p]\n", this );
375       mConditionalWait.Wait( lock );
376     }
377
378     if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
379     {
380       mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
381     }
382
383     currentFrame = mCurrentFrame;
384     startFrame = mStartFrame;
385     endFrame = mEndFrame;
386     loopCount = mLoopCount;
387
388     mResourceReady = true;
389     mNeedRender = false;
390     mCurrentFrameUpdated = false;
391     mUpdateFrameNumber = true;
392   }
393
394   auto currentFrameStartTime = std::chrono::system_clock::now();
395
396   if( mPlayState == PlayState::STOPPING )
397   {
398     currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
399     ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
400
401     stopped = true;
402   }
403   else if( mPlayState == PlayState::PLAYING )
404   {
405     bool animationFinished = false;
406
407     if( currentFrame >= endFrame )  // last frame
408     {
409       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
410       {
411         mForward = false;
412       }
413       else
414       {
415         if( loopCount < 0 || ++mCurrentLoop < loopCount )   // repeat forever or before the last loop
416         {
417           ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
418           mUpdateFrameNumber = false;
419         }
420         else
421         {
422           animationFinished = true;   // end of animation
423         }
424       }
425     }
426     else if( currentFrame == startFrame && !mForward )  // first frame
427     {
428       if( loopCount < 0 || ++mCurrentLoop < loopCount )   // repeat forever or before the last loop
429       {
430         mForward = true;
431       }
432       else
433       {
434         animationFinished = true;   // end of animation
435       }
436     }
437
438     if( animationFinished )
439     {
440       if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
441       {
442         stopped = true;
443       }
444       else
445       {
446         mPlayState = PlayState::STOPPING;
447       }
448     }
449   }
450
451   // Rasterize
452   if( !mVectorRenderer.Render( currentFrame ) )
453   {
454     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
455     mUpdateFrameNumber = false;
456   }
457
458   if( stopped )
459   {
460     mPlayState = PlayState::STOPPED;
461     mForward = true;
462     mCurrentLoop = 0;
463
464     // Animation is finished
465     mAnimationFinishedTrigger->Trigger();
466
467     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
468   }
469
470   auto timeToSleepUntil = currentFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds );
471
472 #if defined(DEBUG_ENABLED)
473   auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( timeToSleepUntil - std::chrono::system_clock::now() );
474
475   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [current = %d, sleep duration = %lld] [%p]\n", currentFrame, sleepDuration.count(), this );
476 #endif
477
478   std::this_thread::sleep_until( timeToSleepUntil );
479 }
480
481 uint32_t VectorRasterizeThread::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
482 {
483   uint32_t frame = currentFrame;
484
485   switch( mStopBehavior )
486   {
487     case DevelImageVisual::StopBehavior::FIRST_FRAME:
488     {
489       frame = startFrame;
490       break;
491     }
492     case DevelImageVisual::StopBehavior::LAST_FRAME:
493     {
494       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
495       {
496         frame = startFrame;
497       }
498       else
499       {
500         frame = endFrame;
501       }
502       break;
503     }
504     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
505     {
506       frame = currentFrame;
507       break;
508     }
509   }
510
511   return frame;
512 }
513
514 } // namespace Internal
515
516 } // namespace Toolkit
517
518 } // namespace Dali