X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fanimated-vector-image%2Fvector-animation-task.cpp;h=01b6898403615ea15e9025dead7fee85c5f9e728;hp=a202747e3404b47ce97a711c0fc822df988b12c1;hb=HEAD;hpb=b6e5096fe564c1fb6c56383b1e878eb51358ae41 diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp index a202747..ac448c0 100644 --- a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp +++ b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -19,7 +19,9 @@ #include // EXTERNAL INCLUDES +#include #include +#include #include #include @@ -28,6 +30,13 @@ #include #include +#ifdef TRACE_ENABLED +#include +#include +#include +#include +#endif + namespace Dali { namespace Toolkit @@ -43,17 +52,32 @@ constexpr auto MICROSECONDS_PER_SECOND(1e+6); Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION"); #endif +DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false); + +#ifdef TRACE_ENABLED +uint64_t GetNanoseconds() +{ + // Get the time of a monotonic clock since its epoch. + auto epoch = std::chrono::steady_clock::now().time_since_epoch(); + auto duration = std::chrono::duration_cast(epoch); + return static_cast(duration.count()); +} +#endif + } // unnamed namespace VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache) -: mUrl(), +: AsyncTask(MakeCallback(this, &VectorAnimationTask::TaskCompleted), AsyncTask::PriorityType::HIGH, AsyncTask::ThreadType::WORKER_THREAD), + mImageUrl(), + mEncodedImageBuffer(), mVectorRenderer(VectorAnimationRenderer::New()), mAnimationData(), mVectorAnimationThread(factoryCache.GetVectorAnimationManager().GetVectorAnimationThread()), - mConditionalWait(), + mMutex(), mResourceReadySignal(), - mAnimationFinishedTrigger(), - mLoadCompletedTrigger(new EventThreadCallback(MakeCallback(this, &VectorAnimationTask::OnLoadCompleted))), + mLoadCompletedCallback(MakeCallback(this, &VectorAnimationTask::OnLoadCompleted)), + mCachedLayerInfo(), + mCachedMarkerInfo(), mPlayState(PlayState::STOPPED), mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME), mLoopingMode(DevelImageVisual::LoopingMode::RESTART), @@ -68,15 +92,24 @@ VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache) 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) + mLoadFailed(false), + mRasterized(false), + mKeepAnimation(false), + mLayerInfoCached(false), + mMarkerInfoCached(false), + mEnableFrameCache(false), + mNotifyAfterRasterization(false), + mSizeUpdated(false) { mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted); } @@ -86,33 +119,120 @@ VectorAnimationTask::~VectorAnimationTask() DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this); } -void VectorAnimationTask::Finalize() +void VectorAnimationTask::Process() { - ConditionalWait::ScopedLock lock(mConditionalWait); + mRasterized = Rasterize(); +} - // Release some objects in the main thread - if(mAnimationFinishedTrigger) - { - mAnimationFinishedTrigger.reset(); - } - if(mLoadCompletedTrigger) +bool VectorAnimationTask::IsReady() +{ + return true; +} + +void VectorAnimationTask::Finalize() +{ { - mLoadCompletedTrigger.reset(); + Mutex::ScopedLock lock(mMutex); + + // Release some objects in the main thread + if(mAnimationFinishedCallback) + { + mVectorAnimationThread.RemoveEventTriggerCallbacks(mAnimationFinishedCallback.get()); + mAnimationFinishedCallback.reset(); + } + if(mLoadCompletedCallback) + { + mVectorAnimationThread.RemoveEventTriggerCallbacks(mLoadCompletedCallback.get()); + mLoadCompletedCallback.reset(); + } + + mDestroyTask = true; } mVectorRenderer.Finalize(); +} + +void VectorAnimationTask::TaskCompleted(VectorAnimationTaskPtr task) +{ + mVectorAnimationThread.OnTaskCompleted(task, task->IsRasterized(), task->IsAnimating()); +} - mDestroyTask = true; +bool VectorAnimationTask::IsRasterized() +{ + return mRasterized; +} + +bool VectorAnimationTask::IsAnimating() +{ + return mKeepAnimation; } -bool VectorAnimationTask::Load() +bool VectorAnimationTask::Load(bool synchronousLoading) { - if(!mVectorRenderer.Load(mUrl)) +#ifdef TRACE_ENABLED + uint64_t mStartTimeNanoSceonds = 0; + uint64_t mEndTimeNanoSceonds = 0; + if(gTraceFilter && gTraceFilter->IsTraceEnabled()) + { + mStartTimeNanoSceonds = GetNanoseconds(); + std::ostringstream oss; + oss << "[u:" << mImageUrl.GetEllipsedUrl() << "]"; + // DALI_TRACE_BEGIN(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level + DALI_LOG_RELEASE_INFO("BEGIN: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str()); + } +#endif + + if(mEncodedImageBuffer) + { + if(!mVectorRenderer.Load(mEncodedImageBuffer.GetRawBuffer())) + { + mLoadFailed = true; + } + + // We don't need to hold image buffer anymore. + mEncodedImageBuffer.Reset(); + } + else if(mImageUrl.IsLocalResource()) + { + if(!mVectorRenderer.Load(mImageUrl.GetUrl())) + { + mLoadFailed = true; + } + } + else { - DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mUrl.c_str()); + Dali::Vector remoteData; + if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), remoteData) || // Failed if we fail to download json file, + !mVectorRenderer.Load(remoteData)) // or download data is not valid vector animation file. + { + mLoadFailed = true; + } + } + + if(mLoadFailed) + { + DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mImageUrl.GetUrl().c_str()); mLoadRequest = false; - mLoadFailed = true; - mLoadCompletedTrigger->Trigger(); + { + Mutex::ScopedLock lock(mMutex); + if(!synchronousLoading && mLoadCompletedCallback) + { + mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get(), 0u); + } + } +#ifdef TRACE_ENABLED + if(gTraceFilter && gTraceFilter->IsTraceEnabled()) + { + mEndTimeNanoSceonds = GetNanoseconds(); + std::ostringstream oss; + oss << std::fixed << std::setprecision(3); + oss << "["; + oss << "d:" << static_cast(mEndTimeNanoSceonds - mStartTimeNanoSceonds) / 1000000.0f << "ms "; + oss << "u:" << mImageUrl.GetEllipsedUrl() << "]"; + // DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level + DALI_LOG_RELEASE_INFO("END: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str()); + } +#endif return false; } @@ -124,28 +244,57 @@ bool VectorAnimationTask::Load() mFrameDurationMicroSeconds = MICROSECONDS_PER_SECOND / mFrameRate; mLoadRequest = false; - mLoadCompletedTrigger->Trigger(); + { + Mutex::ScopedLock lock(mMutex); + if(!synchronousLoading && mLoadCompletedCallback) + { + mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get(), 0u); + } + } - DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Load: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Load: file = %s [%d frames, %f fps] [%p]\n", mImageUrl.GetUrl().c_str(), mTotalFrame, mFrameRate, this); + +#ifdef TRACE_ENABLED + if(gTraceFilter && gTraceFilter->IsTraceEnabled()) + { + mEndTimeNanoSceonds = GetNanoseconds(); + std::ostringstream oss; + oss << std::fixed << std::setprecision(3); + oss << "["; + oss << "d:" << static_cast(mEndTimeNanoSceonds - mStartTimeNanoSceonds) / 1000000.0f << "ms "; + oss << "u:" << mImageUrl.GetEllipsedUrl() << "]"; + // DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level + DALI_LOG_RELEASE_INFO("END: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str()); + } +#endif return true; } void VectorAnimationTask::SetRenderer(Renderer renderer) { - ConditionalWait::ScopedLock lock(mConditionalWait); - mVectorRenderer.SetRenderer(renderer); DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this); } -void VectorAnimationTask::RequestLoad(const std::string& url) +void VectorAnimationTask::RequestLoad(const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, bool synchronousLoading) { - mUrl = url; - mLoadRequest = true; + mImageUrl = url; + mEncodedImageBuffer = encodedImageBuffer; - mVectorAnimationThread.AddTask(this); + if(!synchronousLoading) + { + mLoadRequest = true; + + mVectorAnimationThread.AddTask(this); + } + else + { + Load(true); + + OnLoadCompleted(0u); + } } bool VectorAnimationTask::IsLoadRequested() const @@ -155,13 +304,13 @@ bool VectorAnimationTask::IsLoadRequested() const void VectorAnimationTask::SetAnimationData(const AnimationData& data) { - ConditionalWait::ScopedLock lock(mConditionalWait); + Mutex::ScopedLock lock(mMutex); DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this); uint32_t index = mAnimationDataIndex == 0 ? 1 : 0; // Use the other buffer - mAnimationData[index] = data; + mAnimationData[index].push_back(data); mAnimationDataUpdated = true; if(data.resendFlag & VectorAnimationTask::RESEND_SIZE) @@ -182,6 +331,20 @@ void VectorAnimationTask::SetSize(uint32_t width, uint32_t height) mWidth = width; mHeight = height; + // If fixedCache is enabled, Call KeepRasterizedBuffer() + if(mEnableFrameCache) + { + if(mTotalFrame > 0 && !mLoadFailed) + { + mVectorRenderer.KeepRasterizedBuffer(); + } + else + { + // If Load is not yet, update the size later. + mSizeUpdated = true; + } + } + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this); } } @@ -215,17 +378,17 @@ void VectorAnimationTask::PauseAnimation() { mPlayState = PlayState::PAUSED; + // Ensure to render paused frame. + mNeedForceRenderOnceTrigger = true; + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this); } } -void VectorAnimationTask::SetAnimationFinishedCallback(EventThreadCallback* callback) +void VectorAnimationTask::SetAnimationFinishedCallback(CallbackBase* callback) { - ConditionalWait::ScopedLock lock(mConditionalWait); - if(callback) - { - mAnimationFinishedTrigger = std::unique_ptr(callback); - } + Mutex::ScopedLock lock(mMutex); + mAnimationFinishedCallback = std::unique_ptr(callback); } void VectorAnimationTask::SetLoopCount(int32_t count) @@ -309,13 +472,25 @@ void VectorAnimationTask::SetPlayRange(const Property::Array& playRange) 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); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mImageUrl.GetUrl().c_str(), this); } } @@ -338,6 +513,12 @@ void VectorAnimationTask::SetCurrentFrameNumber(uint32_t frameNumber) 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 @@ -377,7 +558,38 @@ void VectorAnimationTask::SetLoopingMode(DevelImageVisual::LoopingMode::Type loo void VectorAnimationTask::GetLayerInfo(Property::Map& map) const { - mVectorRenderer.GetLayerInfo(map); + // Fast-out if file is loading, or load failed. + if(mLoadFailed || IsLoadRequested()) + { + return; + } + + if(DALI_UNLIKELY(!mLayerInfoCached)) + { + // Update only 1 time. + mLayerInfoCached = true; + mVectorRenderer.GetLayerInfo(mCachedLayerInfo); + } + + map = mCachedLayerInfo; +} + +void VectorAnimationTask::GetMarkerInfo(Property::Map& map) const +{ + // Fast-out if file is loading, or load failed. + if(mLoadFailed || IsLoadRequested()) + { + return; + } + + if(DALI_UNLIKELY(!mMarkerInfoCached)) + { + // Update only 1 time. + mMarkerInfoCached = true; + mVectorRenderer.GetMarkerInfo(mCachedMarkerInfo); + } + + map = mCachedMarkerInfo; } VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReadySignal() @@ -385,24 +597,24 @@ VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReady return mResourceReadySignal; } -bool VectorAnimationTask::Rasterize(bool& keepAnimation) +bool VectorAnimationTask::Rasterize() { bool stopped = false; uint32_t currentFrame; - keepAnimation = false; + mKeepAnimation = false; { - ConditionalWait::ScopedLock lock(mConditionalWait); + Mutex::ScopedLock lock(mMutex); if(mDestroyTask) { // The task will be destroyed. We don't need rasterization. return false; } + } - if(mLoadRequest) - { - return Load(); - } + if(mLoadRequest) + { + return Load(false); } if(mLoadFailed) @@ -410,6 +622,16 @@ bool VectorAnimationTask::Rasterize(bool& keepAnimation) return false; } +#ifdef TRACE_ENABLED + uint64_t mStartTimeNanoSceonds = 0; + uint64_t mEndTimeNanoSceonds = 0; +#endif + DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_LOTTIE_RASTERIZE_TASK", [&](std::ostringstream& oss) { + mStartTimeNanoSceonds = GetNanoseconds(); + oss << "[s:" << mWidth << "x" << mHeight << " "; + oss << "u:" << mImageUrl.GetEllipsedUrl() << "]"; + }); + ApplyAnimationData(); if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber) @@ -494,23 +716,51 @@ bool VectorAnimationTask::Rasterize(bool& keepAnimation) mForward = true; mCurrentLoop = 0; + mNeedForceRenderOnceTrigger = true; + + if(mVectorRenderer) + { + // Notify the Renderer that rendering is stopped. + mVectorRenderer.RenderStopped(); + } + // Animation is finished { - ConditionalWait::ScopedLock lock(mConditionalWait); - if(mNeedAnimationFinishedTrigger && mAnimationFinishedTrigger) + Mutex::ScopedLock lock(mMutex); + if(mNeedAnimationFinishedTrigger && mAnimationFinishedCallback) { - mAnimationFinishedTrigger->Trigger(); + 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; + mKeepAnimation = true; } + DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_LOTTIE_RASTERIZE_TASK", [&](std::ostringstream& oss) { + mEndTimeNanoSceonds = GetNanoseconds(); + oss << std::fixed << std::setprecision(3); + oss << "["; + oss << "d:" << static_cast(mEndTimeNanoSceonds - mStartTimeNanoSceonds) / 1000000.0f << "ms "; + oss << "s:" << mWidth << "x" << mHeight << " "; + oss << "f:" << mCurrentFrame << " "; + oss << "l:" << mCurrentLoop << " "; + oss << "p:" << mPlayState << " "; + oss << "u:" << mImageUrl.GetEllipsedUrl() << "]"; + }); + return true; } @@ -587,9 +837,9 @@ void VectorAnimationTask::ApplyAnimationData() uint32_t index; { - ConditionalWait::ScopedLock lock(mConditionalWait); + Mutex::ScopedLock lock(mMutex); - if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].resendFlag != 0) + if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].size() != 0) { // Data is not updated or the previous data is not applied yet. return; @@ -601,63 +851,71 @@ void VectorAnimationTask::ApplyAnimationData() index = mAnimationDataIndex; } - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT) - { - SetLoopCount(mAnimationData[index].loopCount); - } - - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE) + for(const auto& animationData : mAnimationData[index]) { - SetPlayRange(mAnimationData[index].playRange); - } + if(animationData.resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT) + { + SetLoopCount(animationData.loopCount); + } - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR) - { - SetStopBehavior(mAnimationData[index].stopBehavior); - } + if(animationData.resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE) + { + SetPlayRange(animationData.playRange); + } - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE) - { - SetLoopingMode(mAnimationData[index].loopingMode); - } + if(animationData.resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR) + { + SetStopBehavior(animationData.stopBehavior); + } - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME) - { - SetCurrentFrameNumber(mAnimationData[index].currentFrame); - } + if(animationData.resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE) + { + SetLoopingMode(animationData.loopingMode); + } - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY) - { - mVectorRenderer.InvalidateBuffer(); - } + if(animationData.resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME) + { + SetCurrentFrameNumber(animationData.currentFrame); + } - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY) - { - for(auto&& iter : mAnimationData[index].dynamicProperties) + if(animationData.resendFlag & VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION) { - mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast(iter.property), iter.callback, iter.id); + mNotifyAfterRasterization = animationData.notifyAfterRasterization; } - } - if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE) - { - if(mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING) + if(animationData.resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY) { - PlayAnimation(); + mVectorRenderer.InvalidateBuffer(); } - else if(mAnimationData[index].playState == DevelImageVisual::PlayState::PAUSED) + + if(animationData.resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY) { - PauseAnimation(); + for(auto&& iter : animationData.dynamicProperties) + { + mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast(iter.property), iter.callback, iter.id); + } } - else if(mAnimationData[index].playState == DevelImageVisual::PlayState::STOPPED) + + if(animationData.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE) { - StopAnimation(); + mAppliedPlayStateId = animationData.playStateId; + if(animationData.playState == DevelImageVisual::PlayState::PLAYING) + { + PlayAnimation(); + } + else if(animationData.playState == DevelImageVisual::PlayState::PAUSED) + { + PauseAnimation(); + } + else if(animationData.playState == DevelImageVisual::PlayState::STOPPED) + { + StopAnimation(); + } } } - // reset data - mAnimationData[index].dynamicProperties.clear(); - mAnimationData[index].resendFlag = 0; + // reset data list + mAnimationData[index].clear(); } void VectorAnimationTask::OnUploadCompleted() @@ -665,10 +923,15 @@ void VectorAnimationTask::OnUploadCompleted() mResourceReadySignal.Emit(ResourceStatus::READY); } -void VectorAnimationTask::OnLoadCompleted() +void VectorAnimationTask::OnLoadCompleted(uint32_t /* not used */) { if(!mLoadFailed) { + if(mEnableFrameCache && mSizeUpdated) + { + mVectorRenderer.KeepRasterizedBuffer(); + mSizeUpdated = false; + } mResourceReadySignal.Emit(ResourceStatus::LOADED); } else