(Vector) Use one EventThreadCallback 79/294279/1
authorHeeyong Song <heeyong.song@samsung.com>
Tue, 13 Jun 2023 07:33:48 +0000 (16:33 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Thu, 15 Jun 2023 09:02:05 +0000 (18:02 +0900)
EventThreadCallback uses an fd internally and some systems have a limit on the number of fd.
So reduce the number of fd

Change-Id: I55f6e7f5211d0bc567a1b2362c782e9fc2a74b90

automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h

index 92cc203..6a5a089 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -974,8 +974,7 @@ int UtcDaliAnimatedVectorImageVisualAnimationFinishedSignal(void)
 
   Property::Map propertyMap;
   propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
-    .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
-    .Add(DevelImageVisual::Property::LOOP_COUNT, 3);
+    .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME);
 
   Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
   DALI_TEST_CHECK(visual);
@@ -991,14 +990,24 @@ int UtcDaliAnimatedVectorImageVisualAnimationFinishedSignal(void)
 
   application.GetScene().Add(actor);
 
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - render a frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  propertyMap.Clear();
+  propertyMap.Add(DevelImageVisual::Property::LOOP_COUNT, 3);
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, propertyMap);
+
   Property::Map attributes;
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
 
   application.SendNotification();
   application.Render();
 
-  // Wait for animation finish - render, finish
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+  // Wait for animation finish
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   Property::Map    map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
   Property::Value* value = map.Find(DevelImageVisual::Property::PLAY_STATE);
@@ -1269,8 +1278,6 @@ int UtcDaliAnimatedVectorImageVisualStopBehavior(void)
   Property::Map propertyMap;
   propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
     .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
-    .Add(DevelImageVisual::Property::LOOP_COUNT, 3)
-    .Add(DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::FIRST_FRAME)
     .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
 
   Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
@@ -1285,14 +1292,25 @@ int UtcDaliAnimatedVectorImageVisualStopBehavior(void)
 
   application.GetScene().Add(actor);
 
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 2 - load & render a frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  propertyMap.Clear();
+  propertyMap.Add(DevelImageVisual::Property::LOOP_COUNT, 3);
+  propertyMap.Add(DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::FIRST_FRAME);
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, propertyMap);
+
   Property::Map attributes;
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
 
   application.SendNotification();
   application.Render();
 
-  // Trigger count is 3 - load, render, animation finished
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   Property::Map    map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
   Property::Value* value = map.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER);
@@ -1377,9 +1395,6 @@ int UtcDaliAnimatedVectorImageVisualLoopingMode(void)
   Property::Map propertyMap;
   propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
     .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
-    .Add(DevelImageVisual::Property::LOOP_COUNT, 3)
-    .Add(DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME)
-    .Add(DevelImageVisual::Property::LOOPING_MODE, DevelImageVisual::LoopingMode::AUTO_REVERSE)
     .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
 
   Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
@@ -1394,14 +1409,26 @@ int UtcDaliAnimatedVectorImageVisualLoopingMode(void)
 
   application.GetScene().Add(actor);
 
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 2 - load, render
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  propertyMap.Clear();
+  propertyMap.Add(DevelImageVisual::Property::LOOP_COUNT, 3);
+  propertyMap.Add(DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME);
+  propertyMap.Add(DevelImageVisual::Property::LOOPING_MODE, DevelImageVisual::LoopingMode::AUTO_REVERSE);
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, propertyMap);
+
   Property::Map attributes;
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
 
   application.SendNotification();
   application.Render();
 
-  // Trigger count is 3 - load, render, animation finished
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   Property::Map    map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
   Property::Value* value = map.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER);
@@ -1566,6 +1593,12 @@ int UtcDaliAnimatedVectorImageVisualMultipleInstances(void)
 
   application.GetScene().Add(actor1);
 
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 2 - load & render a frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
   propertyMap.Clear();
   propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
     .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
@@ -1585,8 +1618,8 @@ int UtcDaliAnimatedVectorImageVisualMultipleInstances(void)
   application.SendNotification();
   application.Render();
 
-  // Trigger count is 4 - load & render a frame for each instance
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(4), true, TEST_LOCATION);
+  // Trigger count is 2 - load & render a frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
 
   DevelControl::DoAction(actor2, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, Property::Map());
 
