From 149c55edab542d019ae3974cfccbc57a1aa5f1cc Mon Sep 17 00:00:00 2001 From: Eunki Hong Date: Wed, 5 Feb 2025 22:12:08 +0900 Subject: [PATCH] [Tizen] Fix AnimatedImageVisual not rendering well if ReleasePolicy is not DETACHED Their are some logical issue if we use ReleasePolicy as DESTROYED or NEVER and SceneOff+SceneOn again cases. Current ImageCache system not consider non-empty queue case when we call FirstFrame(); Rather to fix the logic, let we simply clear the cache before re-call FirstFrame(); Since we remove texture cache at processor time, Clear cache immediately will not make any side effects. Change-Id: Idbc1a2cc62724ff67b84554cc94dc7168fa7f942 Signed-off-by: Eunki Hong --- .../src/dali-toolkit/utc-Dali-ImageView.cpp | 67 ++++++++++++++++--- .../animated-image/animated-image-visual.cpp | 39 ++++++++--- .../animated-image/fixed-image-cache.cpp | 6 +- .../rolling-animated-image-cache.cpp | 41 +++++++----- .../animated-image/rolling-image-cache.cpp | 9 ++- 5 files changed, 121 insertions(+), 41 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index c53e1c25ea..532020f8bb 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -1787,7 +1787,7 @@ int UtcDaliImageViewPaddingProperty(void) // Child ImageView should be positioned dependinig on Parent ImageView's Padding value DALI_TEST_EQUALS(childImage.GetProperty(Dali::Actor::Property::POSITION), Vector3(15, 5, 0), TEST_LOCATION); - // Check whether Image Visual transforms on ImageVieiw::OnRelayout() + // Check whether Image Visual transforms on ImageView::OnRelayout() Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation(imageView); Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(controlImpl, ImageView::Property::IMAGE); Property::Map resultMap; @@ -1826,7 +1826,7 @@ int UtcDaliImageViewPaddingProperty02(void) DALI_TEST_EQUALS(imageView.GetProperty(Control::Property::PADDING), Extents(15, 10, 5, 10), TEST_LOCATION); - // Check whether Image Visual transforms on ImageVieiw::OnRelayout() + // Check whether Image Visual transforms on ImageView::OnRelayout() Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation(imageView); Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(controlImpl, ImageView::Property::IMAGE); Property::Map resultMap; @@ -1874,7 +1874,7 @@ int UtcDaliImageViewPaddingProperty03(void) application.SendNotification(); application.Render(); - // Check whether Image Visual transforms on ImageVieiw::OnRelayout() + // Check whether Image Visual transforms on ImageView::OnRelayout() Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation(imageView); Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(controlImpl, ImageView::Property::IMAGE); Property::Map resultMap; @@ -1922,7 +1922,7 @@ int UtcDaliImageViewPaddingProperty04(void) application.SendNotification(); application.Render(); - // Check whether Image Visual transforms on ImageVieiw::OnRelayout() + // Check whether Image Visual transforms on ImageView::OnRelayout() Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation(imageView); Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(controlImpl, ImageView::Property::IMAGE); Property::Map resultMap; @@ -1965,7 +1965,7 @@ int UtcDaliImageViewTransformTest01(void) application.SendNotification(); application.Render(); - // Check whether Image Visual transforms on ImageVieiw::OnRelayout() + // Check whether Image Visual transforms on ImageView::OnRelayout() Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation(imageView); Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(controlImpl, ImageView::Property::IMAGE); Property::Map resultMap; @@ -3168,7 +3168,7 @@ int UtcDaliImageViewSyncSVGLoading02(void) application.SendNotification(); application.Render(); - // Check whether Image Visual transforms on ImageVieiw::OnRelayout() + // Check whether Image Visual transforms on ImageView::OnRelayout() Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation(imageView); Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(controlImpl, ImageView::Property::IMAGE); Property::Map resultMap; @@ -6417,4 +6417,55 @@ int UtcDaliImageViewSvgReRasterizeDuringResourceReady01(void) } END_TEST; -} \ No newline at end of file +} + +int UtcDaliImageViewAnimatedImageVisualWithReleasePolicy(void) +{ + tet_infoline("Use AnimatedImageVisual with ReleasePolicy, and Unparent+Add again. Check ResourceReady comes well"); + ToolkitTestApplication application; + + gResourceReadySignalFired = false; + + ImageView imageView = ImageView::New(); + + Property::Map imageMap; + imageMap[Visual::Property::TYPE] = Visual::IMAGE; + imageMap[ImageVisual::Property::URL] = TEST_GIF_FILE_NAME; + imageMap[ImageVisual::Property::RELEASE_POLICY] = ImageVisual::ReleasePolicy::DESTROYED; + + imageView.SetProperty(ImageView::Property::IMAGE, imageMap); + imageView.SetProperty(Actor::Property::SIZE, Vector2(100.f, 100.f)); + imageView.ResourceReadySignal().Connect(&ResourceReadySignal); + + tet_printf("Stop animation immediatly, for the stable test\n"); + DevelControl::DoAction(imageView, ImageView::Property::IMAGE, DevelAnimatedImageVisual::Action::STOP, Property::Value()); + + application.GetScene().Add(imageView); + application.SendNotification(); + application.Render(16); + + // loading started, this waits for the loader thread (wait 2 images - batch size) + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + + DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION); + DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION); + DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::READY, TEST_LOCATION); + + gResourceReadySignalFired = false; + + tet_printf("Unparent and add scene again\n"); + imageView.Unparent(); + application.GetScene().Add(imageView); + + tet_printf("Check whether resource ready signal emitted without Notification or wait\n"); + DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION); + DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION); + DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::READY, TEST_LOCATION); + + application.SendNotification(); + application.Render(16); + + gResourceReadySignalFired = false; + + END_TEST; +} diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp index a61a9bdbeb..d979806d2b 100644 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -299,11 +299,12 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image AnimatedImageVisual::~AnimatedImageVisual() { - // AnimatedImageVisual destroyed so remove texture unless ReleasePolicy is set to never release - // If this is animated image, clear cache. Else if this is single frame image, this is affected be release policy. - if(mFrameCount > SINGLE_IMAGE_COUNT || mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER) + if(DALI_LIKELY(mImageCache)) { - if(DALI_LIKELY(mImageCache)) + // AnimatedImageVisual destroyed so remove texture unless ReleasePolicy is set to never release + // If this is animated image, clear cache always. + // Else if this is single frame image, this is affected be release policy. + if(mFrameCount > SINGLE_IMAGE_COUNT || mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER) { mImageCache->ClearCache(); } @@ -902,9 +903,23 @@ void AnimatedImageVisual::DoSetOnScene(Actor& actor) { mStartFirstFrame = true; mPlacementActor = actor; - PrepareTextureSet(); - actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged); + + // We should clear cached informations before mImageCache->FirstFrame(); + // TODO : Could we remove this cache clearing code? + if(mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::DETACHED) + { + if(DALI_LIKELY(mImageCache)) + { + mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas + } + mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING; + + TextureSet textureSet = TextureSet::New(); + mImpl->mRenderer.SetTextures(textureSet); + } + + PrepareTextureSet(); } void AnimatedImageVisual::DoSetOffScene(Actor& actor) @@ -1062,6 +1077,7 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t first } } + mCurrentFrameIndex = FIRST_FRAME_INDEX; if(mImpl->mResourceStatus != Toolkit::Visual::ResourceStatus::FAILED) { if(mFrameCount > SINGLE_IMAGE_COUNT) @@ -1074,8 +1090,6 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t first DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::READY)\n"); ResourceReady(Toolkit::Visual::ResourceStatus::READY); } - - mCurrentFrameIndex = FIRST_FRAME_INDEX; } void AnimatedImageVisual::PrepareTextureSet() @@ -1100,7 +1114,7 @@ void AnimatedImageVisual::PrepareTextureSet() void AnimatedImageVisual::SetImageSize(TextureSet& textureSet) { - if(textureSet) + if(DALI_LIKELY(textureSet && textureSet.GetTextureCount() > 0u)) { Texture texture = textureSet.GetTexture(0); if(texture) @@ -1226,7 +1240,10 @@ bool AnimatedImageVisual::DisplayNextFrame() mImpl->mRenderer.SetTextures(textureSet); CheckMaskTexture(); } - mFrameDelayTimer.SetInterval(CalculateInterval(mImageCache->GetFrameInterval(frameIndex), mFrameSpeedFactor)); + if(mFrameDelayTimer) + { + mFrameDelayTimer.SetInterval(CalculateInterval(mImageCache->GetFrameInterval(frameIndex), mFrameSpeedFactor)); + } } mCurrentFrameIndex = frameIndex; diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp index 96f0f3e41c..43e877a8dc 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -170,9 +170,9 @@ void FixedImageCache::MakeReady(bool wasReady, uint32_t frameIndex, bool preMult void FixedImageCache::ClearCache() { - if(Dali::Adaptor::IsAvailable()) + if(DALI_LIKELY(Dali::Adaptor::IsAvailable())) { - for(std::size_t i = 0; i < mImageUrls.size(); ++i) + for(std::size_t i = 0u; i < mImageUrls.size(); ++i) { mTextureManager.RequestRemove(mImageUrls[i].mTextureId, this); mImageUrls[i].mTextureId = TextureManager::INVALID_TEXTURE_ID; diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp index 0cffcd01cf..7f0dae2a6b 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -28,22 +28,27 @@ namespace #if defined(DEBUG_ENABLED) Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE"); -#define LOG_CACHE \ - if(gAnimImgLogFilter->IsEnabledFor(Debug::Concise)) \ - { \ - std::ostringstream oss; \ - oss << "Size:" << mQueue.Count() << " [ "; \ - for(std::size_t _i = 0; _i < mQueue.Count(); ++_i) \ - { \ - oss << _i << "={ frm#: " << mQueue[_i].mFrameNumber << " tex: " << mTextureIds[mQueue[_i].mFrameNumber] << "}, "; \ - } \ - oss << " ]" << std::endl; \ - DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "%s", oss.str().c_str()); \ +// clang-format off +#define LOG_CACHE \ + if(gAnimImgLogFilter->IsEnabledFor(Debug::Concise)) \ + { \ + std::ostringstream oss; \ + oss << "Size:" << mQueue.Count() << " [ "; \ + for(std::size_t _i = 0; _i < mQueue.Count(); ++_i) \ + { \ + oss << _i << "={ frm#: " << mQueue[_i].mFrameNumber << " tex: "; \ + oss << (DALI_LIKELY(mQueue[_i].mFrameNumber < mTextureIds.size()) ? \ + mTextureIds[mQueue[_i].mFrameNumber] : \ + TextureManager::INVALID_TEXTURE_ID) << "}, "; \ + } \ + oss << " ]" << std::endl; \ + DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "%s", oss.str().c_str()); \ } - #else #define LOG_CACHE #endif +// clang-format on + } // namespace namespace Dali @@ -83,6 +88,7 @@ RollingAnimatedImageCache::RollingAnimatedImageCache(TextureManager& mIsSynchronousLoading(isSynchronousLoading) { mTextureIds.resize(mFrameCount); + mTextureIds[0] = TextureManager::INVALID_TEXTURE_ID; mIntervals.assign(mFrameCount, 0); } @@ -286,7 +292,7 @@ TextureSet RollingAnimatedImageCache::GetFrontTextureSet() const TextureManager::TextureId RollingAnimatedImageCache::GetCachedTextureId(int index) const { - return mTextureIds[mQueue[index].mFrameNumber]; + return DALI_LIKELY(mQueue[index].mFrameNumber < mTextureIds.size()) ? mTextureIds[mQueue[index].mFrameNumber] : TextureManager::INVALID_TEXTURE_ID; } void RollingAnimatedImageCache::PopFrontCache() @@ -307,9 +313,12 @@ void RollingAnimatedImageCache::PopFrontCache() void RollingAnimatedImageCache::ClearCache() { - while(Dali::Adaptor::IsAvailable() && !mQueue.IsEmpty()) + if(DALI_LIKELY(Dali::Adaptor::IsAvailable())) { - PopFrontCache(); + while(!mQueue.IsEmpty()) + { + PopFrontCache(); + } } mLoadWaitingQueue.clear(); mLoadState = TextureManager::LoadState::NOT_STARTED; diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp index c83161caca..7cc12b54bc 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -221,9 +221,12 @@ void RollingImageCache::PopFrontCache() void RollingImageCache::ClearCache() { - while(Dali::Adaptor::IsAvailable() && !mQueue.IsEmpty()) + if(DALI_LIKELY(Dali::Adaptor::IsAvailable())) { - PopFrontCache(); + while(!mQueue.IsEmpty()) + { + PopFrontCache(); + } } mLoadState = TextureManager::LoadState::NOT_STARTED; } -- 2.34.1