/*
- * 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.
{
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
: 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()
// 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();
{
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
}
}
-void VectorAnimationThread::OnTaskCompleted(VectorAnimationTaskPtr task, bool keepAnimation)
+void VectorAnimationThread::OnTaskCompleted(VectorAnimationTaskPtr task, bool success, bool keepAnimation)
{
if(!mDestroyThread)
{
needRasterize = true;
}
- if(keepAnimation)
+ if(keepAnimation && success)
{
if(mCompletedTasks.end() == std::find(mCompletedTasks.begin(), mCompletedTasks.end(), task))
{
}
}
+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)
{
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
// 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
{
}
}
-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)
mAwakeCallback(std::unique_ptr<CallbackBase>(callback)),
mSleepTimePoint(),
mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+ mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
mNeedToSleep(false),
mDestroyThread(false)
{
{
SetThreadName("VectorSleepThread");
mLogFactory.InstallLogFunction();
+ mTraceFactory.InstallTraceFunction();
while(!mDestroyThread)
{
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);