index 5d987b9..8a4ada9 100644 (file)
@@ -377,7 +377,7 @@ void AnimatedVectorImageVisual::DoSetProperty(Property::Index index, const Prope
 void AnimatedVectorImageVisual::OnInitialize(void)
 {
   mVectorAnimationTask->ResourceReadySignal().Connect(this, &AnimatedVectorImageVisual::OnResourceReady);
-  mVectorAnimationTask->SetAnimationFinishedCallback(new EventThreadCallback(MakeCallback(this, &AnimatedVectorImageVisual::OnAnimationFinished)));
+  mVectorAnimationTask->SetAnimationFinishedCallback(MakeCallback(this, &AnimatedVectorImageVisual::OnAnimationFinished));
 
   mVectorAnimationTask->RequestLoad(mUrl.GetUrl(), IsSynchronousLoadingRequired());
 
index 40f1a64..6d4b2ef 100644 (file)
@@ -53,8 +53,7 @@ VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
   mVectorAnimationThread(factoryCache.GetVectorAnimationManager().GetVectorAnimationThread()),
   mConditionalWait(),
   mResourceReadySignal(),
-  mAnimationFinishedTrigger(),
-  mLoadCompletedTrigger(new EventThreadCallback(MakeCallback(this, &VectorAnimationTask::OnLoadCompleted))),
+  mLoadCompletedCallback(MakeCallback(this, &VectorAnimationTask::OnLoadCompleted)),
   mPlayState(PlayState::STOPPED),
   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
   mLoopingMode(DevelImageVisual::LoopingMode::RESTART),
@@ -104,13 +103,13 @@ void VectorAnimationTask::Finalize()
   ConditionalWait::ScopedLock lock(mConditionalWait);
 
   // Release some objects in the main thread
-  if(mAnimationFinishedTrigger)
+  if(mAnimationFinishedCallback)
   {
-    mAnimationFinishedTrigger.reset();
+    mVectorAnimationThread.RemoveEventTriggerCallback(mAnimationFinishedCallback.get());
   }
-  if(mLoadCompletedTrigger)
+  if(mLoadCompletedCallback)
   {
-    mLoadCompletedTrigger.reset();
+    mVectorAnimationThread.RemoveEventTriggerCallback(mLoadCompletedCallback.get());
   }
 
   mVectorRenderer.Finalize();
@@ -142,7 +141,7 @@ bool VectorAnimationTask::Load(bool synchronousLoading)
     mLoadFailed  = true;
     if(!synchronousLoading)
     {
-      mLoadCompletedTrigger->Trigger();
+      mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get());
     }
     return false;
   }
@@ -157,7 +156,7 @@ bool VectorAnimationTask::Load(bool synchronousLoading)
   mLoadRequest = false;
   if(!synchronousLoading)
   {
-    mLoadCompletedTrigger->Trigger();
+    mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get());
   }
 
   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Load: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this);
@@ -263,13 +262,10 @@ void VectorAnimationTask::PauseAnimation()
   }
 }
 
-void VectorAnimationTask::SetAnimationFinishedCallback(EventThreadCallback* callback)
+void VectorAnimationTask::SetAnimationFinishedCallback(CallbackBase* callback)
 {
   ConditionalWait::ScopedLock lock(mConditionalWait);
-  if(callback)
-  {
-    mAnimationFinishedTrigger = std::unique_ptr<EventThreadCallback>(callback);
-  }
+  mAnimationFinishedCallback = std::unique_ptr<CallbackBase>(callback);
 }
 
 void VectorAnimationTask::SetLoopCount(int32_t count)
@@ -547,9 +543,9 @@ bool VectorAnimationTask::Rasterize()
     // Animation is finished
     {
       ConditionalWait::ScopedLock lock(mConditionalWait);
-      if(mNeedAnimationFinishedTrigger && mAnimationFinishedTrigger)
+      if(mNeedAnimationFinishedTrigger && mAnimationFinishedCallback)
       {
-        mAnimationFinishedTrigger->Trigger();
+        mVectorAnimationThread.AddEventTriggerCallback(mAnimationFinishedCallback.get());
       }
     }
 
index 0b2c43e..e1b80c3 100644 (file)
@@ -181,7 +181,7 @@ public:
    * @brief This callback is called after the animation is finished.
    * @param[in] callback The animation finished callback
    */
