Append Stopped animation notify list at Update Animation time 45/307245/6
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 6 Mar 2024 09:01:41 +0000 (18:01 +0900)
committerEunki Hong <eunkiki.hong@samsung.com>
Mon, 18 Mar 2024 02:35:45 +0000 (02:35 +0000)
Let we insert animation notification list at Animate() time, instead of
immediate.

This will make insure we will not notify signal for destroyed, cleared animation.
And it will increase performance minor.

Change-Id: I5371be63c36787874e9ae850e14e5796c5f819b1
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali/utc-Dali-Animation.cpp
dali/internal/update/animation/scene-graph-animation.cpp
dali/internal/update/animation/scene-graph-animation.h
dali/internal/update/manager/update-manager.cpp

index 489b906..f360cbd 100644 (file)
@@ -3308,7 +3308,7 @@ int UtcDaliAnimationStopEmitFinishedSignalImmediateP(void)
     application.SendNotification();
     application.Render(0);
 
-    // expect finished signal recieved due to Stop API.
+    // expect finished signal not recieved.
     application.SendNotification();
     finishCheck.CheckSignalNotReceived();
     finishCheck.Reset();
@@ -3327,7 +3327,7 @@ int UtcDaliAnimationStopEmitFinishedSignalImmediateP(void)
     application.SendNotification();
     application.Render(0);
 
-    // expect finished signal recieved due to Stop API.
+    // expect finished signal not recieved.
     application.SendNotification();
     finishCheck.CheckSignalNotReceived();
     finishCheck.Reset();
@@ -3406,6 +3406,90 @@ int UtcDaliAnimationClearP(void)
   END_TEST;
 }
 
