This is a combination of 5 commits.
[Tizen] Force call KeepRendering when lottie animation stopped, or frame changed
Change-Id: Ie9c44a8a3997a644080c934d36e99c8aee804bf2
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
(Vector) Let we send finished signal only for matched sent play/stop from visual
It is possible that AnimationFinished trigger comes "after" event thread Play action comes.
If then, user's Play action be skipped.
To avoid this case, let we give the id when play state changed to Play / Pause / Stop.
And send finished signal only if the id is matched what visual know.
Change-Id: I03409e65d2f6b947940ea5591959b106ff8de2bd
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
(Vector) Add NOTIFY_AFTER_RASTERIZATION property for low fps file + Use UpdateOnce instead of KeepRendering
Let we change renderer rendering behavior is IF_REQUIRED.
It will be useful if app try to render lottie file which has less than 60fps.
+
Let we use UpdateOnce() API for force-rendering instead of KeepRendering().
KeepRendering will make ProcessCoreEvents forcely, which might not be need for animated vector cases.
Change-Id: Iaece9a5ff9e135acfdac404f68bdc690e6a7be8c
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
(Vector) Reduce the number of UpdateOnce call after rasterization
Previous code request UpdateOnce by each visuals.
But this don't need to spend the number of requests.
So let we just use only one single request API for it.
Change-Id: I5b11ee7ad19dc7c32945c0cfc637f7c65cfe3a77
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
Fix minor code errror
Change-Id: Ib9bebb5945418fdc040a9828c3989e1a931bd443
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
void RemoveIdle( CallbackBase* callback );
void RunIdles();
- static Integration::Scene GetScene( Dali::Window window );
+ void RequestUpdateOnce();
+
+ static Integration::Scene GetScene(Dali::Window window);
Dali::RenderSurfaceInterface& GetSurface();
Dali::WindowContainer GetWindows();
mCallbacks.Clear();
}
+void Adaptor::RequestUpdateOnce()
+{
+ if(mTestApplication)
+ {
+ auto scene = mTestApplication->GetScene();
+ if(scene)
+ {
+ tet_printf("Adaptor::RequestUpdateOnce()\n");
+ scene.KeepRendering(0.0f);
+ }
+ }
+}
+
Dali::RenderSurfaceInterface& Adaptor::GetSurface()
{
DALI_ASSERT_ALWAYS( ! mWindows.empty() );
// Wait for animation finish
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+ // EventThread will be triggered after animation finished (For render forcibly).
+ // TODO : Is this logic will works well on server-side?
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
// Jump to 3
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3);
#define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
/*
- * Copyright (c) 2023 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.
* @note This property is read-only.
*/
MARKER_INFO = ORIENTATION_CORRECTION + 15,
+
+ /**
+ * @brief Whether notify AnimatedVectorImageVisual to render thread after every rasterization or not.
+ * @details Name "notifyAfterRasterization", type Property::BOOLEAN.
+ * If this property is true, AnimatedVectorImageVisual send notify to render thread after every rasterization.
+ * If false, AnimatedVectorImageVisual set Renderer's Behaviour as Continouly (mean, always update the render thread.)
+ *
+ * This flag is useful if given resource has low fps, so we don't need to render every frame.
+ * @note It is used in the AnimatedVectorImageVisual. The default is false.
+ */
+ NOTIFY_AFTER_RASTERIZATION = ORIENTATION_CORRECTION + 17
};
} //namespace Property
#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/devel-api/common/stage.h>
#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/rendering/decorated-visual-renderer.h>
mPlacementActor(),
mPlayState(DevelImageVisual::PlayState::STOPPED),
mEventCallback(nullptr),
+ mLastSentPlayStateId(0u),
mLoadFailed(false),
mRendererAdded(false),
mCoreShutdown(false),
mRedrawInScalingDown(true),
- mUseFixedCache(false)
+ mUseFixedCache(false),
+ mNotifyAfterRasterization(false)
{
// the rasterized image is with pre-multiplied alpha format
mImpl->mFlags |= Visual::Base::Impl::IS_PREMULTIPLIED_ALPHA;
map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
map.Insert(Toolkit::DevelImageVisual::Property::USE_FIXED_CACHE, mUseFixedCache);
+ map.Insert(Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, mNotifyAfterRasterization);
}
void AnimatedVectorImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
{
DoSetProperty(Toolkit::DevelImageVisual::Property::USE_FIXED_CACHE, keyValue.second);
}
+ else if(keyValue.first == NOTIFY_AFTER_RASTERIZATION)
+ {
+ DoSetProperty(Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, keyValue.second);
+ }
}
}
}
break;
}
+
+ case Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION:
+ {
+ bool notifyAfterRasterization = false;
+ if(value.Get(notifyAfterRasterization))
+ {
+ if(mNotifyAfterRasterization != notifyAfterRasterization)
+ {
+ mNotifyAfterRasterization = notifyAfterRasterization;
+
+ mAnimationData.notifyAfterRasterization = mNotifyAfterRasterization;
+ mAnimationData.resendFlag |= VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION;
+ }
+ }
+ break;
+ }
}
}
{
if(IsOnScene() && mVisualSize != Vector2::ZERO)
{
- if(mAnimationData.playState != DevelImageVisual::PlayState::PLAYING)
- {
- mAnimationData.playState = DevelImageVisual::PlayState::PLAYING;
- mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
- }
+ // Always resend Playing state. If task is already playing, it will be ignored at Rasterize time.
+ mAnimationData.playState = DevelImageVisual::PlayState::PLAYING;
+ mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
}
mPlayState = DevelImageVisual::PlayState::PLAYING;
break;
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "status = %d [%p]\n", status, this);
}
-void AnimatedVectorImageVisual::OnAnimationFinished()
+void AnimatedVectorImageVisual::OnAnimationFinished(uint32_t playStateId)
{
+ // Only send event when animation is finished by the last Play/Pause/Stop request.
+ if(mLastSentPlayStateId != playStateId)
+ {
+ return;
+ }
+
AnimatedVectorImageVisualPtr self = this; // Keep reference until this API finished
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnAnimationFinished: action state = %d [%p]\n", mPlayState, this);
}
}
- if(mImpl->mRenderer)
+ if(!mNotifyAfterRasterization && mImpl->mRenderer)
{
mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
}
{
if(mAnimationData.resendFlag)
{
+ if(mAnimationData.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
+ {
+ // Keep last sent playId. It will be used when we try to emit AnimationFinished signal.
+ // The OnAnimationFinished signal what before Play/Pause/Stop action send could be come after action sent.
+ // To ensure the OnAnimationFinished signal comes belong to what we sent, we need to keep last sent playId.
+ mAnimationData.playStateId = ++mLastSentPlayStateId;
+ }
mVectorAnimationTask->SetAnimationData(mAnimationData);
- if(mImpl->mRenderer)
+ if(mImpl->mRenderer &&
+ ((mAnimationData.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE) ||
+ (mAnimationData.resendFlag & VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION)))
{
- if(mAnimationData.playState == DevelImageVisual::PlayState::PLAYING)
+ if(!mNotifyAfterRasterization && mPlayState == DevelImageVisual::PlayState::PLAYING)
{
+ // Make rendering behaviour if we don't notify after rasterization, but animation playing.
mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
}
else
{
+ // Otherwise, notify will be sended after rasterization. Make behaviour as required.
mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
}
}
/**
* @brief Event callback from rasterize thread. This is called after the animation is finished.
+ *
+ * @param[in] playStateId The play state id
*/
- void OnAnimationFinished();
+ void OnAnimationFinished(uint32_t playStateId);
/**
* @brief Send animation data to the rasterize thread.
WeakHandle<Actor> mPlacementActor;
DevelImageVisual::PlayState::Type mPlayState;
CallbackBase* mEventCallback; // Not owned
- bool mLoadFailed;
- bool mRendererAdded;
- bool mCoreShutdown;
- bool mRedrawInScalingDown;
- bool mUseFixedCache;
+
+ uint32_t mLastSentPlayStateId;
+
+ bool mLoadFailed : 1;
+ bool mRendererAdded : 1;
+ bool mCoreShutdown : 1;
+ bool mRedrawInScalingDown : 1;
+ bool mUseFixedCache : 1;
+ bool mNotifyAfterRasterization : 1;
};
} // namespace Internal
mWidth(0),
mHeight(0),
mAnimationDataIndex(0),
+ mAppliedPlayStateId(0u),
mLoopCount(LOOP_FOREVER),
mCurrentLoop(0),
mForward(true),
mUpdateFrameNumber(false),
mNeedAnimationFinishedTrigger(true),
+ mNeedForceRenderOnceTrigger(false),
mAnimationDataUpdated(false),
mDestroyTask(false),
mLoadRequest(false),
mLoadFailed(false),
mUseFixedCache(false),
+ mNotifyAfterRasterization(false),
mSizeUpdated(false)
{
mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted);
Mutex::ScopedLock lock(mMutex);
if(!synchronousLoading && mLoadCompletedCallback)
{
- mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get());
+ mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get(), 0u);
}
}
return false;
Mutex::ScopedLock lock(mMutex);
if(!synchronousLoading && mLoadCompletedCallback)
{
- mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get());
+ mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get(), 0u);
}
}
{
Load(true);
- OnLoadCompleted();
+ OnLoadCompleted(0u);
}
}
{
mPlayState = PlayState::PAUSED;
+ // Ensure to render paused frame.
+ mNeedForceRenderOnceTrigger = true;
+
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this);
}
}
if(mStartFrame > mCurrentFrame)
{
mCurrentFrame = mStartFrame;
+
+ if(mPlayState != PlayState::PLAYING)
+ {
+ // Ensure to render current frame.
+ mNeedForceRenderOnceTrigger = true;
+ }
}
else if(mEndFrame < mCurrentFrame)
{
mCurrentFrame = mEndFrame;
+
+ if(mPlayState != PlayState::PLAYING)
+ {
+ // Ensure to render current frame.
+ mNeedForceRenderOnceTrigger = true;
+ }
}
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mUrl.c_str(), this);
mCurrentFrame = frameNumber;
mUpdateFrameNumber = false;
+ if(mPlayState != PlayState::PLAYING)
+ {
+ // Ensure to render current frame.
+ mNeedForceRenderOnceTrigger = true;
+ }
+
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this);
}
else
mForward = true;
mCurrentLoop = 0;
+ mNeedForceRenderOnceTrigger = true;
+
if(mVectorRenderer)
{
// Notify the Renderer that rendering is stopped.
Mutex::ScopedLock lock(mMutex);
if(mNeedAnimationFinishedTrigger && mAnimationFinishedCallback)
{
- mVectorAnimationThread.AddEventTriggerCallback(mAnimationFinishedCallback.get());
+ mVectorAnimationThread.AddEventTriggerCallback(mAnimationFinishedCallback.get(), mAppliedPlayStateId);
}
}
DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this);
}
+ // Forcely trigger render once if need.
+ if(mNotifyAfterRasterization || mNeedForceRenderOnceTrigger)
+ {
+ Mutex::ScopedLock lock(mMutex);
+ mVectorAnimationThread.RequestForceRenderOnce();
+ mNeedForceRenderOnceTrigger = false;
+ }
+
if(mPlayState != PlayState::PAUSED && mPlayState != PlayState::STOPPED)
{
keepAnimation = true;
SetCurrentFrameNumber(mAnimationData[index].currentFrame);
}
+ if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION)
+ {
+ mNotifyAfterRasterization = mAnimationData[index].notifyAfterRasterization;
+ }
+
if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
{
mVectorRenderer.InvalidateBuffer();
if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
{
+ mAppliedPlayStateId = mAnimationData[index].playStateId;
if(mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING)
{
PlayAnimation();
mResourceReadySignal.Emit(ResourceStatus::READY);
}
-void VectorAnimationTask::OnLoadCompleted()
+void VectorAnimationTask::OnLoadCompleted(uint32_t /* not used */)
{
if(!mLoadFailed)
{
*/
enum ResendFlags
{
- RESEND_PLAY_RANGE = 1 << 0,
- RESEND_LOOP_COUNT = 1 << 1,
- RESEND_STOP_BEHAVIOR = 1 << 2,
- RESEND_LOOPING_MODE = 1 << 3,
- RESEND_CURRENT_FRAME = 1 << 4,
- RESEND_SIZE = 1 << 5,
- RESEND_PLAY_STATE = 1 << 6,
- RESEND_NEED_RESOURCE_READY = 1 << 7,
- RESEND_DYNAMIC_PROPERTY = 1 << 8
+ RESEND_PLAY_RANGE = 1 << 0,
+ RESEND_LOOP_COUNT = 1 << 1,
+ RESEND_STOP_BEHAVIOR = 1 << 2,
+ RESEND_LOOPING_MODE = 1 << 3,
+ RESEND_CURRENT_FRAME = 1 << 4,
+ RESEND_SIZE = 1 << 5,
+ RESEND_PLAY_STATE = 1 << 6,
+ RESEND_NEED_RESOURCE_READY = 1 << 7,
+ RESEND_DYNAMIC_PROPERTY = 1 << 8,
+ RESEND_NOTIFY_AFTER_RASTERIZATION = 1 << 9,
};
/**
currentFrame(0),
width(0),
height(0),
- loopCount(-1)
+ loopCount(-1),
+ playStateId(0),
+ notifyAfterRasterization(false)
{
}
AnimationData& operator=(const AnimationData& rhs)
{
resendFlag |= rhs.resendFlag; // OR resend flag
- playRange = rhs.playRange;
- playState = rhs.playState;
- stopBehavior = rhs.stopBehavior;
- loopingMode = rhs.loopingMode;
- currentFrame = rhs.currentFrame;
- width = rhs.width;
- height = rhs.height;
- loopCount = rhs.loopCount;
+ playRange = rhs.playRange;
+ playState = rhs.playState;
+ stopBehavior = rhs.stopBehavior;
+ loopingMode = rhs.loopingMode;
+ currentFrame = rhs.currentFrame;
+ width = rhs.width;
+ height = rhs.height;
+ loopCount = rhs.loopCount;
+ playStateId = rhs.playStateId;
+ notifyAfterRasterization = rhs.notifyAfterRasterization;
dynamicProperties.insert(dynamicProperties.end(), rhs.dynamicProperties.begin(), rhs.dynamicProperties.end());
return *this;
}
uint32_t width;
uint32_t height;
int32_t loopCount;
+ uint32_t playStateId;
+ bool notifyAfterRasterization;
};
/**
*/
TimePoint GetNextFrameTime();
+ /**
+ * @brief Called when the rasterization is completed from the asyncTaskManager
+ * @param[in] task The completed task
+ */
+ void TaskCompleted(VectorAnimationTaskPtr task);
+
+ /**
+ * @brief Check the rasterization succeeded
+ * @return true if the rasterization succeeded, false otherwise.
+ */
+ bool IsRasterized();
+
+ /**
+ * @brief Check the animation is running
+ * @return true if the animation is running, false otherwise.
+ */
+ bool IsAnimating();
+
void KeepRasterizedBuffer(bool useFixedCache)
{
mUseFixedCache = useFixedCache;
/**
* @brief Event callback from rasterize thread. This is called when the file loading is completed.
*/
- void OnLoadCompleted();
+ void OnLoadCompleted(uint32_t argument);
// Undefined
VectorAnimationTask(const VectorAnimationTask& task) = delete;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mAnimationDataIndex;
+ uint32_t mAppliedPlayStateId;
int32_t mLoopCount;
int32_t mCurrentLoop;
- bool mForward;
- bool mUpdateFrameNumber;
- bool mNeedAnimationFinishedTrigger;
- bool mAnimationDataUpdated;
- bool mDestroyTask;
- bool mLoadRequest;
- bool mLoadFailed;
- bool mUseFixedCache;
- bool mSizeUpdated;
+ bool mForward : 1;
+ bool mUpdateFrameNumber : 1;
+ bool mNeedAnimationFinishedTrigger : 1;
+ bool mNeedForceRenderOnceTrigger : 1;
+ bool mAnimationDataUpdated : 1;
+ bool mDestroyTask : 1;
+ bool mLoadRequest : 1;
+ bool mLoadFailed : 1;
+ bool mUseFixedCache : 1;
+ bool mNotifyAfterRasterization : 1;
+ bool mSizeUpdated : 1;
};
} // namespace Internal
mSleepThread(MakeCallback(this, &VectorAnimationThread::OnAwakeFromSleep)),
mConditionalWait(),
mEventTriggerMutex(),
+ mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
mNeedToSleep(false),
mDestroyThread(false),
- mLogFactory(Dali::Adaptor::Get().GetLogFactory())
+ mEventTriggered(false),
+ mForceRenderOnce(false)
{
mSleepThread.Start();
}
}
-void VectorAnimationThread::AddEventTriggerCallback(CallbackBase* callback)
+void VectorAnimationThread::AddEventTriggerCallback(CallbackBase* callback, uint32_t argument)
{
Mutex::ScopedLock lock(mEventTriggerMutex);
if(!mDestroyThread)
{
- mTriggerEventCallbacks.push_back(callback);
+ mTriggerEventCallbacks.emplace_back(callback, argument);
if(!mEventTriggered)
{
Mutex::ScopedLock lock(mEventTriggerMutex);
if(!mDestroyThread)
{
- auto iter = std::remove(mTriggerEventCallbacks.begin(), mTriggerEventCallbacks.end(), callback);
+ 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");
void VectorAnimationThread::OnEventCallbackTriggered()
{
- while(CallbackBase* callback = GetNextEventCallback())
+ while(true)
{
- CallbackBase::Execute(*callback);
+ 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();
+ }
+ }
}
}
-CallbackBase* VectorAnimationThread::GetNextEventCallback()
+std::pair<CallbackBase*, uint32_t> VectorAnimationThread::GetNextEventCallback()
{
Mutex::ScopedLock lock(mEventTriggerMutex);
if(!mDestroyThread)
{
if(!mTriggerEventCallbacks.empty())
{
- auto iter = mTriggerEventCallbacks.begin();
- CallbackBase* callback = *iter;
+ auto iter = mTriggerEventCallbacks.begin();
+ auto callbackIdPair = *iter;
mTriggerEventCallbacks.erase(iter);
- return callback;
+ return callbackIdPair;
}
mEventTriggered = false;
}
- return nullptr;
+ return std::make_pair(nullptr, 0u);
}
VectorAnimationThread::RasterizeHelper::RasterizeHelper(VectorAnimationThread& animationThread)
#define DALI_TOOLKIT_VECTOR_ANIMATION_THREAD_H
/*
- * Copyright (c) 2022 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.
* @brief Add an event trigger callback.
*
* @param callback The callback to add
+ * @param argument The argument to pass to the callback
* @note Ownership of the callback is NOT passed onto this class.
* @note The callback will be excuted in the main thread.
*/
- void AddEventTriggerCallback(CallbackBase* callback);
+ void AddEventTriggerCallback(CallbackBase* callback, uint32_t argument);
/**
* @brief Remove event trigger callbacks what we added before.
*/
void RemoveEventTriggerCallbacks(CallbackBase* callback);
+ /**
+ * @brief Request to event callback from rasterize thread. This is called when we want to ensure rendering next frame.
+ */
+ void RequestForceRenderOnce();
+
protected:
/**
* @brief The entry function of the animation thread.
/**
* @brief Gets next event callback to process.
*/
- CallbackBase* GetNextEventCallback();
+ std::pair<CallbackBase*, uint32_t> GetNextEventCallback();
/**
* @brief The thread to sleep until the next frame time.
std::unique_ptr<CallbackBase> mAwakeCallback;
std::chrono::time_point<std::chrono::steady_clock> mSleepTimePoint;
const Dali::LogFactoryInterface& mLogFactory;
- bool mNeedToSleep;
- bool mDestroyThread;
+ bool mNeedToSleep : 1;
+ bool mDestroyThread : 1;
};
private:
VectorAnimationThread& operator=(const VectorAnimationThread& thread) = delete;
private:
- std::vector<VectorAnimationTaskPtr> mAnimationTasks;
- std::vector<VectorAnimationTaskPtr> mCompletedTasks;
- std::vector<VectorAnimationTaskPtr> mWorkingTasks;
- RoundRobinContainerView<RasterizeHelper> mRasterizers;
- std::vector<CallbackBase*> mTriggerEventCallbacks{}; // Callbacks are not owned
- SleepThread mSleepThread;
- ConditionalWait mConditionalWait;
- Mutex mEventTriggerMutex;
- std::unique_ptr<EventThreadCallback> mEventTrigger{};
- bool mNeedToSleep;
- bool mDestroyThread;
- bool mEventTriggered{false};
- const Dali::LogFactoryInterface& mLogFactory;
+ std::vector<VectorAnimationTaskPtr> mAnimationTasks;
+ std::vector<VectorAnimationTaskPtr> mCompletedTasks;
+ std::vector<VectorAnimationTaskPtr> mWorkingTasks;
+ RoundRobinContainerView<RasterizeHelper> mRasterizers;
+ std::vector<std::pair<CallbackBase*, uint32_t>> mTriggerEventCallbacks{}; // Callbacks are not owned
+ SleepThread mSleepThread;
+ ConditionalWait mConditionalWait;
+ Mutex mEventTriggerMutex;
+ std::unique_ptr<EventThreadCallback> mEventTrigger{};
+ const Dali::LogFactoryInterface& mLogFactory;
+
+ bool mNeedToSleep : 1;
+ bool mDestroyThread : 1;
+ bool mEventTriggered : 1;
+ bool mForceRenderOnce : 1;
};
} // namespace Internal
const char* const MASKING_TYPE_NAME("maskingType");
const char* const MASK_TEXTURE_RATIO_NAME("maskTextureRatio");
const char* const USE_FIXED_CACHE("useFixedCache");
+const char* const NOTIFY_AFTER_RASTERIZATION("notifyAfterRasterization");
// Text visual
const char* const TEXT_PROPERTY("text");
extern const char* const MASKING_TYPE_NAME;
extern const char* const MASK_TEXTURE_RATIO_NAME;
extern const char* const USE_FIXED_CACHE;
+extern const char* const NOTIFY_AFTER_RASTERIZATION;
// Text visual
extern const char* const TEXT_PROPERTY;