[dali_2.3.22] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-animation-thread.cpp
index 97634f6..5638ec3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -33,19 +33,6 @@ namespace Internal
 {
 namespace
 {
-constexpr auto DEFAULT_NUMBER_OF_RASTERIZE_THREADS = size_t{4u};
-constexpr auto NUMBER_OF_RASTERIZE_THREADS_ENV     = "DALI_VECTOR_RASTERIZE_THREADS";
-
-size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
-{
-  using Dali::EnvironmentVariable::GetEnvironmentVariable;
-  auto           numberString          = GetEnvironmentVariable(environmentVariable);
-  auto           numberOfThreads       = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
-  constexpr auto MAX_NUMBER_OF_THREADS = 100u;
-  DALI_ASSERT_DEBUG(numberOfThreads < MAX_NUMBER_OF_THREADS);
-  return (numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS) ? numberOfThreads : defaultValue;
-}
-
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
 #endif
@@ -56,14 +43,20 @@ VectorAnimationThread::VectorAnimationThread()
 : mAnimationTasks(),
   mCompletedTasks(),
   mWorkingTasks(),
-  mRasterizers(GetNumberOfThreads(NUMBER_OF_RASTERIZE_THREADS_ENV, DEFAULT_NUMBER_OF_RASTERIZE_THREADS), [&]() { return RasterizeHelper(*this); }),
   mSleepThread(MakeCallback(this, &VectorAnimationThread::OnAwakeFromSleep)),
   mConditionalWait(),
+  mEventTriggerMutex(),
+  mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
   mNeedToSleep(false),
   mDestroyThread(false),
-  mLogFactory(Dali::Adaptor::Get().GetLogFactory())
+  mEventTriggered(false),
+  mForceRenderOnce(false)
 {
+  mAsyncTaskManager = Dali::AsyncTaskManager::Get();
   mSleepThread.Start();
+
+  mEventTrigger = std::unique_ptr<EventThreadCallback>(new EventThreadCallback(MakeCallback(this, &VectorAnimationThread::OnEventCallbackTriggered)));
 }
 
 VectorAnimationThread::~VectorAnimationThread()
@@ -71,11 +64,18 @@ VectorAnimationThread::~VectorAnimationThread()
   // Stop the thread
   {
     ConditionalWait::ScopedLock lock(mConditionalWait);
-    mDestroyThread = true;
-    mNeedToSleep   = false;
+    // Wait until some event thread trigger relative job finished.
+    {
+      Mutex::ScopedLock lock(mEventTriggerMutex);
+      mDestroyThread = true;
+    }
+    mNeedToSleep = false;
     mConditionalWait.Notify(lock);
   }
 
+  // Stop event trigger
+  mEventTrigger.reset();
+
   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::~VectorAnimationThread: Join [%p]\n", this);
 
   Join();
@@ -85,7 +85,9 @@ void VectorAnimationThread::AddTask(VectorAnimationTaskPtr task)
 {
   ConditionalWait::ScopedLock lock(mConditionalWait);
 
-  if(mAnimationTasks.end() == std::find(mAnimationTasks.begin(), mAnimationTasks.end(), task))
+  // Find if the task is already in the list except loading task
+  auto iter = std::find_if(mAnimationTasks.begin(), mAnimationTasks.end(), [task](VectorAnimationTaskPtr& element) { return (element == task && !element->IsLoadRequested()); });
+  if(iter == mAnimationTasks.end())
   {
     auto currentTime = task->CalculateNextFrameTime(true); // Rasterize as soon as possible
 
@@ -112,7 +114,7 @@ void VectorAnimationThread::AddTask(VectorAnimationTaskPtr task)
   }
 }
 
-void VectorAnimationThread::OnTaskCompleted(VectorAnimationTaskPtr task, bool keepAnimation)
+void VectorAnimationThread::OnTaskCompleted(VectorAnimationTaskPtr task, bool success, bool keepAnimation)
 {
   if(!mDestroyThread)
   {
@@ -131,7 +133,7 @@ void VectorAnimationThread::OnTaskCompleted(VectorAnimationTaskPtr task, bool ke
       needRasterize = true;
     }
 
-    if(keepAnimation)
+    if(keepAnimation && success)
     {
       if(mCompletedTasks.end() == std::find(mCompletedTasks.begin(), mCompletedTasks.end(), task))
       {
@@ -159,10 +161,51 @@ void VectorAnimationThread::OnAwakeFromSleep()
   }
 }
 
+void VectorAnimationThread::AddEventTriggerCallback(CallbackBase* callback, uint32_t argument)
+{
+  Mutex::ScopedLock lock(mEventTriggerMutex);
+  if(!mDestroyThread)
+  {
+    mTriggerEventCallbacks.emplace_back(callback, argument);
+
+    if(!mEventTriggered)
+    {
+      mEventTrigger->Trigger();
+      mEventTriggered = true;
+    }
+  }
+}
+
+void VectorAnimationThread::RemoveEventTriggerCallbacks(CallbackBase* callback)
+{
+  Mutex::ScopedLock lock(mEventTriggerMutex);
+  if(!mDestroyThread)
+  {
+    auto iter = std::remove_if(mTriggerEventCallbacks.begin(), mTriggerEventCallbacks.end(), [&callback](std::pair<CallbackBase*, uint32_t>& item) { return item.first == callback; });
+    mTriggerEventCallbacks.erase(iter, mTriggerEventCallbacks.end());
+  }
+}
+
+void VectorAnimationThread::RequestForceRenderOnce()
+{
+  Mutex::ScopedLock lock(mEventTriggerMutex);
+  if(!mDestroyThread)
+  {
+    mForceRenderOnce = true;
+
+    if(!mEventTriggered)
+    {
+      mEventTrigger->Trigger();
+      mEventTriggered = true;
+    }
+  }
+}
+
 void VectorAnimationThread::Run()
 {
   SetThreadName("VectorAnimationThread");
   mLogFactory.InstallLogFunction();
+  mTraceFactory.InstallTraceFunction();
 
   while(!mDestroyThread)
   {
@@ -220,11 +263,10 @@ void VectorAnimationThread::Rasterize()
     auto nextFrameTime = nextTask->GetNextFrameTime();
 
 #if defined(DEBUG_ENABLED)
-    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(nextFrameTime - currentTime);
+//    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(nextFrameTime - currentTime);
 
-    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::Rasterize: [next time = %lld]\n", duration.count());
+//    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::Rasterize: [next time = %lld]\n", duration.count());
 #endif
-
     if(nextFrameTime <= currentTime)
     {
       // If the task is not in the working list
@@ -234,11 +276,7 @@ void VectorAnimationThread::Rasterize()
 
         // Add it to the working list
         mWorkingTasks.push_back(nextTask);
-
-        auto rasterizerHelperIt = mRasterizers.GetNext();
-        DALI_ASSERT_ALWAYS(rasterizerHelperIt != mRasterizers.End());
-
-        rasterizerHelperIt->Rasterize(nextTask);
+        mAsyncTaskManager.AddTask(nextTask);
       }
       else
       {
@@ -253,29 +291,46 @@ void VectorAnimationThread::Rasterize()
   }
 }
 
-VectorAnimationThread::RasterizeHelper::RasterizeHelper(VectorAnimationThread& animationThread)
-: RasterizeHelper(std::unique_ptr<VectorRasterizeThread>(new VectorRasterizeThread()), animationThread)
-{
-}
-
-VectorAnimationThread::RasterizeHelper::RasterizeHelper(RasterizeHelper&& rhs)
-: RasterizeHelper(std::move(rhs.mRasterizer), rhs.mAnimationThread)
-{
-}
-
-VectorAnimationThread::RasterizeHelper::RasterizeHelper(std::unique_ptr<VectorRasterizeThread> rasterizer, VectorAnimationThread& animationThread)
-: mRasterizer(std::move(rasterizer)),
-  mAnimationThread(animationThread)
+void VectorAnimationThread::OnEventCallbackTriggered()
 {
-  mRasterizer->SetCompletedCallback(MakeCallback(&mAnimationThread, &VectorAnimationThread::OnTaskCompleted));
+  while(true)
+  {
+    auto callbackPair = GetNextEventCallback();
+    if(callbackPair.first == nullptr)
+    {
+      break;
+    }
+    CallbackBase::Execute(*callbackPair.first, callbackPair.second);
+  }
+  // Request update once if we need.
+  {
+    Mutex::ScopedLock lock(mEventTriggerMutex);
+    if(!mDestroyThread && mForceRenderOnce)
+    {
+      mForceRenderOnce = false;
+      if(Dali::Adaptor::IsAvailable())
+      {
+        Dali::Adaptor::Get().UpdateOnce();
+      }
+    }
+  }
 }
 
-void VectorAnimationThread::RasterizeHelper::Rasterize(VectorAnimationTaskPtr task)
+std::pair<CallbackBase*, uint32_t> VectorAnimationThread::GetNextEventCallback()
 {
-  if(task)
+  Mutex::ScopedLock lock(mEventTriggerMutex);
+  if(!mDestroyThread)
   {
-    mRasterizer->AddTask(task);
+    if(!mTriggerEventCallbacks.empty())
+    {
+      auto iter           = mTriggerEventCallbacks.begin();
+      auto callbackIdPair = *iter;
+      mTriggerEventCallbacks.erase(iter);
+      return callbackIdPair;
+    }
+    mEventTriggered = false;
   }
+  return std::make_pair(nullptr, 0u);
 }
 
 VectorAnimationThread::SleepThread::SleepThread(CallbackBase* callback)
@@ -283,6 +338,7 @@ VectorAnimationThread::SleepThread::SleepThread(CallbackBase* callback)
   mAwakeCallback(std::unique_ptr<CallbackBase>(callback)),
   mSleepTimePoint(),
   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
   mNeedToSleep(false),
   mDestroyThread(false)
 {
@@ -312,6 +368,7 @@ void VectorAnimationThread::SleepThread::Run()
 {
   SetThreadName("VectorSleepThread");
   mLogFactory.InstallLogFunction();
+  mTraceFactory.InstallTraceFunction();
 
   while(!mDestroyThread)
   {
@@ -330,9 +387,9 @@ void VectorAnimationThread::SleepThread::Run()
     if(needToSleep)
     {
 #if defined(DEBUG_ENABLED)
-      auto sleepDuration = std::chrono::duration_cast<std::chrono::milliseconds>(mSleepTimePoint - std::chrono::steady_clock::now());
+//      auto sleepDuration = std::chrono::duration_cast<std::chrono::milliseconds>(mSleepTimePoint - std::chrono::steady_clock::now());
 
-      DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::SleepThread::Run: [sleep duration = %lld]\n", sleepDuration.count());
+//      DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::SleepThread::Run: [sleep duration = %lld]\n", sleepDuration.count());
 #endif
 
       std::this_thread::sleep_until(sleepTimePoint);