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