(AnimatedVectorImageVisual) Use the content default size
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-rasterize-thread.cpp
1 /*
2  * Copyright (c) 2018 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   mPlayRange( 0.0f, 1.0f ),
65   mPlayState( DevelImageVisual::PlayState::STOPPED ),
66   mFrameDurationNanoSeconds( 0 ),
67   mProgress( 0.0f ),
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   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
82 {
83   Initialize();
84 }
85
86 VectorRasterizeThread::~VectorRasterizeThread()
87 {
88   // Stop the thread
89   {
90     ConditionalWait::ScopedLock lock( mConditionalWait );
91     mDestroyThread = true;
92     mConditionalWait.Notify( lock );
93
94     // This should be called in the main thread to stop waiting for the dequeuable buffer.
95     mVectorRenderer.StopRender();
96   }
97
98   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join\n" );
99
100   Join();
101 }
102
103 void VectorRasterizeThread::Run()
104 {
105   SetThreadName( "VectorImageThread" );
106   mLogFactory.InstallLogFunction();
107
108   while( !mDestroyThread )
109   {
110     Rasterize();
111   }
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   if( mPlayState != DevelImageVisual::PlayState::PLAYING )
143   {
144     mPlayState = DevelImageVisual::PlayState::PLAYING;
145     mConditionalWait.Notify( lock );
146
147     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Start\n" );
148   }
149 }
150
151 void VectorRasterizeThread::StopAnimation()
152 {
153   ConditionalWait::ScopedLock lock( mConditionalWait );
154   if( mPlayState != DevelImageVisual::PlayState::STOPPED )
155   {
156     mPlayState = DevelImageVisual::PlayState::STOPPED;
157
158     mCurrentFrame = mStartFrame;
159     mCurrentFrameUpdated = true;
160
161     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
162   }
163 }
164
165 void VectorRasterizeThread::PauseAnimation()
166 {
167   ConditionalWait::ScopedLock lock( mConditionalWait );
168   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
169   {
170     mPlayState = DevelImageVisual::PlayState::PAUSED;
171
172     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" );
173   }
174 }
175
176 void VectorRasterizeThread::RenderFrame()
177 {
178   ConditionalWait::ScopedLock lock( mConditionalWait );
179
180   if( !mResourceReady )
181   {
182     mNeedRender = true;
183     mConditionalWait.Notify( lock );
184
185     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
186   }
187 }
188
189 void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
190 {
191   ConditionalWait::ScopedLock lock( mConditionalWait );
192   mResourceReadyTrigger = std::unique_ptr< EventThreadCallback >( callback );
193 }
194
195 void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback )
196 {
197   ConditionalWait::ScopedLock lock( mConditionalWait );
198   mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
199 }
200
201 void VectorRasterizeThread::SetLoopCount( int32_t count )
202 {
203   if( mLoopCount != count )
204   {
205     ConditionalWait::ScopedLock lock( mConditionalWait );
206
207     mLoopCount = count;
208   }
209 }
210
211 int32_t VectorRasterizeThread::GetLoopCount() const
212 {
213   return mLoopCount;
214 }
215
216 void VectorRasterizeThread::SetPlayRange( Vector2 range )
217 {
218   // Make sure the range specified is between 0.0 and 1.0
219   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
220   {
221     Vector2 orderedRange( range );
222     // If the range is not in order swap values
223     if( range.x > range.y )
224     {
225       orderedRange = Vector2( range.y, range.x );
226     }
227
228     if( mPlayRange != orderedRange )
229     {
230       ConditionalWait::ScopedLock lock( mConditionalWait );
231
232       mPlayRange = orderedRange;
233
234       mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
235       mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
236
237       // If the current frame is out of the range, change the current frame also.
238       if( mStartFrame > mCurrentFrame )
239       {
240         mCurrentFrame = mStartFrame;
241
242         mCurrentFrameUpdated = true;
243         mResourceReady = false;
244       }
245       else if( mEndFrame < mCurrentFrame )
246       {
247         mCurrentFrame = mEndFrame;
248
249         mCurrentFrameUpdated = true;
250         mResourceReady = false;
251       }
252     }
253   }
254 }
255
256 Vector2 VectorRasterizeThread::GetPlayRange() const
257 {
258   return mPlayRange;
259 }
260
261 void VectorRasterizeThread::SetCurrentProgress( float progress )
262 {
263   ConditionalWait::ScopedLock lock( mConditionalWait );
264
265   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
266   {
267     mProgress = progress;
268
269     mCurrentFrame = static_cast< uint32_t >( mTotalFrame * progress + 0.5f );
270     mCurrentFrameUpdated = true;
271
272     mResourceReady = false;
273
274     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentProgress: progress = %f (%d)\n", progress, mCurrentFrame );
275   }
276 }
277
278 float VectorRasterizeThread::GetCurrentProgress() const
279 {
280   return ( static_cast< float >( mCurrentFrame ) / static_cast< float >( mTotalFrame ) );
281 }
282
283 void VectorRasterizeThread::GetDefaultSize( uint32_t& width, uint32_t& height ) const
284 {
285   mVectorRenderer.GetDefaultSize( width, height );
286 }
287
288 DevelImageVisual::PlayState VectorRasterizeThread::GetPlayState() const
289 {
290   return mPlayState;
291 }
292
293 bool VectorRasterizeThread::IsResourceReady() const
294 {
295   return mResourceReady;
296 }
297
298 void VectorRasterizeThread::Initialize()
299 {
300   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
301
302   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
303
304   mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
305   mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
306
307   mCurrentFrame = std::max( static_cast< uint32_t >( mTotalFrame * mProgress + 0.5f ), mStartFrame );
308
309   mFrameRate = mVectorRenderer.GetFrameRate();
310   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
311
312   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Initialize: file = %s [%d frames, %f fps]\n", mUrl.c_str(), mTotalFrame, mFrameRate );
313 }
314
315 void VectorRasterizeThread::Rasterize()
316 {
317   bool resourceReady;
318   uint32_t currentFrame, startFrame, endFrame;
319   int32_t loopCount;
320   DevelImageVisual::PlayState playState;
321
322   {
323     ConditionalWait::ScopedLock lock( mConditionalWait );
324
325     if( mPlayState != DevelImageVisual::PlayState::PLAYING && !mNeedRender && !mDestroyThread )
326     {
327       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Wait\n" );
328
329       if( mPlayState == DevelImageVisual::PlayState::STOPPED )
330       {
331         // Reset the current loop
332         mCurrentLoop = 0;
333       }
334       mConditionalWait.Wait( lock );
335     }
336
337     resourceReady = mResourceReady;
338     currentFrame = mCurrentFrame++;
339     startFrame = mStartFrame;
340     endFrame = mEndFrame;
341     loopCount = mLoopCount;
342     playState = mPlayState;
343
344     mNeedRender = false;
345     mResourceReady = true;
346     mCurrentFrameUpdated = false;
347   }
348
349   auto currentFrameStartTime = std::chrono::system_clock::now();
350
351   // Rasterize
352   mVectorRenderer.Render( currentFrame );
353
354   if( playState == DevelImageVisual::PlayState::PLAYING )
355   {
356     if( currentFrame >= endFrame )
357     {
358       if( loopCount < 0 )
359       {
360         // repeat forever
361         ResetToStart( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
362       }
363       else
364       {
365         mCurrentLoop++;
366         if( mCurrentLoop >= loopCount )
367         {
368           mPlayState = DevelImageVisual::PlayState::STOPPED;
369
370           // Animation is finished
371           mAnimationFinishedTrigger->Trigger();
372
373           DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished\n" );
374         }
375         else
376         {
377           ResetToStart( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );
378         }
379       }
380     }
381   }
382
383   if( !resourceReady )
384   {
385     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
386
387     mResourceReadyTrigger->Trigger();
388   }
389
390   auto timeToSleepUntil = currentFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds );
391
392 #if defined(DEBUG_ENABLED)
393   auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( timeToSleepUntil - std::chrono::system_clock::now() );
394
395   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [current = %d, sleep duration = %lld]\n", mCurrentFrame, sleepDuration.count() );
396 #endif
397
398   std::this_thread::sleep_until( timeToSleepUntil );
399 }
400
401 } // namespace Internal
402
403 } // namespace Toolkit
404
405 } // namespace Dali