[Tizen] Fix AnimatedImageVisual not rendering well if ReleasePolicy is not DETACHED 33/319233/2
authorEunki Hong <eunkiki.hong@samsung.com>
Wed, 5 Feb 2025 13:12:08 +0000 (22:12 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 6 Feb 2025 05:49:19 +0000 (14:49 +0900)
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 <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp

index c53e1c25ea00541754fc3dcdca434bd243ee5462..532020f8bba92c8310ee55520e28486e4bbdf7c6 100644 (file)
@@ -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<Vector3>(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<Extents>(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;
+}
index a61a9bdbebb7bbdcd81203106161eb388b93d03b..d979806d2b910d1da82cfb54d5c18796e76bd084 100644 (file)
@@ -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;
index 96f0f3e41c53377ad1b9ce6887507f036afc0f1b..43e877a8dc3375c6ebc2edd2104c0abfafe4549b 100644 (file)
@@ -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;
index 0cffcd01cf11e98ba885568fb418ef6c26a47ae5..7f0dae2a6bb30716106690b5d686cb2c55ea89f2 100644 (file)
@@ -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;
index c83161cacaa6430d4d21bb79b90b3ffb71d0b341..7cc12b54bc68353d7d2337a408faf075484fced9 100644 (file)
@@ -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;
 }