Fix maskTextureId remove issue 94/281894/3
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 23 Sep 2022 04:48:41 +0000 (13:48 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Tue, 27 Sep 2022 04:08:36 +0000 (13:08 +0900)
After remove maskTextureInfo at TextureCacheManager,
original textureInfo reference can be broken.

This patch make validate the textureInfo's reference well.

Change-Id: I69e83bff5da237fe0a0ff66ce892de0f5e6ddb58
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
dali-toolkit/internal/texture-manager/texture-manager-impl.cpp

index 5f82a5c..c80d1b5 100644 (file)
@@ -54,8 +54,9 @@ void utc_dali_toolkit_texture_manager_cleanup(void)
 
 namespace
 {
-const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
-const char* TEST_MASK_FILE_NAME  = TEST_RESOURCE_DIR "/mask.png";
+const char* TEST_IMAGE_FILE_NAME   = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+const char* TEST_IMAGE_2_FILE_NAME = TEST_RESOURCE_DIR "/icon-delete.png";
+const char* TEST_MASK_FILE_NAME    = TEST_RESOURCE_DIR "/mask.png";
 
 class TestObserver : public Dali::Toolkit::TextureUploadObserver
 {
@@ -1034,7 +1035,7 @@ int UtcTextureManagerAsyncSyncAsync(void)
   Texture asyncTexture2 = asyncTextureSet2.GetTexture(0u);
   DALI_TEST_CHECK(syncTexture);
   DALI_TEST_CHECK(asyncTexture2);
-  DALI_TEST_CHECK(asyncTexture2 == syncTexture);               // check loaded two texture is same.
+  DALI_TEST_CHECK(asyncTexture2 == syncTexture); // check loaded two texture is same.
 
   // observer is called synchronously because the texture is cached.
   DALI_TEST_EQUALS(asyncObserver2.mLoaded, true, TEST_LOCATION);
@@ -1216,3 +1217,162 @@ int UtcTextureManagerRemoveDuringApplyMasking(void)
 
   END_TEST;
 }
+
+int UtcTextureManagerMaskCacheTest(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcTextureManagerMaskCacheTest");
+
+  TextureManager textureManager; // Create new texture manager
+
+  TestObserver observer1;
+  TestObserver observer2;
+
+  std::string                        filename(TEST_IMAGE_FILE_NAME);
+  std::string                        filename2(TEST_IMAGE_2_FILE_NAME);
+  std::string                        maskname(TEST_MASK_FILE_NAME);
+  TextureManager::MaskingDataPointer maskInfo = nullptr;
+  maskInfo.reset(new TextureManager::MaskingData());
+  maskInfo->mAlphaMaskUrl       = maskname;
+  maskInfo->mAlphaMaskId        = TextureManager::INVALID_TEXTURE_ID;
+  maskInfo->mCropToMask         = true;
+  maskInfo->mContentScaleFactor = 1.0f;
+
+  TextureManager::MaskingDataPointer maskInfo2 = nullptr;
+  maskInfo2.reset(new TextureManager::MaskingData());
+  maskInfo2->mAlphaMaskUrl       = maskname;
+  maskInfo2->mAlphaMaskId        = TextureManager::INVALID_TEXTURE_ID;
+  maskInfo2->mCropToMask         = true;
+  maskInfo2->mContentScaleFactor = 1.0f;
+
+  auto                          textureId1(TextureManager::INVALID_TEXTURE_ID);
+  auto                          textureId2(TextureManager::INVALID_TEXTURE_ID);
+  Vector4                       atlasRect(0.f, 0.f, 1.f, 1.f);
+  Dali::ImageDimensions         atlasRectSize(0, 0);
+  bool                          synchronousLoading(false);
+  bool                          atlasingStatus(false);
+  bool                          loadingStatus(false);
+  auto                          preMultiply         = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  ImageAtlasManagerPtr          atlasManager        = nullptr;
+  Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+  textureManager.LoadTexture(
+    filename,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo,
+    synchronousLoading,
+    textureId1,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer1,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  // Load image and mask image.
+  // Now, LoadState become MASK_APPLYING
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  tet_printf("Current textureId1:%d's state become MASK_APPLYING\n", static_cast<int>(textureId1));
+
+  textureManager.LoadTexture(
+    filename2,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    maskInfo2,
+    synchronousLoading,
+    textureId2,
+    atlasRect,
+    atlasRectSize,
+    atlasingStatus,
+    loadingStatus,
+    &observer2,
+    atlasUploadObserver,
+    atlasManager,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  application.SendNotification();
+  application.Render();
+
+  // Load image2 + image1 apply mask + image2 apply mask = total 3 event trigger required.
+  // Note that we use cached mask image.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(observer1.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer1.mObserverCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mLoaded, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
+
+  try
+  {
+    // Remove textureId1 first, and then remove textureId2. Check whether segfault occured.
+    textureManager.Remove(textureId1, &observer1);
+    textureManager.Remove(textureId2, &observer2);
+
+    TestObserver observer3;
+    maskInfo.reset(new TextureManager::MaskingData());
+    maskInfo->mAlphaMaskUrl       = maskname;
+    maskInfo->mAlphaMaskId        = TextureManager::INVALID_TEXTURE_ID;
+    maskInfo->mCropToMask         = true;
+    maskInfo->mContentScaleFactor = 1.0f;
+
+    textureManager.LoadTexture(
+      filename,
+      ImageDimensions(),
+      FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR,
+      maskInfo,
+      synchronousLoading,
+      textureId1,
+      atlasRect,
+      atlasRectSize,
+      atlasingStatus,
+      loadingStatus,
+      &observer3,
+      atlasUploadObserver,
+      atlasManager,
+      true,
+      TextureManager::ReloadPolicy::CACHED,
+      preMultiply);
+
+    DALI_TEST_EQUALS(observer3.mLoaded, false, TEST_LOCATION);
+    DALI_TEST_EQUALS(observer3.mObserverCalled, false, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render();
+
+    // Load image and mask image.
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+    DALI_TEST_EQUALS(observer3.mLoaded, false, TEST_LOCATION);
+    DALI_TEST_EQUALS(observer3.mObserverCalled, false, TEST_LOCATION);
+
+    // Apply mask.
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+    DALI_TEST_EQUALS(observer3.mLoaded, true, TEST_LOCATION);
+    DALI_TEST_EQUALS(observer3.mObserverCalled, true, TEST_LOCATION);
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(false);
+  }
+
+  END_TEST;
+}
index 0c89aad..f761781 100644 (file)
@@ -37,8 +37,8 @@ constexpr auto INITIAL_HASH_NUMBER                     = size_t{0u};
 constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS  = size_t{4u};
 constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u};
 
-constexpr auto TEXTURE_INDEX       = 0u; ///< The Index for texture
-constexpr auto MASK_TEXTURE_INDEX  = 1u; ///< The Index for mask texture
+constexpr auto TEXTURE_INDEX      = 0u; ///< The Index for texture
+constexpr auto MASK_TEXTURE_INDEX = 1u; ///< The Index for mask texture
 
 constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV  = "DALI_TEXTURE_LOCAL_THREADS";
 constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS";
@@ -710,7 +710,7 @@ void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureU
     if(textureCacheIndex != INVALID_CACHE_INDEX)
     {
       TextureManager::TextureId maskTextureId = INVALID_TEXTURE_ID;
-      TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]);
+      TextureInfo&              textureInfo(mTextureCacheManager[textureCacheIndex]);
       if(textureInfo.maskTextureId != INVALID_TEXTURE_ID)
       {
         maskTextureId = textureInfo.maskTextureId;
@@ -741,6 +741,12 @@ void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureU
         // Remove its observer
         RemoveTextureObserver(textureInfo, observer);
 
+        // Keep loadState due to the textureInfo validate problem.
+        auto textureLoadState = textureInfo.loadState;
+
+        // Remove textureId in CacheManager
+        mTextureCacheManager.RemoveCache(textureInfo);
+
         // Remove maskTextureId in CacheManager
         if(maskTextureId != INVALID_TEXTURE_ID)
         {
@@ -750,15 +756,12 @@ void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureU
             TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
 
             // Only Remove maskTexture when texture's loadState is not CANCELLED. because it is already deleted.
-            if(textureInfo.loadState != LoadState::CANCELLED)
+            if(textureLoadState != LoadState::CANCELLED)
             {
               mTextureCacheManager.RemoveCache(maskTextureInfo);
             }
           }
         }
-
-        // Remove textureId in CacheManager
-        mTextureCacheManager.RemoveCache(textureInfo);
       }
     }
 
@@ -1210,7 +1213,7 @@ void TextureManager::UploadTextures(std::vector<Devel::PixelBuffer>& pixelBuffer
 
     for(auto&& pixelBuffer : pixelBuffers)
     {
-      Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
+      Texture   texture   = Texture::New(Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
       PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
       texture.Upload(pixelData);
       textureInfo.textures.push_back(texture);
@@ -1346,7 +1349,7 @@ void TextureManager::EmitLoadComplete(TextureUploadObserver* observer, TextureMa
 
 TextureSet TextureManager::GetTextureSet(const TextureManager::TextureId& textureId)
 {
-  TextureSet textureSet;
+  TextureSet                textureSet;
   TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
   if(loadState == TextureManager::LoadState::UPLOADED)
   {
@@ -1406,8 +1409,8 @@ void TextureManager::RemoveTextureObserver(TextureManager::TextureInfo& textureI
   // Remove its observer
   if(observer)
   {
-    const auto   iterEnd = textureInfo.observerList.End();
-    const auto   iter    = std::find(textureInfo.observerList.Begin(), iterEnd, observer);
+    const auto iterEnd = textureInfo.observerList.End();
+    const auto iter    = std::find(textureInfo.observerList.Begin(), iterEnd, observer);
     if(iter != iterEnd)
     {
       // Disconnect and remove the observer.