+int UtcDaliAnimationClearIgnoreFinishedSignal(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  application.GetScene().Add(actor);
+
+  // Build the animation
+  float     durationSeconds(1.0f);
+  Animation animation = Animation::New(durationSeconds);
+  Vector3   targetPosition(100.0f, 100.0f, 100.0f);
+  animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+  Vector3 fiftyPercentProgress(targetPosition * 0.5f);
+
+  // Start the animation
+  animation.Play();
+
+  bool                 signalReceived(false);
+  AnimationFinishCheck finishCheck(signalReceived);
+  animation.FinishedSignal().Connect(&application, finishCheck);
+
+  // Check finished signal not emmited if animation was cleared.
+  {
+    tet_printf("Check whether stop and clear case didnt send finished signal\n");
+    // Play the animation, and stop after animation finished naturally, and clear.
+    animation.Play();
+
+    application.SendNotification();
+
+    animation.Stop();
+    animation.Clear();
+
+    application.SendNotification();
+    finishCheck.CheckSignalNotReceived();
+    finishCheck.Reset();
+
+    // Finish animation naturally. (Note that dali don't call finished callback even if one render frame spend more than duration.)
+    application.Render(static_cast<uint32_t>(durationSeconds * 500.0f));
+    application.Render(static_cast<uint32_t>(durationSeconds * 500.0f) + 10u);
+    application.SendNotification();
+
+    // expect finished signal not recieved.
+    finishCheck.CheckSignalNotReceived();
+    finishCheck.Reset();
+
+    application.SendNotification();
+    application.Render(0);
+  }
+  {
+    tet_printf("Check whether stop and clear and render-well case send finished signal\n");
+    // Play the animation, and stop after animation finished naturally, and clear, and play again.
+    animation.PlayAfter(durationSeconds);
+
+    application.SendNotification();
+
+    // delay 50%.
+    application.Render(static_cast<uint32_t>(durationSeconds * 500.0f));
+
+    animation.Stop();
+    animation.Clear();
+    animation.Play();
+
+    application.SendNotification();
+    finishCheck.CheckSignalNotReceived();
+    finishCheck.Reset();
+
+    // Finish animation naturally. (Note that dali don't call finished callback even if one render frame spend more than duration.)
+    application.Render(static_cast<uint32_t>(durationSeconds * 500.0f));
+    application.Render(static_cast<uint32_t>(durationSeconds * 500.0f) + 10u);
+    application.SendNotification();
+
+    // expect finished signal recieved due to Animation finished.
+    application.SendNotification();
+    finishCheck.CheckSignalReceived();
+    finishCheck.Reset();
+
+    application.SendNotification();
+    application.Render(0);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliAnimationEmptyAnimatorAndLoopCount(void)
 {
   // Clear and play the empty animation, and get the state values.
index 8530da2..1392a21 100644 (file)
@@ -170,7 +170,8 @@ void Animation::Play()
   // Let we don't change current loop value if the state was paused.
   if(mState != Paused)
   {
-    mCurrentLoop = 0;
+    mCurrentLoop  = 0;
+    mDelaySeconds = 0.0f;
   }
   mState = Playing;
 
@@ -192,7 +193,8 @@ void Animation::PlayFrom(float progress)
     // Let we don't change current loop value if the state was paused.
     if(mState != Paused)
     {
-      mCurrentLoop = 0;
+      mCurrentLoop  = 0;
+      mDelaySeconds = 0.0f;
     }
     mState = Playing;
 
@@ -261,6 +263,7 @@ bool Animation::Stop(BufferIndex bufferIndex)
   if(mState == Playing || mState == Paused)
   {
     animationFinished = true; // The actor-thread should be notified of this
+    mIsStopped        = true;
 
     if(mEndAction != Dali::Animation::DISCARD)
     {
@@ -278,6 +281,7 @@ bool Animation::Stop(BufferIndex bufferIndex)
     mCurrentLoop = 0;
   }
 
+  mDelaySeconds   = 0.0f;
   mElapsedSeconds = mPlayRange.x * mDurationSeconds;
   mState          = Stopped;
   mIsFirstLoop    = true;
@@ -285,7 +289,7 @@ bool Animation::Stop(BufferIndex bufferIndex)
   return animationFinished;
 }
 
-void Animation::Clear(BufferIndex bufferIndex)
+void Animation::ClearAnimator(BufferIndex bufferIndex)
 {
   // Stop animation immediatly.
   Stop(bufferIndex);
@@ -295,6 +299,7 @@ void Animation::Clear(BufferIndex bufferIndex)
   mAnimatorSortRequired = false;
 
   // Reset animation state values.
+  mIsStopped   = false; ///< Do not make notify.
   mPlayedCount = 0;
   mCurrentLoop = 0;
 }
@@ -315,7 +320,8 @@ void Animation::OnDestroy(BufferIndex bufferIndex)
     }
   }
 
-  mState = Destroyed;
+  mIsStopped = false; ///< Do not make notify.
+  mState     = Destroyed;
 }
 
 void Animation::SetLoopingMode(bool loopingMode)
@@ -349,9 +355,12 @@ void Animation::AddAnimator(OwnerPointer<AnimatorBase>& animator)
   mAnimators.PushBack(animator.Release());
 }
 
