[dali_1.4.10] Merge branch 'devel/master'
[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
26 // INTERNAL INCLUDES
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
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 VectorRasterizeThread::VectorRasterizeThread( const std::string& url )
49 : mUrl( url ),
50   mVectorRenderer(),
51   mConditionalWait(),
52   mMutex(),
53   mResourceReadyTrigger(),
54   mAnimationFinishedTrigger(),
55   mPlayRange( 0.0f, 1.0f ),
56   mPlayState( DevelImageVisual::PlayState::STOPPED ),
57   mProgress( 0.0f ),
58   mCurrentFrame( 0 ),
59   mTotalFrame( 0 ),
60   mStartFrame( 0 ),
61   mEndFrame( 0 ),
62   mWidth( 0 ),
63   mHeight( 0 ),
64   mLoopCount( LOOP_FOREVER ),
65   mCurrentLoop( 0 ),
66   mNeedRender( false ),
67   mDestroyThread( false ),
68   mResourceReady( false ),
69   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
70 {
71   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
72 }
73
74 VectorRasterizeThread::~VectorRasterizeThread()
75 {
76   // Stop the thread
77   {
78     ConditionalWait::ScopedLock lock( mConditionalWait );
79     mDestroyThread = true;
80     mConditionalWait.Notify( lock );
81
82     // This should be called in the main thread to stop waiting for the dequeuable buffer.
83     mVectorRenderer.StopRender();
84   }
85
86   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join\n" );
87
88   Join();
89 }
90
91 void VectorRasterizeThread::Run()
92 {
93   SetThreadName( "VectorImageThread" );
94   mLogFactory.InstallLogFunction();
95
96   //TODO: check the return value
97   StartRender();
98
99   while( IsThreadReady() )
100   {
101     Rasterize();
102   }
103 }
104
105 void VectorRasterizeThread::SetRenderer( Renderer renderer )
106 {
107   ConditionalWait::ScopedLock lock( mConditionalWait );
108
109   mVectorRenderer.SetRenderer( renderer );
110
111   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer\n" );
112 }
113
114 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
115 {
116   if( mWidth != width || mHeight != height )
117   {
118     ConditionalWait::ScopedLock lock( mConditionalWait );
119     mVectorRenderer.SetSize( width, height );
120
121     mWidth = width;
122     mHeight = height;
123
124     mResourceReady = false;
125
126     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height );
127   }
128 }
129
130 void VectorRasterizeThread::PlayAnimation()
131 {
132   ConditionalWait::ScopedLock lock( mConditionalWait );
133   if( mPlayState != DevelImageVisual::PlayState::PLAYING )
134   {
135     mPlayState = DevelImageVisual::PlayState::PLAYING;
136     mConditionalWait.Notify( lock );
137
138     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Start\n" );
139   }
140 }
141
142 void VectorRasterizeThread::StopAnimation()
143 {
144   ConditionalWait::ScopedLock lock( mConditionalWait );
145   if( mPlayState != DevelImageVisual::PlayState::STOPPED )
146   {
147     mPlayState = DevelImageVisual::PlayState::STOPPED;
148
149     // Reset the current frame and the current loop
150     mCurrentFrame = mStartFrame;
151     mCurrentLoop = 0;
152
153     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
154   }
155 }
156
157 void VectorRasterizeThread::PauseAnimation()
158 {
159   ConditionalWait::ScopedLock lock( mConditionalWait );
160   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
161   {
162     mPlayState = DevelImageVisual::PlayState::PAUSED;
163
164     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" );
165   }
166 }
167
168 void VectorRasterizeThread::RenderFrame()
169 {
170   ConditionalWait::ScopedLock lock( mConditionalWait );
171
172   if( !mResourceReady )
173   {
174     mNeedRender = true;
175     mConditionalWait.Notify( lock );
176
177     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
178   }
179 }
180
181 void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
182 {
183   ConditionalWait::ScopedLock lock( mConditionalWait );
184   mResourceReadyTrigger = std::unique_ptr< EventThreadCallback >( callback );
185 }
186
187 void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback )
188 {
189   ConditionalWait::ScopedLock lock( mConditionalWait );
190   mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
191 }
192
193 void VectorRasterizeThread::SetLoopCount( int32_t count )
194 {
195   if( mLoopCount != count )
196   {
197     ConditionalWait::ScopedLock lock( mConditionalWait );
198
199     mLoopCount = count;
200
201     // Reset progress
202     mCurrentLoop = 0;
203   }
204 }
205
206 int32_t VectorRasterizeThread::GetLoopCount() const
207 {
208   return mLoopCount;
209 }
210
211 void VectorRasterizeThread::SetPlayRange( Vector2 range )
212 {
213   // Make sure the range specified is between 0.0 and 1.0
214   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
215   {
216     Vector2 orderedRange( range );
217     // If the range is not in order swap values
218     if( range.x > range.y )
219     {
220       orderedRange = Vector2( range.y, range.x );
221     }
222
223     if( mPlayRange != orderedRange )
224     {
225       ConditionalWait::ScopedLock lock( mConditionalWait );
226
227       mPlayRange = orderedRange;
228
229       if( mTotalFrame != 0 )
230       {
231         mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
232         mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
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           mResourceReady = false;
240         }
241         else if( mEndFrame < mCurrentFrame )
242         {
243           mCurrentFrame = mEndFrame;
244
245           mResourceReady = false;
246         }
247       }
248     }
249   }
250 }
251
252 Vector2 VectorRasterizeThread::GetPlayRange() const
253 {
254   return mPlayRange;
255 }
256
257 void VectorRasterizeThread::SetCurrentProgress( float progress )
258 {
259   ConditionalWait::ScopedLock lock( mConditionalWait );
260
261   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
262   {
263     mProgress = progress;
264
265     if( mTotalFrame != 0 )
266     {
267       mCurrentFrame = static_cast< uint32_t >( mTotalFrame * progress + 0.5f );
268     }
269
270     mResourceReady = false;
271
272     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentProgress: progress = %f (%d)\n", progress, mCurrentFrame );
273   }
274 }
275
276 float VectorRasterizeThread::GetCurrentProgress() const
277 {
278   return ( static_cast< float >( mCurrentFrame ) / static_cast< float >( mTotalFrame ) );
279 }
280
281 DevelImageVisual::PlayState VectorRasterizeThread::GetPlayState() const
282 {
283   return mPlayState;
284 }
285
286 bool VectorRasterizeThread::IsResourceReady() const
287 {
288   return mResourceReady;
289 }
290
291 bool VectorRasterizeThread::IsThreadReady()
292 {
293   ConditionalWait::ScopedLock lock( mConditionalWait );
294
295   if( mPlayState != DevelImageVisual::PlayState::PLAYING && !mNeedRender && !mDestroyThread )
296   {
297     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::IsThreadReady: Wait\n" );
298
299     mConditionalWait.Wait( lock );
300   }
301
302   // Keep the thread alive if this thread is NOT to be destroyed
303   return !mDestroyThread;
304 }
305
306 bool VectorRasterizeThread::StartRender()
307 {
308   //TODO: check the return value
309   mVectorRenderer.StartRender();
310
311   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
312
313   mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
314   mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
315
316   mCurrentFrame = std::max( static_cast< uint32_t >( mTotalFrame * mProgress + 0.5f ), mStartFrame );
317
318   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d (%d, %d)]\n", mTotalFrame, mStartFrame, mEndFrame );
319
320   return true;
321 }
322
323 void VectorRasterizeThread::Rasterize()
324 {
325   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [%d]\n", mCurrentFrame );
326
327   bool needRender, resourceReady;
328
329   {
330     ConditionalWait::ScopedLock lock( mConditionalWait );
331     needRender = mNeedRender;
332     resourceReady = mResourceReady;
333   }
334
335   // Rasterize
336   mVectorRenderer.Render( mCurrentFrame );
337
338   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
339   {
340     if( ++mCurrentFrame >= mEndFrame )
341     {
342       if( mLoopCount < 0 )
343       {
344         // repeat forever
345         mCurrentFrame = mStartFrame;
346       }
347       else
348       {
349         mCurrentLoop++;
350         if( mCurrentLoop >= mLoopCount )
351         {
352           // Animation is finished
353           mPlayState = DevelImageVisual::PlayState::STOPPED;
354
355           // Reset the current frame and the current loop
356           mCurrentFrame = mStartFrame;
357           mCurrentLoop = 0;
358
359           mAnimationFinishedTrigger->Trigger();
360
361           DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished\n" );
362         }
363         else
364         {
365           mCurrentFrame = mStartFrame;
366         }
367       }
368     }
369   }
370
371   if( needRender )
372   {
373     mNeedRender = false;
374   }
375
376   if( !resourceReady )
377   {
378     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
379
380     mResourceReadyTrigger->Trigger();
381     mResourceReady = true;
382   }
383 }
384
385 } // namespace Internal
386
387 } // namespace Toolkit
388
389 } // namespace Dali