2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h>
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>
40 constexpr auto LOOP_FOREVER = -1;
41 constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
43 #if defined(DEBUG_ENABLED)
44 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
47 } // unnamed namespace
49 VectorRasterizeThread::VectorRasterizeThread( const std::string& url )
54 mResourceReadyTrigger(),
55 mAnimationFinishedTrigger(),
56 mPlayRange( 0.0f, 1.0f ),
57 mPlayState( DevelImageVisual::PlayState::STOPPED ),
58 mFrameDurationNanoSeconds( 0 ),
67 mLoopCount( LOOP_FOREVER ),
70 mDestroyThread( false ),
71 mResourceReady( false ),
72 mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
74 mVectorRenderer = VectorAnimationRenderer::New( mUrl );
77 VectorRasterizeThread::~VectorRasterizeThread()
81 ConditionalWait::ScopedLock lock( mConditionalWait );
82 mDestroyThread = true;
83 mConditionalWait.Notify( lock );
85 // This should be called in the main thread to stop waiting for the dequeuable buffer.
86 mVectorRenderer.StopRender();
89 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join\n" );
94 void VectorRasterizeThread::Run()
96 SetThreadName( "VectorImageThread" );
97 mLogFactory.InstallLogFunction();
99 //TODO: check the return value
102 while( IsThreadReady() )
108 void VectorRasterizeThread::SetRenderer( Renderer renderer )
110 ConditionalWait::ScopedLock lock( mConditionalWait );
112 mVectorRenderer.SetRenderer( renderer );
114 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer\n" );
117 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
119 if( mWidth != width || mHeight != height )
121 ConditionalWait::ScopedLock lock( mConditionalWait );
122 mVectorRenderer.SetSize( width, height );
127 mResourceReady = false;
129 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height );
133 void VectorRasterizeThread::PlayAnimation()
135 ConditionalWait::ScopedLock lock( mConditionalWait );
136 if( mPlayState != DevelImageVisual::PlayState::PLAYING )
138 mPlayState = DevelImageVisual::PlayState::PLAYING;
139 mConditionalWait.Notify( lock );
141 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Start\n" );
145 void VectorRasterizeThread::StopAnimation()
147 ConditionalWait::ScopedLock lock( mConditionalWait );
148 if( mPlayState != DevelImageVisual::PlayState::STOPPED )
150 mPlayState = DevelImageVisual::PlayState::STOPPED;
152 // Reset the current frame and the current loop
153 mCurrentFrame = mStartFrame;
156 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
160 void VectorRasterizeThread::PauseAnimation()
162 ConditionalWait::ScopedLock lock( mConditionalWait );
163 if( mPlayState == DevelImageVisual::PlayState::PLAYING )
165 mPlayState = DevelImageVisual::PlayState::PAUSED;
167 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" );
171 void VectorRasterizeThread::RenderFrame()
173 ConditionalWait::ScopedLock lock( mConditionalWait );
175 if( !mResourceReady )
178 mConditionalWait.Notify( lock );
180 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
184 void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
186 ConditionalWait::ScopedLock lock( mConditionalWait );
187 mResourceReadyTrigger = std::unique_ptr< EventThreadCallback >( callback );
190 void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback )
192 ConditionalWait::ScopedLock lock( mConditionalWait );
193 mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
196 void VectorRasterizeThread::SetLoopCount( int32_t count )
198 if( mLoopCount != count )
200 ConditionalWait::ScopedLock lock( mConditionalWait );
209 int32_t VectorRasterizeThread::GetLoopCount() const
214 void VectorRasterizeThread::SetPlayRange( Vector2 range )
216 // Make sure the range specified is between 0.0 and 1.0
217 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
219 Vector2 orderedRange( range );
220 // If the range is not in order swap values
221 if( range.x > range.y )
223 orderedRange = Vector2( range.y, range.x );
226 if( mPlayRange != orderedRange )
228 ConditionalWait::ScopedLock lock( mConditionalWait );
230 mPlayRange = orderedRange;
232 if( mTotalFrame != 0 )
234 mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
235 mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
237 // If the current frame is out of the range, change the current frame also.
238 if( mStartFrame > mCurrentFrame )
240 mCurrentFrame = mStartFrame;
242 mResourceReady = false;
244 else if( mEndFrame < mCurrentFrame )
246 mCurrentFrame = mEndFrame;
248 mResourceReady = false;
255 Vector2 VectorRasterizeThread::GetPlayRange() const
260 void VectorRasterizeThread::SetCurrentProgress( float progress )
262 ConditionalWait::ScopedLock lock( mConditionalWait );
264 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
266 mProgress = progress;
268 if( mTotalFrame != 0 )
270 mCurrentFrame = static_cast< uint32_t >( mTotalFrame * progress + 0.5f );
273 mResourceReady = false;
275 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentProgress: progress = %f (%d)\n", progress, mCurrentFrame );
279 float VectorRasterizeThread::GetCurrentProgress() const
281 return ( static_cast< float >( mCurrentFrame ) / static_cast< float >( mTotalFrame ) );
284 DevelImageVisual::PlayState VectorRasterizeThread::GetPlayState() const
289 bool VectorRasterizeThread::IsResourceReady() const
291 return mResourceReady;
294 bool VectorRasterizeThread::IsThreadReady()
296 ConditionalWait::ScopedLock lock( mConditionalWait );
298 if( mPlayState != DevelImageVisual::PlayState::PLAYING && !mNeedRender && !mDestroyThread )
300 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::IsThreadReady: Wait\n" );
302 mConditionalWait.Wait( lock );
305 // Keep the thread alive if this thread is NOT to be destroyed
306 return !mDestroyThread;
309 bool VectorRasterizeThread::StartRender()
311 //TODO: check the return value
312 mVectorRenderer.StartRender();
314 mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
316 mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
317 mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
319 mCurrentFrame = std::max( static_cast< uint32_t >( mTotalFrame * mProgress + 0.5f ), mStartFrame );
321 mFrameRate = mVectorRenderer.GetFrameRate();
322 mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
324 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d, %f fps]\n", mTotalFrame, mFrameRate );
329 void VectorRasterizeThread::Rasterize()
331 bool needRender, resourceReady;
334 ConditionalWait::ScopedLock lock( mConditionalWait );
335 needRender = mNeedRender;
336 resourceReady = mResourceReady;
339 auto currentFrameStartTime = std::chrono::system_clock::now();
342 mVectorRenderer.Render( mCurrentFrame );
344 if( mPlayState == DevelImageVisual::PlayState::PLAYING )
346 if( ++mCurrentFrame >= mEndFrame )
351 mCurrentFrame = mStartFrame;
356 if( mCurrentLoop >= mLoopCount )
358 // Animation is finished
359 mPlayState = DevelImageVisual::PlayState::STOPPED;
361 // Reset the current frame and the current loop
362 mCurrentFrame = mStartFrame;
365 mAnimationFinishedTrigger->Trigger();
367 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished\n" );
371 mCurrentFrame = mStartFrame;
384 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
386 mResourceReadyTrigger->Trigger();
387 mResourceReady = true;
390 auto timeToSleepUntil = currentFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds );
392 #if defined(DEBUG_ENABLED)
393 auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( timeToSleepUntil - std::chrono::system_clock::now() );
395 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [current = %d, sleep duration = %lld]\n", mCurrentFrame, sleepDuration.count() );
398 std::this_thread::sleep_until( timeToSleepUntil );
401 } // namespace Internal
403 } // namespace Toolkit