Merge "Add right shift handling for text controller" into 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 #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   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
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   //TODO: check the return value
109   StartRender();
110
111   while( !mDestroyThread )
112   {
113     Rasterize();
114   }
115 }
116
117 void VectorRasterizeThread::SetRenderer( Renderer renderer )
118 {
119   ConditionalWait::ScopedLock lock( mConditionalWait );
120
121   mVectorRenderer.SetRenderer( renderer );
122
123   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer\n" );
124 }
125
126 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
127 {
128   if( mWidth != width || mHeight != height )
129   {
130     ConditionalWait::ScopedLock lock( mConditionalWait );
131     mVectorRenderer.SetSize( width, height );
132
133     mWidth = width;
134     mHeight = height;
135
136     mResourceReady = false;
137
138     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height );
139   }
140 }
141
142 void VectorRasterizeThread::PlayAnimation()
143 {
144   ConditionalWait::ScopedLock lock( mConditionalWait );
145   if( mPlayState != DevelImageVisual::PlayState::PLAYING )
146   {
147     mPlayState = DevelImageVisual::PlayState::PLAYING;
148     mConditionalWait.Notify( lock );
149
150     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Start\n" );
151   }
152 }
153
154 void VectorRasterizeThread::StopAnimation()
155 {
156   ConditionalWait::ScopedLock lock( mConditionalWait );
157   if( mPlayState != DevelImageVisual::PlayState::STOPPED )
158   {
159     mPlayState = DevelImageVisual::PlayState::STOPPED;
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       if( mTotalFrame != 0 )
235       {
236         mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
237         mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
238
239         // If the current frame is out of the range, change the current frame also.
240         if( mStartFrame > mCurrentFrame )
241         {
242           mCurrentFrame = mStartFrame;
243
244           mCurrentFrameUpdated = true;
245           mResourceReady = false;
246         }
247         else if( mEndFrame < mCurrentFrame )
248         {
249           mCurrentFrame = mEndFrame;
250
251           mCurrentFrameUpdated = true;
252           mResourceReady = false;
253         }
254       }
255     }
256   }
257 }
258
259 Vector2 VectorRasterizeThread::GetPlayRange() const
260 {
261   return mPlayRange;
262 }
263
264 void VectorRasterizeThread::SetCurrentProgress( float progress )
265 {
266   ConditionalWait::ScopedLock lock( mConditionalWait );
267
268   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
269   {
270     mProgress = progress;
271
272     if( mTotalFrame != 0 )
273     {
274       mCurrentFrame = static_cast< uint32_t >( mTotalFrame * progress + 0.5f );
275       mCurrentFrameUpdated = true;
276     }
277
278     mResourceReady = false;
279
280     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentProgress: progress = %f (%d)\n", progress, mCurrentFrame );
281   }
282 }
283
284 float VectorRasterizeThread::GetCurrentProgress() const
285 {
286   return ( static_cast< float >( mCurrentFrame ) / static_cast< float >( mTotalFrame ) );
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 bool VectorRasterizeThread::StartRender()
300 {
301   //TODO: check the return value
302   mVectorRenderer.StartRender();
303
304   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
305
306   mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
307   mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
308
309   mCurrentFrame = std::max( static_cast< uint32_t >( mTotalFrame * mProgress + 0.5f ), mStartFrame );
310
311   mFrameRate = mVectorRenderer.GetFrameRate();
312   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
313
314   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d, %f fps]\n", mTotalFrame, mFrameRate );
315
316   return true;
317 }
318
319 void VectorRasterizeThread::Rasterize()
320 {
321   bool resourceReady;
322   uint32_t currentFrame, startFrame, endFrame;
323   int32_t loopCount;
324   DevelImageVisual::PlayState playState;
325
326   {
327     ConditionalWait::ScopedLock lock( mConditionalWait );
328
329     if( mPlayState != DevelImageVisual::PlayState::PLAYING && !mNeedRender && !mDestroyThread )
330     {
331       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Wait\n" );
332
333       if( mPlayState == DevelImageVisual::PlayState::STOPPED )
334       {
335         // Reset the current frame and the current loop
336         mCurrentFrame = mStartFrame;
337         mCurrentLoop = 0;
338       }
339       mConditionalWait.Wait( lock );
340     }
341
342     resourceReady = mResourceReady;
343     currentFrame = mCurrentFrame++;
344     startFrame = mStartFrame;
345     endFrame = mEndFrame;
346     loopCount = mLoopCount;
347     playState = mPlayState;
348
349     mNeedRender = false;
350     mResourceReady = true;
351     mCurrentFrameUpdated = false;
352   }
353
354   auto currentFrameStartTime = std::chrono::system_clock::now();
355
356   // Rasterize
357   mVectorRenderer.Render( currentFrame );
358
359   if( playState == DevelImageVisual::PlayState::PLAYING )
360   {
361     if( currentFrame >= endFrame )
362     {
363       if( loopCount < 0 )
364       {
365         // repeat forever
366         ResetToStart( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
367       }
368       else
369       {
370         mCurrentLoop++;
371         if( mCurrentLoop >= loopCount )
372         {
373           mPlayState = DevelImageVisual::PlayState::STOPPED;
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", mCurrentFrame, 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