Let we don't do any additional progress after application terminated.
Also, let we keep the VectorAnimationThread lifetime until all
working VectorAnimationTask are completed.
Since that task use VectorAnimationThread as reference, we cannot release
the memory of VectorAnimationManager memory. So just call finalize API.
Change-Id: I6f33c3f5863d8ad3ad9a08d45b134501582d87be
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
: mEventCallbacks(),
mLifecycleObservers(),
mVectorAnimationThread(nullptr),
- mProcessorRegistered(false)
+ mProcessorRegistered(false),
+ mDestroyed(false)
{
}
VectorAnimationManager::~VectorAnimationManager()
{
- for(auto&& iter : mEventCallbacks)
- {
- delete iter;
- }
- mEventCallbacks.clear();
-
- if(mProcessorRegistered && Adaptor::IsAvailable())
- {
- Adaptor::Get().UnregisterProcessor(*this, true);
- }
+ Finalize();
for(auto observer : mLifecycleObservers)
{
void VectorAnimationManager::RegisterEventCallback(CallbackBase* callback)
{
- mEventCallbacks.push_back(callback);
+ if(DALI_LIKELY(!mDestroyed))
+ {
+ mEventCallbacks.push_back(callback);
- if(!mProcessorRegistered)
+ if(!mProcessorRegistered && DALI_LIKELY(Adaptor::IsAvailable()))
+ {
+ Adaptor::Get().RegisterProcessor(*this, true); // Use post processor to trigger after layoutting
+ mProcessorRegistered = true;
+ }
+ }
+ else
{
- Adaptor::Get().RegisterProcessor(*this, true); // Use post processor to trigger after layoutting
- mProcessorRegistered = true;
+ delete callback; // No longer needed.
}
}
}
}
+void VectorAnimationManager::Finalize()
+{
+ if(DALI_LIKELY(!mDestroyed))
+ {
+ DALI_LOG_DEBUG_INFO("Finalizing Vector Animation Manager.\n");
+ mDestroyed = true;
+
+ for(auto&& iter : mEventCallbacks)
+ {
+ delete iter;
+ }
+
+ mEventCallbacks.clear();
+
+ if(mProcessorRegistered && Adaptor::IsAvailable())
+ {
+ Adaptor::Get().UnregisterProcessor(*this, true);
+ mProcessorRegistered = false;
+ }
+
+ if(mVectorAnimationThread)
+ {
+ mVectorAnimationThread->Finalize();
+ }
+ }
+}
+
void VectorAnimationManager::Process(bool postProcessor)
{
- for(auto&& iter : mEventCallbacks)
+ if(DALI_LIKELY(!mDestroyed))
{
- CallbackBase::Execute(*iter);
- delete iter;
+ for(auto&& iter : mEventCallbacks)
+ {
+ CallbackBase::Execute(*iter);
+ delete iter;
+ }
+
+ mEventCallbacks.clear();
}
- mEventCallbacks.clear();
Adaptor::Get().UnregisterProcessor(*this, true);
mProcessorRegistered = false;
*/
void UnregisterEventCallback(CallbackBase* callback);
+ /**
+ * @brief Finalize the manager. This will stop the animation thread and clear all resources.
+ */
+ void Finalize();
+
protected: // Implementation of Processor
/**
* @copydoc Dali::Integration::Processor::Process()
std::vector<CallbackBase*> mEventCallbacks;
std::vector<LifecycleObserver*> mLifecycleObservers;
std::unique_ptr<VectorAnimationThread> mVectorAnimationThread;
- bool mProcessorRegistered;
+ bool mProcessorRegistered : 1;
+ bool mDestroyed : 1;
};
} // namespace Internal
// Forcely trigger render once if need.
if(mNotifyAfterRasterization || mNeedForceRenderOnceTrigger)
{
- Mutex::ScopedLock lock(mMutex);
mVectorAnimationThread.RequestForceRenderOnce();
mNeedForceRenderOnceTrigger = false;
}
#include <dali/devel-api/adaptor-framework/thread-settings.h>
#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
#include <thread>
namespace Dali
// Stop the thread
{
ConditionalWait::ScopedLock lock(mConditionalWait);
- // Wait until some event thread trigger relative job finished.
- {
- Mutex::ScopedLock eventTriggerLock(mEventTriggerMutex);
- Mutex::ScopedLock taskCompletedLock(mTaskCompletedMutex);
- Mutex::ScopedLock animationTasksLock(mAnimationTasksMutex);
- DALI_LOG_DEBUG_INFO("Mark VectorAnimationThread destroyed\n");
- mDestroyThread = true;
- }
- mNeedToSleep = false;
+ Finalize();
mConditionalWait.Notify(lock);
}
DALI_LOG_DEBUG_INFO("VectorAnimationThread Join request\n");
Join();
+
+ // We need to wait all working tasks are completed before destructing this thread.
+ while(mWorkingTasks.size() > 0)
+ {
+ DALI_LOG_DEBUG_INFO("Still waiting WorkingTasks [%zu]\n", mWorkingTasks.size());
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+
+ // ConditionalWait notifyed when task complete.
+ // If task complete, then remove working tasks list and then wait again, until all working tasks are completed.
+ decltype(mCompletedTasksQueue) completedTasksQueue;
+ {
+ Mutex::ScopedLock taskCompletedLock(mTaskCompletedMutex);
+ completedTasksQueue.swap(mCompletedTasksQueue);
+ }
+ if(completedTasksQueue.empty())
+ {
+ mConditionalWait.Wait(lock);
+ // Task completed may have been added to the queue while we were waiting.
+ {
+ Mutex::ScopedLock taskCompletedLock(mTaskCompletedMutex);
+ completedTasksQueue.swap(mCompletedTasksQueue);
+ }
+ }
+
+ DALI_LOG_DEBUG_INFO("Completed task queue [%zu]\n", completedTasksQueue.size());
+
+ for(auto& taskPair : completedTasksQueue)
+ {
+ auto workingIter = std::find(mWorkingTasks.begin(), mWorkingTasks.end(), taskPair.first);
+ if(workingIter != mWorkingTasks.end())
+ {
+ mWorkingTasks.erase(workingIter);
+ }
+ }
+ }
}
/// Event thread called
Mutex::ScopedLock taskCompletedLock(mTaskCompletedMutex);
- if(DALI_LIKELY(!mDestroyThread))
- {
- mCompletedTasksQueue.emplace_back(task, success && keepAnimation);
+ // DevNote : We need to add task queue, and notify even if mDestroyThread is true.
+ // Since we should make ensure that all working tasks are completed before destroying the thread.
+ mCompletedTasksQueue.emplace_back(task, success && keepAnimation);
- // wake up the animation thread.
- // Note that we should not make mNeedToSleep as false now.
- mConditionalWait.Notify(lock);
- }
+ // wake up the animation thread.
+ // Note that we should not make mNeedToSleep as false now.
+ mConditionalWait.Notify(lock);
}
/// VectorAnimationThread::SleepThread called, Mutex SleepThread::mAwakeCallbackMutex is locked
}
}
+/// Event thread called
+void VectorAnimationThread::Finalize()
+{
+ Mutex::ScopedLock eventTriggerLock(mEventTriggerMutex);
+ Mutex::ScopedLock taskCompletedLock(mTaskCompletedMutex);
+ Mutex::ScopedLock animationTasksLock(mAnimationTasksMutex);
+ // Wait until some event thread trigger, and tasks relative job finished.
+ if(DALI_LIKELY(!mDestroyThread))
+ {
+ DALI_LOG_DEBUG_INFO("Mark VectorAnimationThread destroyed\n");
+ mDestroyThread = true;
+ }
+ mNeedToSleep = false;
+}
+
/// VectorAnimationThread called
void VectorAnimationThread::Run()
{
SetThreadName("VectorAnimationThread");
mLogFactory.InstallLogFunction();
- while(!mDestroyThread)
+ while(DALI_LIKELY(!mDestroyThread))
{
Rasterize();
}
/// VectorAnimationThread called
void VectorAnimationThread::MoveTasksToCompleted(VectorAnimationTaskPtr task, bool keepAnimation)
{
- if(DALI_LIKELY(!mDestroyThread))
- {
- bool needRasterize = false;
+ // DevNote : We need to consume task queue, and notify even if mDestroyThread is true.
+ // Since we should make ensure that all working tasks are completed before destroying the thread.
+ bool needRasterize = false;
- auto workingTask = std::find(mWorkingTasks.begin(), mWorkingTasks.end(), task);
- if(workingTask != mWorkingTasks.end())
- {
- mWorkingTasks.erase(workingTask);
- }
+ auto workingIter = std::find(mWorkingTasks.begin(), mWorkingTasks.end(), task);
+ if(workingIter != mWorkingTasks.end())
+ {
+ mWorkingTasks.erase(workingIter);
+ }
+ if(DALI_LIKELY(!mDestroyThread))
+ {
// Check pending task
{
Mutex::ScopedLock animationTasksLock(mAnimationTasksMutex);
*/
void RequestForceRenderOnce();
+ /**
+ * @brief Finalize the thread.
+ */
+ void Finalize();
+
protected:
/**
* @brief The entry function of the animation thread.
return *mVectorAnimationManager;
}
+void VisualFactoryCache::FinalizeVectorAnimationManager()
+{
+ if(mVectorAnimationManager)
+ {
+ mVectorAnimationManager->Finalize();
+ }
+}
+
Geometry VisualFactoryCache::CreateGridGeometry(Uint16Pair gridSize)
{
uint16_t gridWidth = gridSize.GetWidth();
*/
VectorAnimationManager& GetVectorAnimationManager();
+ /**
+ * @brief Finalize vector animation manager.
+ * It will be called when application is terminated.
+ */
+ void FinalizeVectorAnimationManager();
+
protected:
/**
* Undefined copy constructor.
// EXTERNAL INCLUDES
#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/object/property-array.h>
#include <dali/public-api/object/type-registry-helper.h>
mImageVisualShaderFactory(),
mTextVisualShaderFactory(),
mSlotDelegate(this),
+ mLifecycleController(Dali::LifecycleController::Get()),
mDebugEnabled(debugEnabled),
mPreMultiplyOnLoad(true)
{
+ if(DALI_LIKELY(mLifecycleController))
+ {
+ mLifecycleController.TerminateSignal().Connect(this, &VisualFactory::OnApplicationTerminated);
+ }
}
VisualFactory::~VisualFactory()
{
+ if(DALI_LIKELY(mLifecycleController))
+ {
+ mLifecycleController.TerminateSignal().Disconnect(this, &VisualFactory::OnApplicationTerminated);
+ }
}
void VisualFactory::OnStyleChangedSignal(Toolkit::StyleManager styleManager, StyleChange::Type type)
return *mTextVisualShaderFactory;
}
+void VisualFactory::OnApplicationTerminated()
+{
+ if(mFactoryCache)
+ {
+ mFactoryCache->FinalizeVectorAnimationManager();
+ }
+ // We don't need to keep it anymore
+ mLifecycleController.Reset();
+}
+
} // namespace Internal
} // namespace Toolkit
// EXTERNAL INCLUDES
#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
/**
* @copydoc Toolkit::VisualFactory
*/
-class VisualFactory : public BaseObject
+class VisualFactory : public BaseObject, public ConnectionTracker
{
public:
/**
*/
TextVisualShaderFactory& GetTextVisualShaderFactory();
+ /**
+ * @brief Callbacks called when application is terminated.
+ */
+ void OnApplicationTerminated();
+
VisualFactory(const VisualFactory&) = delete;
VisualFactory& operator=(const VisualFactory& rhs) = delete;
std::unique_ptr<ImageVisualShaderFactory> mImageVisualShaderFactory;
std::unique_ptr<TextVisualShaderFactory> mTextVisualShaderFactory;
SlotDelegate<VisualFactory> mSlotDelegate;
+ Dali::LifecycleController mLifecycleController;
bool mDebugEnabled : 1;
bool mPreMultiplyOnLoad : 1; ///< Local store for this flag
};