X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fanimated-vector-image%2Fvector-rasterize-thread.cpp;h=2c393335a7716e34464e6b61144b8cefa9412b72;hp=52c65414f5cef8016a84e69b2118bd0c2694b1fe;hb=52f294c7dc6b1bbd3265489a2d8f70659ed88931;hpb=88164ac28facfc414392d99ff5d1cbcd4f9e9d2c diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.cpp b/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.cpp index 52c6541..2c39333 100644 --- a/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.cpp +++ b/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ #include #include #include - -// INTERNAL INCLUDES +#include +#include namespace Dali { @@ -38,36 +38,54 @@ namespace { constexpr auto LOOP_FOREVER = -1; +constexpr auto NANOSECONDS_PER_SECOND( 1e+9 ); #if defined(DEBUG_ENABLED) Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" ); #endif +template< typename T > +inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait ) +{ + ConditionalWait::ScopedLock lock( conditionalWait ); + if( !updated ) + { + value = newValue; + updated = true; + } +} + } // unnamed namespace -VectorRasterizeThread::VectorRasterizeThread( const std::string& url, Renderer renderer, uint32_t width, uint32_t height ) +VectorRasterizeThread::VectorRasterizeThread( const std::string& url ) : mUrl( url ), mVectorRenderer(), mConditionalWait(), - mMutex(), - mResourceReadyTrigger( NULL ), - mPlayRange( 0.0f, 1.0f ), + mAnimationFinishedTrigger(), + mPlayState( PlayState::STOPPED ), + mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ), + mLoopingMode( DevelImageVisual::LoopingMode::RESTART ), + mFrameDurationNanoSeconds( 0 ), + mFrameRate( 60.0f ), mCurrentFrame( 0 ), mTotalFrame( 0 ), mStartFrame( 0 ), mEndFrame( 0 ), - mWidth( width ), - mHeight( height ), + mWidth( 0 ), + mHeight( 0 ), mLoopCount( LOOP_FOREVER ), mCurrentLoop( 0 ), mNeedRender( false ), - mPlaying( false ), - mPaused( false ), mDestroyThread( false ), mResourceReady( false ), + mCurrentFrameUpdated( false ), + mCurrentLoopUpdated( false ), + mForward( true ), + mUpdateFrameNumber( false ), + mNeedAnimationFinishedTrigger( true ), mLogFactory( Dali::Adaptor::Get().GetLogFactory() ) { - mVectorRenderer = VectorAnimationRenderer::New( mUrl, renderer, width, height ); + Initialize(); } VectorRasterizeThread::~VectorRasterizeThread() @@ -77,16 +95,11 @@ VectorRasterizeThread::~VectorRasterizeThread() ConditionalWait::ScopedLock lock( mConditionalWait ); mDestroyThread = true; mConditionalWait.Notify( lock ); - - // This should be called in the main thread to stop waiting for the dequeuable buffer. - mVectorRenderer.StopRender(); } - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join\n" ); + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join [%p]\n", this ); Join(); - - delete mResourceReadyTrigger; } void VectorRasterizeThread::Run() @@ -94,189 +107,423 @@ void VectorRasterizeThread::Run() SetThreadName( "VectorImageThread" ); mLogFactory.InstallLogFunction(); - //TODO: check the return value - StartRender(); - - while( IsThreadReady() ) + while( !mDestroyThread ) { Rasterize(); } + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Run: End of thread [%p]\n", this ); } -void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height ) +void VectorRasterizeThread::SetRenderer( Renderer renderer ) { ConditionalWait::ScopedLock lock( mConditionalWait ); - mVectorRenderer.SetSize( width, height ); - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height ); + mVectorRenderer.SetRenderer( renderer ); + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer [%p]\n", this ); } -void VectorRasterizeThread::StartAnimation() +void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height ) +{ + if( mWidth != width || mHeight != height ) + { + ConditionalWait::ScopedLock lock( mConditionalWait ); + mVectorRenderer.SetSize( width, height ); + + mWidth = width; + mHeight = height; + + mResourceReady = false; + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d [%p]\n", width, height, this ); + } +} + +void VectorRasterizeThread::PlayAnimation() { ConditionalWait::ScopedLock lock( mConditionalWait ); - if( !mPlaying ) + + if( mPlayState != PlayState::PLAYING ) { - mPlaying = true; - mPaused = false; + mNeedRender = true; + mUpdateFrameNumber = false; + mPlayState = PlayState::PLAYING; mConditionalWait.Notify( lock ); - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartAnimation: Start\n" ); + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Play [%p]\n", this ); } } void VectorRasterizeThread::StopAnimation() { ConditionalWait::ScopedLock lock( mConditionalWait ); - if( mPlaying ) + if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING ) { - mPlaying = false; - mPaused = false; + mNeedRender = true; + mNeedAnimationFinishedTrigger = false; + mPlayState = PlayState::STOPPING; + mConditionalWait.Notify( lock ); - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" ); + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop [%p]\n", this ); } } void VectorRasterizeThread::PauseAnimation() { ConditionalWait::ScopedLock lock( mConditionalWait ); - if( mPlaying && !mPaused ) + if( mPlayState == PlayState::PLAYING ) { - mPaused = true; + mPlayState = PlayState::PAUSED; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" ); + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause [%p]\n", this ); } } -void VectorRasterizeThread::ResumeAnimation() +void VectorRasterizeThread::RenderFrame() { ConditionalWait::ScopedLock lock( mConditionalWait ); - if( mPlaying && mPaused ) + + if( !mResourceReady ) { - mPaused = false; + mNeedRender = true; mConditionalWait.Notify( lock ); - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::ResumeAnimation: Resume\n" ); + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render [%p]\n", this ); } } -void VectorRasterizeThread::RenderFrame() +void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback ) { ConditionalWait::ScopedLock lock( mConditionalWait ); - mNeedRender = true; - mConditionalWait.Notify( lock ); + mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback ); +} - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" ); +void VectorRasterizeThread::SetLoopCount( int32_t count ) +{ + if( mLoopCount != count ) + { + ConditionalWait::ScopedLock lock( mConditionalWait ); + + mLoopCount = count; + mCurrentLoop = 0; + mCurrentLoopUpdated = true; + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetLoopCount: [%d] [%p]\n", count, this ); + } } -void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback ) +void VectorRasterizeThread::SetPlayRange( uint32_t startFrame, uint32_t endFrame ) { - ConditionalWait::ScopedLock lock( mConditionalWait ); - mResourceReadyTrigger = callback; + // Make sure the range specified is between 0 and the total frame number + if( ( startFrame < mTotalFrame ) && ( endFrame < mTotalFrame ) ) + { + // If the range is not in order swap values + if( startFrame > endFrame ) + { + uint32_t temp = startFrame; + startFrame = endFrame; + endFrame = temp; + } + + if( startFrame != mStartFrame || endFrame != mEndFrame ) + { + ConditionalWait::ScopedLock lock( mConditionalWait ); + + mStartFrame = startFrame; + mEndFrame = endFrame; + + // If the current frame is out of the range, change the current frame also. + if( mStartFrame > mCurrentFrame ) + { + mCurrentFrame = mStartFrame; + + mCurrentFrameUpdated = true; + mResourceReady = false; + } + else if( mEndFrame < mCurrentFrame ) + { + mCurrentFrame = mEndFrame; + + mCurrentFrameUpdated = true; + mResourceReady = false; + } + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this ); + } + } } -void VectorRasterizeThread::SetLoopCount( int16_t count ) +DevelImageVisual::PlayState::Type VectorRasterizeThread::GetPlayState() const { - ConditionalWait::ScopedLock lock( mConditionalWait ); + DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED; - mLoopCount = count; + switch( mPlayState ) + { + case PlayState::PLAYING: + { + state = DevelImageVisual::PlayState::PLAYING; + break; + } + case PlayState::PAUSED: + { + state = DevelImageVisual::PlayState::PAUSED; + break; + } + case PlayState::STOPPING: + case PlayState::STOPPED: + { + state = DevelImageVisual::PlayState::STOPPED; + break; + } + } + + return state; +} - // Reset progress - mCurrentLoop = 0; - mCurrentFrame = mStartFrame; +bool VectorRasterizeThread::IsResourceReady() const +{ + return mResourceReady; } -void VectorRasterizeThread::SetPlayRange( Vector2 range ) +void VectorRasterizeThread::SetCurrentFrameNumber( uint32_t frameNumber ) { ConditionalWait::ScopedLock lock( mConditionalWait ); - mPlayRange = range; + if( mCurrentFrame == frameNumber ) + { + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this ); + return; + } - if( mTotalFrame != 0 ) + if( frameNumber >= mStartFrame && frameNumber <= mEndFrame ) { - mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f ); - mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f ); + mCurrentFrame = frameNumber; + mCurrentFrameUpdated = true; + + mResourceReady = false; + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this ); } + else + { + DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame ); + } +} + +uint32_t VectorRasterizeThread::GetCurrentFrameNumber() const +{ + return mCurrentFrame; +} + +uint32_t VectorRasterizeThread::GetTotalFrameNumber() const +{ + return mTotalFrame; +} + +void VectorRasterizeThread::GetDefaultSize( uint32_t& width, uint32_t& height ) const +{ + mVectorRenderer.GetDefaultSize( width, height ); } -bool VectorRasterizeThread::IsThreadReady() +void VectorRasterizeThread::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior ) { ConditionalWait::ScopedLock lock( mConditionalWait ); + mStopBehavior = stopBehavior; - if( ( !mPlaying || mPaused ) && !mNeedRender && !mDestroyThread ) - { - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::IsThreadReady: Wait\n" ); + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this ); +} - if( !mPlaying ) - { - mCurrentFrame = mStartFrame; - mCurrentLoop = 0; - } +void VectorRasterizeThread::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode ) +{ + ConditionalWait::ScopedLock lock( mConditionalWait ); + mLoopingMode = loopingMode; - mConditionalWait.Wait( lock ); - } + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this ); +} - // Keep the thread alive if this thread is NOT to be destroyed - return !mDestroyThread; +VectorRasterizeThread::UploadCompletedSignalType& VectorRasterizeThread::UploadCompletedSignal() +{ + return mVectorRenderer.UploadCompletedSignal(); } -bool VectorRasterizeThread::StartRender() +void VectorRasterizeThread::Initialize() { - //TODO: check the return value - mVectorRenderer.StartRender(); + mVectorRenderer = VectorAnimationRenderer::New( mUrl ); mTotalFrame = mVectorRenderer.GetTotalFrameNumber(); - mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f ); - mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f ); + mEndFrame = mTotalFrame - 1; + + mFrameRate = mVectorRenderer.GetFrameRate(); + mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate; - mCurrentFrame = mStartFrame; + uint32_t width, height; + mVectorRenderer.GetDefaultSize( width, height ); - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d (%d, %d)]\n", mTotalFrame, mStartFrame, mEndFrame ); + SetSize( width, height ); - return true; + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this ); } void VectorRasterizeThread::Rasterize() { - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [%d]\n", mCurrentFrame ); + bool stopped = false, needAnimationFinishedTrigger; + uint32_t currentFrame, startFrame, endFrame; + int32_t loopCount, currentLoopCount; - // Rasterize - mVectorRenderer.Render( mCurrentFrame ); + { + ConditionalWait::ScopedLock lock( mConditionalWait ); - if( mPlaying && !mPaused ) + if( ( mPlayState == PlayState::PAUSED || mPlayState == PlayState::STOPPED ) && !mNeedRender && !mDestroyThread ) + { + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Wait [%p]\n", this ); + mConditionalWait.Wait( lock ); + } + + if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber ) + { + mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1; + } + + currentFrame = mCurrentFrame; + startFrame = mStartFrame; + endFrame = mEndFrame; + loopCount = mLoopCount; + currentLoopCount = mCurrentLoop; + needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger; + + mResourceReady = true; + mNeedRender = false; + mCurrentFrameUpdated = false; + mCurrentLoopUpdated = false; + mUpdateFrameNumber = true; + mNeedAnimationFinishedTrigger = true; + } + + auto currentFrameStartTime = std::chrono::system_clock::now(); + + if( mPlayState == PlayState::STOPPING ) { - if( ++mCurrentFrame >= mEndFrame ) + currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame ); + ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait ); + + stopped = true; + } + else if( mPlayState == PlayState::PLAYING ) + { + bool animationFinished = false; + + if( currentFrame >= endFrame ) // last frame { - if( mLoopCount < 0 ) + if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE ) { - // repeat forever - mCurrentFrame = mStartFrame; + mForward = false; } else { - mCurrentLoop++; - if( mCurrentLoop >= mLoopCount ) + if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop { - // Animation is finished - mPlaying = false; + ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait ); // If the current frame is changed in the event thread, don't overwrite it. + mUpdateFrameNumber = false; } else { - mCurrentFrame = mStartFrame; + animationFinished = true; // end of animation } + ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait ); + } + } + else if( currentFrame == startFrame && !mForward ) // first frame + { + if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop + { + mForward = true; + } + else + { + animationFinished = true; // end of animation + } + ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait ); + } + + if( animationFinished ) + { + if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME ) + { + stopped = true; + } + else + { + mPlayState = PlayState::STOPPING; } } } - mNeedRender = false; + // Rasterize + if( !mVectorRenderer.Render( currentFrame ) ) + { + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this ); + mUpdateFrameNumber = false; + } - if( !mResourceReady ) + if( stopped ) { - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" ); + mPlayState = PlayState::STOPPED; + mForward = true; + mCurrentLoop = 0; - mResourceReadyTrigger->Trigger(); - mResourceReady = true; + // Animation is finished + if( needAnimationFinishedTrigger ) + { + mAnimationFinishedTrigger->Trigger(); + } + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this ); } + + auto timeToSleepUntil = currentFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ); + +#if defined(DEBUG_ENABLED) + auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( timeToSleepUntil - std::chrono::system_clock::now() ); + + DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [current = %d, sleep duration = %lld] [%p]\n", currentFrame, sleepDuration.count(), this ); +#endif + + std::this_thread::sleep_until( timeToSleepUntil ); +} + +uint32_t VectorRasterizeThread::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame ) +{ + uint32_t frame = currentFrame; + + switch( mStopBehavior ) + { + case DevelImageVisual::StopBehavior::FIRST_FRAME: + { + frame = startFrame; + break; + } + case DevelImageVisual::StopBehavior::LAST_FRAME: + { + if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE ) + { + frame = startFrame; + } + else + { + frame = endFrame; + } + break; + } + case DevelImageVisual::StopBehavior::CURRENT_FRAME: + { + frame = currentFrame; + break; + } + } + + return frame; } } // namespace Internal