From ec9ab53bc6b975200ac45d0d5fb25774f000acce Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Thu, 25 May 2023 18:51:20 +0900 Subject: [PATCH] [Tizen] Do not observe when Reload Previously, we add same observer multiple times when image is loading state and user do Reload action multiple times. In that case, there might be problem if visual destroyed. Change-Id: Iab8b193281649783b80a6e9fb89e86c625b4388a Signed-off-by: Eunki, Hong --- .../src/dali-toolkit/utc-Dali-Control.cpp | 170 ++++++++++++++++++++- .../texture-manager/texture-manager-impl.cpp | 28 +++- 2 files changed, 193 insertions(+), 5 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp index fbca3b6..7e48e46 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -1245,3 +1245,171 @@ int UtcDaliControlDoActionWhenNotStage(void) END_TEST; } + +int UtcDaliControlDoActionMultipleWhenNotStage01(void) +{ + ToolkitTestApplication application; + tet_infoline("DoAction on a visual registered with a control multiple times but not staged"); + + // Set up trace debug + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + //Created AnimatedImageVisual + VisualFactory factory = VisualFactory::Get(); + Visual::Base imageVisual = factory.CreateVisual(TEST_IMAGE_FILE_NAME, ImageDimensions()); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, imageVisual); + dummyControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION); + DALI_TEST_EQUALS(textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION); + textureTrace.Reset(); + + Property::Map attributes; + const uint32_t repeatMax = 10u; + for(uint32_t repeatCnt = 0u; repeatCnt < repeatMax; ++repeatCnt) + { + // DoAction multiple times. + DevelControl::DoAction(dummyControl, DummyControl::Property::TEST_VISUAL, DevelImageVisual::Action::RELOAD, attributes); + } + + tet_infoline("Perform RELOAD action. should reload Image and generate a texture"); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION); + textureTrace.Reset(); + + tet_infoline("Do not load image on more time even we request reload multiple times."); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 1), false, TEST_LOCATION); + + tet_infoline("Adding control to stage will in turn add the visual to the stage"); + + application.GetScene().Add(dummyControl); + + application.SendNotification(); + application.Render(); + tet_infoline("No change in textures could occurs as already loaded and cached texture will be used"); + + DALI_TEST_EQUALS(textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION); + DALI_TEST_EQUALS(textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION); + textureTrace.Reset(); + + dummyControl.Unparent(); + dummyControl.Reset(); + application.SendNotification(); + application.Render(); + + END_TEST; +} + +int UtcDaliControlDoActionMultipleWhenNotStage02(void) +{ + ToolkitTestApplication application; + tet_infoline("DoAction on a visual registered with a control multiple times but not staged"); + + // Set up trace debug + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + //Created AnimatedImageVisual + VisualFactory factory = VisualFactory::Get(); + Visual::Base imageVisual = factory.CreateVisual(TEST_IMAGE_FILE_NAME, ImageDimensions()); + Visual::Base imageVisual2 = factory.CreateVisual(TEST_IMAGE_FILE_NAME, ImageDimensions()); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + + gResourceReadySignalFired = false; + + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, imageVisual); + dummyControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + dummyControl.ResourceReadySignal().Connect(&ResourceReadySignal); + + application.SendNotification(); + application.Render(); + + // Dummy control to keep cache + DummyControl keepCacheControl = DummyControl::New(true); + Impl::DummyControl& keepCacheImpl = static_cast(keepCacheControl.GetImplementation()); + + keepCacheImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, imageVisual2); + keepCacheControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + + Property::Map attributes; + const uint32_t repeatMax = 10u; + for(uint32_t repeatCnt = 0u; repeatCnt < repeatMax; ++repeatCnt) + { + // DoAction multiple times. + DevelControl::DoAction(dummyControl, DummyControl::Property::TEST_VISUAL, DevelImageVisual::Action::RELOAD, attributes); + } + + // Load request for keep cache control. + application.GetScene().Add(keepCacheControl); + + application.SendNotification(); + application.Render(); + + try + { + tet_infoline("Destroy control without stage on. And create new object that as same visual pointer as previous control"); + + const auto* imageVisualObjectPtr = imageVisual.GetObjectPtr(); + const uint32_t tryCountMax = 100u; + uint32_t tryCount = 0u; + do + { + dummyControl.Reset(); + imageVisual.Reset(); + + imageVisual = factory.CreateVisual(TEST_IMAGE_FILE_NAME, ImageDimensions()); + dummyControl = DummyControl::New(true); + + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, imageVisual); + dummyControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + } while(++tryCount < tryCountMax && imageVisualObjectPtr != imageVisual.GetObjectPtr()); + + tet_printf("Luck-trial count : %u. Success? %d\n", tryCount, imageVisualObjectPtr == imageVisual.GetObjectPtr()); + + // Connect signal + dummyControl.ResourceReadySignal().Connect(&ResourceReadySignal); + + application.SendNotification(); + application.Render(); + + tet_infoline("Async load completed after control destroyed. Sigabort should not be occured"); + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + tet_infoline("ResourceReady signal must not be fired!"); + DALI_TEST_EQUALS(gResourceReadySignalFired, false, TEST_LOCATION); + + tet_infoline("Texture generation occured"); + DALI_TEST_EQUALS(textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION); + DALI_TEST_EQUALS(textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION); + textureTrace.Reset(); + + tet_result(TET_PASS); + } + catch(...) + { + // Must not be throw exception. + tet_infoline("Exception occured!"); + tet_result(TET_FAIL); + } + + END_TEST; +} \ No newline at end of file diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp index 74463da..743e809 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -625,7 +625,11 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( case TextureManager::LoadState::MASK_APPLYING: case TextureManager::LoadState::MASK_APPLIED: { - ObserveTexture(textureInfo, observer); + // Do not observe even we reload forced when texture is already loading state. + if(TextureManager::ReloadPolicy::FORCED != reloadPolicy) + { + ObserveTexture(textureInfo, observer); + } break; } case TextureManager::LoadState::UPLOADED: @@ -782,7 +786,7 @@ void TextureManager::Remove(const TextureManager::TextureId& textureId) } } - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove( textureId=%d ) cacheIndex:%d removal maskTextureId=%d, loadingQueueTextureId=%d, loadState=%s\n", textureId, textureCacheIndex.GetIndex(), maskTextureId, mLoadingQueueTextureId, GET_LOAD_STATE_STRING(textureInfo.loadState)); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove( textureId=%d ) cacheIndex:%d removal maskTextureId=%d, loadState=%s\n", textureId, textureCacheIndex.GetIndex(), maskTextureId, GET_LOAD_STATE_STRING(textureInfo.loadState)); // Remove textureId in CacheManager. Now, textureInfo is invalidate. mTextureCacheManager.RemoveCache(textureInfo); @@ -794,6 +798,9 @@ void TextureManager::Remove(const TextureManager::TextureId& textureId) if(maskCacheIndex != INVALID_CACHE_INDEX) { TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]); + + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove mask texture( maskTextureId=%d ) cacheIndex:%d, loadState=%s\n", maskTextureId, maskCacheIndex.GetIndex(), GET_LOAD_STATE_STRING(maskTextureInfo.loadState)); + mTextureCacheManager.RemoveCache(maskTextureInfo); } } @@ -913,7 +920,10 @@ void TextureManager::LoadOrQueueTexture(TextureManager::TextureInfo& textureInfo { // The Texture has already loaded. The other observers have already been notified. // We need to send a "late" loaded notification for this observer. - EmitLoadComplete(observer, textureInfo, true); + if(observer) + { + EmitLoadComplete(observer, textureInfo, true); + } } break; } @@ -937,6 +947,7 @@ void TextureManager::QueueLoadTexture(const TextureManager::TextureInfo& texture if(observer) { + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Connect DestructionSignal to observer:%p\n", observer); observer->DestructionSignal().Connect(this, &TextureManager::ObserverDestroyed); } } @@ -973,6 +984,9 @@ void TextureManager::ProcessLoadQueue() if(cacheIndex != INVALID_CACHE_INDEX) { TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]); + + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::ProcessLoadQueue() textureId=%d, observer=%p, cacheIndex=@%d, loadState:%s\n", element.mTextureId, element.mObserver, cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState)); + if((textureInfo.loadState == LoadState::UPLOADED) || (textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER)) { if(element.mObserver) @@ -1003,6 +1017,8 @@ void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo, if(observer) { textureInfo.observerList.PushBack(observer); + + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Connect DestructionSignal to observer:%p\n", observer); observer->DestructionSignal().Connect(this, &TextureManager::ObserverDestroyed); } } @@ -1345,9 +1361,10 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c // invalidating the reference to the textureInfo struct. // Texture load requests for the same URL are deferred until the end of this // method. - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() textureId:%d url:%s loadState:%s\n", textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState)); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() observer:%p textureId:%d url:%s loadState:%s\n", observer, textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState)); // It is possible for the observer to be deleted. // Disconnect and remove the observer first. + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer); observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed); info->observerList.Erase(info->observerList.End() - 1u); @@ -1374,6 +1391,8 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c void TextureManager::ObserverDestroyed(TextureUploadObserver* observer) { + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::ObserverDestroyed() observer:%p\n", observer); + const std::size_t size = mTextureCacheManager.size(); for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index) { @@ -1495,6 +1514,7 @@ void TextureManager::RemoveTextureObserver(TextureManager::TextureInfo& textureI if(iter != iterEnd) { // Disconnect and remove the observer. + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer); observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed); textureInfo.observerList.Erase(iter); } -- 2.7.4