2 * Copyright (c) 2023 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)),
49 mDestroyThread(false),
50 mLogFactory(Dali::Adaptor::Get().GetLogFactory())
52 mAsyncTaskManager = Dali::AsyncTaskManager::Get();
56 VectorAnimationThread::~VectorAnimationThread()
60 ConditionalWait::ScopedLock lock(mConditionalWait);
61 mDestroyThread = true;
63 mConditionalWait.Notify(lock);
66 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::~VectorAnimationThread: Join [%p]\n", this);
71 void VectorAnimationThread::AddTask(VectorAnimationTaskPtr task)
73 ConditionalWait::ScopedLock lock(mConditionalWait);
75 // Find if the task is already in the list except loading task
76 auto iter = std::find_if(mAnimationTasks.begin(), mAnimationTasks.end(), [task](VectorAnimationTaskPtr& element) { return (element == task && !element->IsLoadRequested()); });
77 if(iter == mAnimationTasks.end())
79 auto currentTime = task->CalculateNextFrameTime(true); // Rasterize as soon as possible
81 bool inserted = false;
82 for(auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter)
84 auto nextTime = (*iter)->GetNextFrameTime();
85 if(nextTime > currentTime)
87 mAnimationTasks.insert(iter, task);
95 mAnimationTasks.push_back(task);
99 // wake up the animation thread
100 mConditionalWait.Notify(lock);
104 void VectorAnimationThread::OnTaskCompleted(VectorAnimationTaskPtr task, bool success, bool keepAnimation)
108 ConditionalWait::ScopedLock lock(mConditionalWait);
109 bool needRasterize = false;
111 auto workingTask = std::find(mWorkingTasks.begin(), mWorkingTasks.end(), task);
112 if(workingTask != mWorkingTasks.end())
114 mWorkingTasks.erase(workingTask);
117 // Check pending task
118 if(mAnimationTasks.end() != std::find(mAnimationTasks.begin(), mAnimationTasks.end(), task))
120 needRasterize = true;
123 if(keepAnimation && success)
125 if(mCompletedTasks.end() == std::find(mCompletedTasks.begin(), mCompletedTasks.end(), task))
127 mCompletedTasks.push_back(task);
128 needRasterize = true;
134 mNeedToSleep = false;
135 // wake up the animation thread
136 mConditionalWait.Notify(lock);
141 void VectorAnimationThread::OnAwakeFromSleep()
145 mNeedToSleep = false;
146 // wake up the animation thread
147 mConditionalWait.Notify();
151 void VectorAnimationThread::Run()
153 SetThreadName("VectorAnimationThread");
154 mLogFactory.InstallLogFunction();
156 while(!mDestroyThread)
162 void VectorAnimationThread::Rasterize()
164 // Lock while popping task out from the queue
165 ConditionalWait::ScopedLock lock(mConditionalWait);
170 mConditionalWait.Wait(lock);
175 // Process completed tasks
176 for(auto&& task : mCompletedTasks)
178 if(mAnimationTasks.end() == std::find(mAnimationTasks.begin(), mAnimationTasks.end(), task))
180 // Should use the frame rate of the animation file
181 auto nextFrameTime = task->CalculateNextFrameTime(false);
183 bool inserted = false;
184 for(auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter)
186 auto time = (*iter)->GetNextFrameTime();
187 if(time > nextFrameTime)
189 mAnimationTasks.insert(iter, task);
197 mAnimationTasks.push_back(task);
201 mCompletedTasks.clear();
203 // pop out the next task from the queue
204 for(auto it = mAnimationTasks.begin(); it != mAnimationTasks.end();)
206 VectorAnimationTaskPtr nextTask = *it;
208 auto currentTime = std::chrono::steady_clock::now();
209 auto nextFrameTime = nextTask->GetNextFrameTime();
211 #if defined(DEBUG_ENABLED)
212 // auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(nextFrameTime - currentTime);
214 // DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::Rasterize: [next time = %lld]\n", duration.count());
216 if(nextFrameTime <= currentTime)
218 // If the task is not in the working list
219 if(std::find(mWorkingTasks.begin(), mWorkingTasks.end(), nextTask) == mWorkingTasks.end())
221 it = mAnimationTasks.erase(it);
223 // Add it to the working list
224 mWorkingTasks.push_back(nextTask);
225 mAsyncTaskManager.AddTask(nextTask);
234 mSleepThread.SleepUntil(nextFrameTime);
240 VectorAnimationThread::SleepThread::SleepThread(CallbackBase* callback)
241 : mConditionalWait(),
242 mAwakeCallback(std::unique_ptr<CallbackBase>(callback)),
244 mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
246 mDestroyThread(false)
250 VectorAnimationThread::SleepThread::~SleepThread()
254 ConditionalWait::ScopedLock lock(mConditionalWait);
255 mDestroyThread = true;
256 mConditionalWait.Notify(lock);
262 void VectorAnimationThread::SleepThread::SleepUntil(std::chrono::time_point<std::chrono::steady_clock> timeToSleepUntil)
264 ConditionalWait::ScopedLock lock(mConditionalWait);
265 mSleepTimePoint = timeToSleepUntil;
267 mConditionalWait.Notify(lock);
270 void VectorAnimationThread::SleepThread::Run()
272 SetThreadName("VectorSleepThread");
273 mLogFactory.InstallLogFunction();
275 while(!mDestroyThread)
278 std::chrono::time_point<std::chrono::steady_clock> sleepTimePoint;
281 ConditionalWait::ScopedLock lock(mConditionalWait);
283 needToSleep = mNeedToSleep;
284 sleepTimePoint = mSleepTimePoint;
286 mNeedToSleep = false;
291 #if defined(DEBUG_ENABLED)
292 // auto sleepDuration = std::chrono::duration_cast<std::chrono::milliseconds>(mSleepTimePoint - std::chrono::steady_clock::now());
294 // DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::SleepThread::Run: [sleep duration = %lld]\n", sleepDuration.count());
297 std::this_thread::sleep_until(sleepTimePoint);
301 CallbackBase::Execute(*mAwakeCallback);
306 ConditionalWait::ScopedLock lock(mConditionalWait);
307 if(!mDestroyThread && !mNeedToSleep)
309 mConditionalWait.Wait(lock);
315 } // namespace Internal
317 } // namespace Toolkit