-void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished, bool& progressReached)
+void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& stopped, bool& finished, bool& progressReached)
 {
-  looped   = false;
+  // Reset mIsStopped flag now.
+  stopped    = mIsStopped;
+  mIsStopped = false;
+
   finished = false;
 
   // Short circuit when animation isn't running
@@ -402,7 +411,7 @@ void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& loop
     float markerFactor  = signSpeedFactor * mProgressMarker;
 
     // check it is looped
-    looped = (elapsedFactor > edgeFactor);
+    const bool looped = (elapsedFactor > edgeFactor);
 
     if(looped)
     {
index 40cf2a3..869fe2f 100644 (file)
@@ -232,10 +232,10 @@ public:
   bool Stop(BufferIndex bufferIndex);
 
   /**
-   * Clear the animation. It will clear all animator, and make this animation never played before.
+   * Clear the animator. It will stop animation, clear all animators, and make this animation never played before.
    * @param[in] bufferIndex The buffer to update when mEndAction == Bake.
    */
-  void Clear(BufferIndex bufferIndex);
+  void ClearAnimator(BufferIndex bufferIndex);
 
   /**
    * Called shortly before the animation is destroyed.
@@ -302,11 +302,11 @@ public:
    * @pre The animation is playing or paused.
    * @param[in] bufferIndex The buffer to update.
    * @param[in] elapsedSeconds The time elapsed since the previous frame.
-   * @param[out] looped True if the animation looped
+   * @param[out] stopped True if the animation stopped this loop
    * @param[out] finished True if the animation has finished.
    * @param[out] progressReached True if progress marker reached
    */
-  void Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished, bool& progressReached);
+  void Update(BufferIndex bufferIndex, float elapsedSeconds, bool& stopped, bool& finished, bool& progressReached);
 
   static uint32_t GetMemoryPoolCapacity();
 
@@ -372,6 +372,7 @@ protected:
   bool mAnimatorSortRequired;          // Flag to whether we need to sort animator or not.
   bool mIsActive[2];                   // Flag to indicate whether the animation is active in the current frame (which is double buffered)
   bool mIsFirstLoop;
+  bool mIsStopped; // Flag to whether this animation call stoped by user at this frame.
 };
 
 }; // namespace SceneGraph
@@ -495,6 +496,7 @@ inline void PlayAnimationMessage(EventThreadServices& eventThreadServices, const
   // Construct message in the message queue memory; note that delete should not be called on the return value
   new(slot) LocalType(&animation, &Animation::Play);
 }
+
 inline void PlayAnimationFromMessage(EventThreadServices& eventThreadServices, const Animation& animation, float progress)
 {
   using LocalType = MessageValue1<Animation, float>;
index d7771cc..7a971f5 100644 (file)
@@ -590,9 +590,6 @@ void UpdateManager::StopAnimation(Animation* animation)
 
   bool animationFinished = animation->Stop(mSceneGraphBuffers.GetUpdateBufferIndex());
 
-  // Queue this animation into notify required animations. Since we need to send Finished signal
-  mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId());
-
   mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || animationFinished;
 }
 
@@ -600,11 +597,7 @@ void UpdateManager::ClearAnimation(Animation* animation)
 {
   DALI_ASSERT_DEBUG(animation && "NULL animation called to clear");
 
-  animation->Clear(mSceneGraphBuffers.GetUpdateBufferIndex());
-
-  // We should remove all notify lists what we requests before clear.
-  // TODO : Could we do this more faster?
-  Dali::EraseIf(mImpl->notifyRequiredAnimations, [&animation](const NotifierInterface::NotifyId& key) { return key == animation->GetNotifyId(); });
+  animation->ClearAnimator(mSceneGraphBuffers.GetUpdateBufferIndex());
 }
 
 void UpdateManager::RemoveAnimation(Animation* animation)
@@ -830,7 +823,6 @@ bool UpdateManager::ProcessGestures(BufferIndex bufferIndex, uint32_t lastVSyncT
 bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds)
 {
   bool animationActive = false;
-  bool animationLooped = false;
 
   auto&& iter = mImpl->animations.Begin();
 
@@ -838,9 +830,9 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds)
   {
     Animation* animation             = *iter;
     bool       finished              = false;
-    bool       looped                = false;
+    bool       stopped               = false;
     bool       progressMarkerReached = false;
-    animation->Update(bufferIndex, elapsedSeconds, looped, finished, progressMarkerReached);
+    animation->Update(bufferIndex, elapsedSeconds, stopped, finished, progressMarkerReached);
 
     animationActive = animationActive || animation->IsActive();
 
@@ -850,10 +842,9 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds)
     }
 
     mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
-    animationLooped                      = animationLooped || looped;
 
-    // queue the notification on finished or stoped
-    if(finished)
+    // queue the notification on finished or stopped
+    if(finished || stopped)
     {
       mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId());
     }