2 * Copyright (c) 2024 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-animation-thread.h>
22 #include <dali/devel-api/adaptor-framework/environment-variable.h>
23 #include <dali/devel-api/adaptor-framework/thread-settings.h>
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/integration-api/debug.h>
36 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
40 } // unnamed namespace
42 VectorAnimationThread::VectorAnimationThread()
46 mSleepThread(MakeCallback(this, &VectorAnimationThread::OnAwakeFromSleep)),
50 mDestroyThread(false),
51 mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
52 mTraceFactory(Dali::Adaptor::Get().GetTraceFactory())
54 mAsyncTaskManager = Dali::AsyncTaskManager::Get();
57 mEventTrigger = std::unique_ptr<EventThreadCallback>(new EventThreadCallback(MakeCallback(this, &VectorAnimationThread::OnEventCallbackTriggered)));
60 VectorAnimationThread::~VectorAnimationThread()
64 ConditionalWait::ScopedLock lock(mConditionalWait);
65 // Wait until some event thread trigger relative job finished.
67 Mutex::ScopedLock lock(mEventTriggerMutex);
68 mDestroyThread = true;
71 mConditionalWait.Notify(lock);
75 mEventTrigger.reset();
77 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::~VectorAnimationThread: Join [%p]\n", this);
82 void VectorAnimationThread::AddTask(VectorAnimationTaskPtr task)
84 ConditionalWait::ScopedLock lock(mConditionalWait);
86 // Find if the task is already in the list except loading task
87 auto iter = std::find_if(mAnimationTasks.begin(), mAnimationTasks.end(), [task](VectorAnimationTaskPtr& element) { return (element == task && !element->IsLoadRequested()); });
88 if(iter == mAnimationTasks.end())
90 auto currentTime = task->CalculateNextFrameTime(true); // Rasterize as soon as possible
92 bool inserted = false;
93 for(auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter)
95 auto nextTime = (*iter)->GetNextFrameTime();
96 if(nextTime > currentTime)
98 mAnimationTasks.insert(iter, task);
106 mAnimationTasks.push_back(task);
109 mNeedToSleep = false;
110 // wake up the animation thread
111 mConditionalWait.Notify(lock);
115 void VectorAnimationThread::OnTaskCompleted(VectorAnimationTaskPtr task, bool success, bool keepAnimation)
119 ConditionalWait::ScopedLock lock(mConditionalWait);
120 bool needRasterize = false;
122 auto workingTask = std::find(mWorkingTasks.begin(), mWorkingTasks.end(), task);
123 if(workingTask != mWorkingTasks.end())
125 mWorkingTasks.erase(workingTask);
128 // Check pending task
129 if(mAnimationTasks.end() != std::find(mAnimationTasks.begin(), mAnimationTasks.end(), task))
131 needRasterize = true;
134 if(keepAnimation && success)
136 if(mCompletedTasks.end() == std::find(mCompletedTasks.begin(), mCompletedTasks.end(), task))
138 mCompletedTasks.push_back(task);
139 needRasterize = true;
145 mNeedToSleep = false;
146 // wake up the animation thread
147 mConditionalWait.Notify(lock);
152 void VectorAnimationThread::OnAwakeFromSleep()
156 mNeedToSleep = false;
157 // wake up the animation thread
158 mConditionalWait.Notify();
162 void VectorAnimationThread::AddEventTriggerCallback(CallbackBase* callback)
164 Mutex::ScopedLock lock(mEventTriggerMutex);
167 mTriggerEventCallbacks.push_back(callback);
171 mEventTrigger->Trigger();
172 mEventTriggered = true;
177 void VectorAnimationThread::RemoveEventTriggerCallbacks(CallbackBase* callback)
179 Mutex::ScopedLock lock(mEventTriggerMutex);
182 auto iter = std::remove(mTriggerEventCallbacks.begin(), mTriggerEventCallbacks.end(), callback);
183 mTriggerEventCallbacks.erase(iter, mTriggerEventCallbacks.end());
187 void VectorAnimationThread::Run()
189 SetThreadName("VectorAnimationThread");
190 mLogFactory.InstallLogFunction();
191 mTraceFactory.InstallTraceFunction();
193 while(!mDestroyThread)
199 void VectorAnimationThread::Rasterize()
201 // Lock while popping task out from the queue
202 ConditionalWait::ScopedLock lock(mConditionalWait);
207 mConditionalWait.Wait(lock);
212 // Process completed tasks
213 for(auto&& task : mCompletedTasks)
215 if(mAnimationTasks.end() == std::find(mAnimationTasks.begin(), mAnimationTasks.end(), task))
217 // Should use the frame rate of the animation file
218 auto nextFrameTime = task->CalculateNextFrameTime(false);
220 bool inserted = false;
221 for(auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter)
223 auto time = (*iter)->GetNextFrameTime();
224 if(time > nextFrameTime)
226 mAnimationTasks.insert(iter, task);
234 mAnimationTasks.push_back(task);
238 mCompletedTasks.clear();
240 // pop out the next task from the queue
241 for(auto it = mAnimationTasks.begin(); it != mAnimationTasks.end();)
243 VectorAnimationTaskPtr nextTask = *it;
245 auto currentTime = std::chrono::steady_clock::now();
246 auto nextFrameTime = nextTask->GetNextFrameTime();
248 #if defined(DEBUG_ENABLED)
249 // auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(nextFrameTime - currentTime);
251 // DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::Rasterize: [next time = %lld]\n", duration.count());
253 if(nextFrameTime <= currentTime)
255 // If the task is not in the working list
256 if(std::find(mWorkingTasks.begin(), mWorkingTasks.end(), nextTask) == mWorkingTasks.end())
258 it = mAnimationTasks.erase(it);
260 // Add it to the working list
261 mWorkingTasks.push_back(nextTask);
262 mAsyncTaskManager.AddTask(nextTask);
271 mSleepThread.SleepUntil(nextFrameTime);
277 void VectorAnimationThread::OnEventCallbackTriggered()
279 while(CallbackBase* callback = GetNextEventCallback())
281 CallbackBase::Execute(*callback);
285 CallbackBase* VectorAnimationThread::GetNextEventCallback()
287 Mutex::ScopedLock lock(mEventTriggerMutex);
290 if(!mTriggerEventCallbacks.empty())
292 auto iter = mTriggerEventCallbacks.begin();
293 CallbackBase* callback = *iter;
294 mTriggerEventCallbacks.erase(iter);
297 mEventTriggered = false;
302 VectorAnimationThread::SleepThread::SleepThread(CallbackBase* callback)
303 : mConditionalWait(),
304 mAwakeCallback(std::unique_ptr<CallbackBase>(callback)),
306 mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
307 mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
309 mDestroyThread(false)
313 VectorAnimationThread::SleepThread::~SleepThread()
317 ConditionalWait::ScopedLock lock(mConditionalWait);
318 mDestroyThread = true;
319 mConditionalWait.Notify(lock);
325 void VectorAnimationThread::SleepThread::SleepUntil(std::chrono::time_point<std::chrono::steady_clock> timeToSleepUntil)
327 ConditionalWait::ScopedLock lock(mConditionalWait);
328 mSleepTimePoint = timeToSleepUntil;
330 mConditionalWait.Notify(lock);
333 void VectorAnimationThread::SleepThread::Run()
335 SetThreadName("VectorSleepThread");
336 mLogFactory.InstallLogFunction();
337 mTraceFactory.InstallTraceFunction();
339 while(!mDestroyThread)
342 std::chrono::time_point<std::chrono::steady_clock> sleepTimePoint;
345 ConditionalWait::ScopedLock lock(mConditionalWait);
347 needToSleep = mNeedToSleep;
348 sleepTimePoint = mSleepTimePoint;
350 mNeedToSleep = false;
355 #if defined(DEBUG_ENABLED)
356 // auto sleepDuration = std::chrono::duration_cast<std::chrono::milliseconds>(mSleepTimePoint - std::chrono::steady_clock::now());
358 // DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::SleepThread::Run: [sleep duration = %lld]\n", sleepDuration.count());
361 std::this_thread::sleep_until(sleepTimePoint);
365 CallbackBase::Execute(*mAwakeCallback);
370 ConditionalWait::ScopedLock lock(mConditionalWait);
371 if(!mDestroyThread && !mNeedToSleep)
373 mConditionalWait.Wait(lock);
379 } // namespace Internal
381 } // namespace Toolkit