Merge "Fix SVACE issue" 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 inline void ResetToStart( bool& updated, uint32_t& value, uint32_t startValue, ConditionalWait& conditionalWait )
48 {
49   ConditionalWait::ScopedLock lock( conditionalWait );
50   if( !updated )
51   {
52     value = startValue;
53   }
54 }
55
56 } // unnamed namespace
57
58 VectorRasterizeThread::VectorRasterizeThread( const std::string& url )
59 : mUrl( url ),
60   mVectorRenderer(),
61   mConditionalWait(),
62   mResourceReadyTrigger(),
63   mAnimationFinishedTrigger(),
64   mPlayState( DevelImageVisual::PlayState::STOPPED ),
65   mFrameDurationNanoSeconds( 0 ),
66   mFrameRate( 60.0f ),
67   mCurrentFrame( 0 ),
68   mTotalFrame( 0 ),
69   mStartFrame( 0 ),
70   mEndFrame( 0 ),
71   mWidth( 0 ),
72   mHeight( 0 ),
73   mLoopCount( LOOP_FOREVER ),
74   mCurrentLoop( 0 ),
75   mNeedRender( false ),
76   mDestroyThread( false ),
77   mResourceReady( false ),
78   mCurrentFrameUpdated( false ),
79   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
80 {
81   Initialize();
82 }
83
84 VectorRasterizeThread::~VectorRasterizeThread()
85 {
86   // Stop the thread
87   {
88     ConditionalWait::ScopedLock lock( mConditionalWait );
89     mDestroyThread = true;
90     mConditionalWait.Notify( lock );
91
92     // This should be called in the main thread to stop waiting for the dequeuable buffer.
93     mVectorRenderer.StopRender();
94   }
95
96   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join\n" );
97
98   Join();
99 }
100
101 void VectorRasterizeThread::Run()
102 {
103   SetThreadName( "VectorImageThread" );
104   mLogFactory.InstallLogFunction();
105
106   while( !mDestroyThread )
107   {
108     Rasterize();
109   }
110
111   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Run: End of thread\n" );
112 }
113
114 void VectorRasterizeThread::SetRenderer( Renderer renderer )
115 {
116   ConditionalWait::ScopedLock lock( mConditionalWait );
117
118   mVectorRenderer.SetRenderer( renderer );
119
120   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer\n" );
121 }
122
123 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
124 {
125   if( mWidth != width || mHeight != height )
126   {
127     ConditionalWait::ScopedLock lock( mConditionalWait );
128     mVectorRenderer.SetSize( width, height );
129
130     mWidth = width;
131     mHeight = height;
132
133     mResourceReady = false;
134
135     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height );
136   }
137 }
138
139 void VectorRasterizeThread::PlayAnimation()
140 {
141   ConditionalWait::ScopedLock lock( mConditionalWait );
142
143   if( mPlayState != DevelImageVisual::PlayState::PLAYING )
144   {
145     mPlayState = DevelImageVisual::PlayState::PLAYING;
146     mConditionalWait.Notify( lock );
147
148     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Start\n" );
149   }
150 }
151
152 void VectorRasterizeThread::StopAnimation()
153 {
154   ConditionalWait::ScopedLock lock( mConditionalWait );
155   if( mPlayState != DevelImageVisual::PlayState::STOPPED )
156   {
157     mPlayState = DevelImageVisual::PlayState::STOPPED;
158
159     mCurrentFrame = mStartFrame;
160     mCurrentFrameUpdated = true;
161
162     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
163   }
164 }
165
166 void VectorRasterizeThread::PauseAnimation()
167 {
168   ConditionalWait::ScopedLock lock( mConditionalWait );
169   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
170   {
171     mPlayState = DevelImageVisual::PlayState::PAUSED;
172
173     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" );
174   }
175 }
176
177 void VectorRasterizeThread::RenderFrame()
178 {
179   ConditionalWait::ScopedLock lock( mConditionalWait );
180
181   if( !mResourceReady )
182   {
183     mNeedRender = true;
184     mConditionalWait.Notify( lock );
185
186     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
187   }
188 }
189
190 void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
191 {
192   ConditionalWait::ScopedLock lock( mConditionalWait );
193   mResourceReadyTrigger = std::unique_ptr< EventThreadCallback >( callback );
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
210     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetLoopCount: [%d]\n", count );
211   }
212 }
213
214 void VectorRasterizeThread::SetPlayRange( uint32_t startFrame, uint32_t endFrame )
215 {
216   // Make sure the range specified is between 0 and the total frame number
217   if( ( startFrame < mTotalFrame ) && ( endFrame < mTotalFrame ) )
218   {
219     // If the range is not in order swap values
220     if( startFrame > endFrame )
221     {
222       uint32_t temp = startFrame;
223       startFrame = endFrame;
224       endFrame = temp;
225     }
226
227     if( startFrame != mStartFrame || endFrame != mEndFrame )
228     {
229       ConditionalWait::ScopedLock lock( mConditionalWait );
230
231       mStartFrame = startFrame;
232       mEndFrame = endFrame;
233
234       // If the current frame is out of the range, change the current frame also.
235       if( mStartFrame > mCurrentFrame )
236       {
237         mCurrentFrame = mStartFrame;
238
239         mCurrentFrameUpdated = true;
240         mResourceReady = false;
241       }
242       else if( mEndFrame < mCurrentFrame )
243       {
244         mCurrentFrame = mEndFrame;
245
246         mCurrentFrameUpdated = true;
247         mResourceReady = false;
248       }
249
250       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetPlayRangeInFrame: [%d, %d]\n", mStartFrame, mEndFrame );
251     }
252   }
253 }
254
255 void VectorRasterizeThread::SetCurrentFrameNumber( uint32_t frameNumber )
256 {
257   ConditionalWait::ScopedLock lock( mConditionalWait );
258
259   if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
260   {
261     mCurrentFrame = frameNumber;
262     mCurrentFrameUpdated = true;
263
264     mResourceReady = false;
265
266     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentFrameNumber: frame number = %f (%d)\n", mCurrentFrame );
267   }
268   else
269   {
270     DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
271   }
272 }
273
274 uint32_t VectorRasterizeThread::GetCurrentFrameNumber() const
275 {
276   return mCurrentFrame;
277 }
278
279 uint32_t VectorRasterizeThread::GetTotalFrameNumber() const
280 {
281   return mTotalFrame;
282 }
283
284 void VectorRasterizeThread::GetDefaultSize( uint32_t& width, uint32_t& height ) const
285 {
286   mVectorRenderer.GetDefaultSize( width, height );
287 }
288
289 DevelImageVisual::PlayState VectorRasterizeThread::GetPlayState() const
290 {
291   return mPlayState;
292 }
293
294 bool VectorRasterizeThread::IsResourceReady() const
295 {
296   return mResourceReady;
297 }
298
299 void VectorRasterizeThread::Initialize()
300 {
301   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
302
303   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
304
305   mEndFrame = mTotalFrame;
306
307   mFrameRate = mVectorRenderer.GetFrameRate();
308   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
309
310   uint32_t width, height;
311   mVectorRenderer.GetDefaultSize( width, height );
312
313   SetSize( width, height );
314
315   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Initialize: file = %s [%d frames, %f fps]\n", mUrl.c_str(), mTotalFrame, mFrameRate );
316 }
317
318 void VectorRasterizeThread::Rasterize()
319 {
320   bool resourceReady;
321   uint32_t currentFrame, startFrame, endFrame;
322   int32_t loopCount;
323   DevelImageVisual::PlayState playState;
324
325   {
326     ConditionalWait::ScopedLock lock( mConditionalWait );
327
328     if( mPlayState != DevelImageVisual::PlayState::PLAYING && !mNeedRender && !mDestroyThread )
329     {
330       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Wait\n" );
331
332       if( mPlayState == DevelImageVisual::PlayState::STOPPED )
333       {
334         // Reset the current loop
335         mCurrentLoop = 0;
336       }
337       mConditionalWait.Wait( lock );
338     }
339
340     resourceReady = mResourceReady;
341     currentFrame = mCurrentFrame++;
342     startFrame = mStartFrame;
343     endFrame = mEndFrame;
344     loopCount = mLoopCount;
345     playState = mPlayState;
346
347     mNeedRender = false;
348     mResourceReady = true;
349     mCurrentFrameUpdated = false;
350   }
351
352   auto currentFrameStartTime = std::chrono::system_clock::now();
353
354   // Rasterize
355   mVectorRenderer.Render( currentFrame );
356
357   if( playState == DevelImageVisual::PlayState::PLAYING )
358   {
359     if( currentFrame >= endFrame )
360     {
361       if( loopCount < 0 )
362       {
363         // repeat forever
364         ResetToStart( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
365       }
366       else
367       {
368         mCurrentLoop++;
369         if( mCurrentLoop >= loopCount )
370         {
371           mPlayState = DevelImageVisual::PlayState::STOPPED;
372
373           ResetToStart( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );
374
375           // Animation is finished
376           mAnimationFinishedTrigger->Trigger();
377
378           DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished\n" );
379         }
380         else
381         {
382           ResetToStart( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );
383         }
384       }
385     }
386   }
387
388   if( !resourceReady )
389   {
390     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
391
392     mResourceReadyTrigger->Trigger();
393   }
394
395   auto timeToSleepUntil = currentFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds );
396
397 #if defined(DEBUG_ENABLED)
398   auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( timeToSleepUntil - std::chrono::system_clock::now() );
399
400   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [current = %d, sleep duration = %lld]\n", currentFrame, sleepDuration.count() );
401 #endif
402
403   std::this_thread::sleep_until( timeToSleepUntil );
404 }
405
406 } // namespace Internal
407
408 } // namespace Toolkit
409
410 } // namespace Dali