-  void SetAnimationFinishedCallback(EventThreadCallback* callback);
+  void SetAnimationFinishedCallback(CallbackBase* callback);
 
   /**
    * @brief Gets the playing range in frame number.
@@ -361,8 +361,8 @@ private:
   VectorAnimationThread&               mVectorAnimationThread;
   ConditionalWait                      mConditionalWait;
   ResourceReadySignalType              mResourceReadySignal;
-  std::unique_ptr<EventThreadCallback> mAnimationFinishedTrigger;
-  std::unique_ptr<EventThreadCallback> mLoadCompletedTrigger;
+  std::unique_ptr<CallbackBase>        mAnimationFinishedCallback{};
+  std::unique_ptr<CallbackBase>        mLoadCompletedCallback{};
   PlayState                            mPlayState;
   DevelImageVisual::StopBehavior::Type mStopBehavior;
   DevelImageVisual::LoopingMode::Type  mLoopingMode;
index 02198f0..08b52d6 100644 (file)
@@ -51,6 +51,8 @@ VectorAnimationThread::VectorAnimationThread()
 {
   mAsyncTaskManager = Dali::AsyncTaskManager::Get();
   mSleepThread.Start();
+
+  mEventTrigger = std::unique_ptr<EventThreadCallback>(new EventThreadCallback(MakeCallback(this, &VectorAnimationThread::OnEventCallbackTriggered)));
 }
 
 VectorAnimationThread::~VectorAnimationThread()
@@ -148,6 +150,28 @@ void VectorAnimationThread::OnAwakeFromSleep()
   }
 }
 
+void VectorAnimationThread::AddEventTriggerCallback(CallbackBase* callback)
+{
+  ConditionalWait::ScopedLock lock(mConditionalWait);
+  mTriggerEventCallbacks.push_back(callback);
+
+  if(!mEventTriggered)
+  {
+    mEventTrigger->Trigger();
+    mEventTriggered = true;
+  }
+}
+
+void VectorAnimationThread::RemoveEventTriggerCallback(CallbackBase* callback)
+{
+  ConditionalWait::ScopedLock lock(mConditionalWait);
+  auto                        iter = std::find(mTriggerEventCallbacks.begin(), mTriggerEventCallbacks.end(), callback);
+  if(iter != mTriggerEventCallbacks.end())
+  {
+    mTriggerEventCallbacks.erase(iter);
+  }
+}
+
 void VectorAnimationThread::Run()
 {
   SetThreadName("VectorAnimationThread");
@@ -237,6 +261,19 @@ void VectorAnimationThread::Rasterize()
   }
 }
 
+void VectorAnimationThread::OnEventCallbackTriggered()
+{
+  ConditionalWait::ScopedLock lock(mConditionalWait);
+
+  for(auto&& iter : mTriggerEventCallbacks)
+  {
+    CallbackBase::Execute(*iter);
+  }
+
+  mTriggerEventCallbacks.clear();
+  mEventTriggered = false;
+}
+
 VectorAnimationThread::SleepThread::SleepThread(CallbackBase* callback)
 : mConditionalWait(),
   mAwakeCallback(std::unique_ptr<CallbackBase>(callback)),
index 0fd37e4..79d1a48 100644 (file)
@@ -51,7 +51,7 @@ public:
   ~VectorAnimationThread() override;
 
   /**
-   * Add a animation task into the vector animation thread, called by main thread.
+   * @brief Add a animation task into the vector animation thread, called by main thread.
    *
    * @param[in] task The task added to the thread.
    */
@@ -59,6 +59,7 @@ public:
 
   /**
    * @brief Called when the rasterization is completed from the rasterize thread.
+   *
    * @param[in] task The completed task
    * @param[in] success true if the task succeeded, false otherwise.
    * @param[in] keepAnimation true if the animation is running, false otherwise.
@@ -70,6 +71,22 @@ public:
    */
   void OnAwakeFromSleep();
 
+  /**
+   * @brief Add an event trigger callback.
+   *
+   * @param callback The callback to add
+   * @note Ownership of the callback is NOT passed onto this class.
+   * @note The callback will be excuted in the main thread.
+   */
+  void AddEventTriggerCallback(CallbackBase* callback);
+
+  /**
+   * @brief Remove an event trigger callback.
+   *
+   * @param callback The callback to remove
+   */
+  void RemoveEventTriggerCallback(CallbackBase* callback);
+
 protected:
   /**
    * @brief The entry function of the animation thread.
@@ -83,6 +100,11 @@ private:
   void Rasterize();
 
   /**
+   * @brief Called when the event callback is triggered.
+   */
+  void OnEventCallbackTriggered();
+
+  /**
    * @brief The thread to sleep until the next frame time.
    */
   class SleepThread : public Thread
@@ -130,15 +152,18 @@ private:
   VectorAnimationThread& operator=(const VectorAnimationThread& thread) = delete;
 
 private:
-  std::vector<VectorAnimationTaskPtr> mAnimationTasks;
-  std::vector<VectorAnimationTaskPtr> mCompletedTasks;
-  std::vector<VectorAnimationTaskPtr> mWorkingTasks;
-  SleepThread                         mSleepThread;
-  ConditionalWait                     mConditionalWait;
-  bool                                mNeedToSleep;
-  bool                                mDestroyThread;
-  const Dali::LogFactoryInterface&    mLogFactory;
-  Dali::AsyncTaskManager              mAsyncTaskManager;
+  std::vector<VectorAnimationTaskPtr>  mAnimationTasks;
+  std::vector<VectorAnimationTaskPtr>  mCompletedTasks;
+  std::vector<VectorAnimationTaskPtr>  mWorkingTasks;
+  std::vector<CallbackBase*>           mTriggerEventCallbacks{}; // Callbacks are not owned
+  SleepThread                          mSleepThread;
+  ConditionalWait                      mConditionalWait;
+  std::unique_ptr<EventThreadCallback> mEventTrigger{};
+  bool                                 mNeedToSleep;
+  bool                                 mDestroyThread;
+  bool                                 mEventTriggered{false};
+  const Dali::LogFactoryInterface&     mLogFactory;
+  Dali::AsyncTaskManager               mAsyncTaskManager;
 };
 
 } // namespace Internal