From: Eunki, Hong Date: Tue, 5 Apr 2022 03:32:45 +0000 (+0900) Subject: Make broken alpha mask image show image X-Git-Tag: dali_2.1.18~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F68%2F273368%2F7;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git Make broken alpha mask image show image Previous code only assume that ALPHA_MASK_URL load success. When we use alpha mask image invalid, the result become strange ; Most of image view not showing anything, but somtimes 1~2 image show broken. This patch make when we use that maskTextureId is load failed case. Change-Id: Ifd157d8b3a74c3a813d13ed3072c945d8ae8cda8 Signed-off-by: Eunki, Hong --- diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp index 6ec8617..e8088a3 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp @@ -591,6 +591,158 @@ int UtcTextureManagerUseInvalidMask(void) END_TEST; } +int UtcTextureManagerUseInvalidMaskAndMaskLoadedFirst(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcTextureManagerUseInvalidMask when normal image loaded first, and mask image loaded first"); + tet_infoline("Try to check PostLoad works well"); + + TextureManager textureManager; // Create new texture manager + + TestObserver observer; + std::string filename(TEST_IMAGE_FILE_NAME); + std::string maskname("invalid.png"); + 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; + + auto textureId(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, + textureId, + atlasRect, + atlasRectSize, + atlasingStatus, + loadingStatus, + WrapMode::DEFAULT, + WrapMode::DEFAULT, + &observer, + atlasUploadObserver, + atlasManager, + true, + TextureManager::ReloadPolicy::CACHED, + preMultiply); + + DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION); + DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(observer.mLoaded, true, TEST_LOCATION); + DALI_TEST_EQUALS(observer.mObserverCalled, true, TEST_LOCATION); + DALI_TEST_EQUALS(observer.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION); + + END_TEST; +} + +int UtcTextureManagerUseInvalidMaskAndMaskLoadedLater(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcTextureManagerUseInvalidMask when normal image loaded first, and mask image loaded later"); + tet_infoline("Try to check CheckForWaitingTexture called"); + + TextureManager textureManager; // Create new texture manager + + TestObserver observer; + std::string filename(TEST_IMAGE_FILE_NAME); + std::string maskname("invalid.png"); + 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; + + auto textureId(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, + textureId, + atlasRect, + atlasRectSize, + atlasingStatus, + loadingStatus, + WrapMode::DEFAULT, + WrapMode::DEFAULT, + &observer, + atlasUploadObserver, + atlasManager, + true, + TextureManager::ReloadPolicy::CACHED, + preMultiply); + + DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION); + DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + // CAPTION : HARD-CODING for coverage. If you are a good boy, Do not follow this code. + { + Dali::Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer( + filename, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + true, ///< synchronousLoading + nullptr, + true, ///< orientationCorrection + preMultiply); + + textureManager.AsyncLoadComplete(textureId, pixelBuffer); + textureManager.AsyncLoadComplete(maskInfo->mAlphaMaskId, Dali::Devel::PixelBuffer()); + textureManager.Remove(maskInfo->mAlphaMaskId, nullptr); + textureManager.Remove(textureId, &observer); + } + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(observer.mLoaded, true, TEST_LOCATION); + DALI_TEST_EQUALS(observer.mObserverCalled, true, TEST_LOCATION); + DALI_TEST_EQUALS(observer.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + + END_TEST; +} + int UtcTextureManagerSynchronousLoadingFail(void) { ToolkitTestApplication application; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index 823c2c2..ddd45ba 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -3128,6 +3128,12 @@ void OnResourceReadySignal03(Control control) gResourceReadySignalCounter++; } +void OnSimpleResourceReadySignal(Control control) +{ + // simply increate counter + gResourceReadySignalCounter++; +} + } // namespace int UtcDaliImageViewSetImageOnResourceReadySignal01(void) @@ -3228,3 +3234,105 @@ int UtcDaliImageViewSetImageOnResourceReadySignal03(void) END_TEST; } + +int UtcDaliImageViewOnResourceReadySignalWithBrokenAlphaMask01(void) +{ + tet_infoline("Test signal handler when image / mask image is broken."); + + ToolkitTestApplication application; + + auto TestResourceReadyUrl = [&application](int eventTriggerCount, bool isSynchronous, const std::string& url, const std::string& mask, const char* location) { + gResourceReadySignalCounter = 0; + + Property::Map map; + map[Toolkit::ImageVisual::Property::URL] = url; + if(!mask.empty()) + { + map[Toolkit::ImageVisual::Property::ALPHA_MASK_URL] = mask; + } + map[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = isSynchronous; + + ImageView imageView = ImageView::New(); + imageView[Toolkit::ImageView::Property::IMAGE] = map; + imageView[Actor::Property::SIZE] = Vector2(100.0f, 200.0f); + imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal); + + application.GetScene().Add(imageView); + application.SendNotification(); + application.Render(); + + if(!isSynchronous) + { + // Wait for loading + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(eventTriggerCount), true, location); + } + tet_printf("test %s [sync:%d] signal fired\n", url.c_str(), isSynchronous ? 1 : 0); + DALI_TEST_EQUALS(gResourceReadySignalCounter, 1, location); + + imageView.Unparent(); + }; + + for(int synchronous = 0; synchronous <= 1; synchronous++) + { + tet_printf("Test normal case (sync:%d)\n", synchronous); + TestResourceReadyUrl(1, synchronous, gImage_600_RGB, "", TEST_LOCATION); + TestResourceReadyUrl(3, synchronous, gImage_600_RGB, gImage_34_RGBA, TEST_LOCATION); // 3 event trigger required : 2 image load + 1 apply mask + + tet_printf("Test broken image case (sync:%d)\n", synchronous); + TestResourceReadyUrl(1, synchronous, "invalid.jpg", "", TEST_LOCATION); + TestResourceReadyUrl(2, synchronous, "invalid.jpg", gImage_34_RGBA, TEST_LOCATION); + + tet_printf("Test broken mask image case (sync:%d)\n", synchronous); + TestResourceReadyUrl(2, synchronous, gImage_600_RGB, "invalid.png", TEST_LOCATION); + + tet_printf("Test broken both image, mask image case (sync:%d)\n", synchronous); + TestResourceReadyUrl(2, synchronous, "invalid.jpg", "invalid.png", TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliImageViewOnResourceReadySignalWithBrokenAlphaMask02(void) +{ + tet_infoline("Test signal handler when image try to use cached-and-broken mask image."); + + ToolkitTestApplication application; + + gResourceReadySignalCounter = 0; + + auto TestBrokenMaskResourceReadyUrl = [&application](const std::string& url, const char* location) { + Property::Map map; + map[Toolkit::ImageVisual::Property::URL] = url; + // Use invalid mask url + map[Toolkit::ImageVisual::Property::ALPHA_MASK_URL] = "invalid.png"; + + ImageView imageView = ImageView::New(); + imageView[Toolkit::ImageView::Property::IMAGE] = map; + imageView[Actor::Property::SIZE] = Vector2(100.0f, 200.0f); + imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal); + + application.GetScene().Add(imageView); + application.SendNotification(); + application.Render(); + + // Don't unparent imageView, for keep the cache. + }; + + // Use more than 4 images (The number of LocalImageLoadThread) + const std::vector testUrlList = {gImage_34_RGBA, gImage_600_RGB, "invalid.jpg" /* invalid url */, TEST_IMAGE_1, TEST_IMAGE_2, TEST_BROKEN_IMAGE_DEFAULT}; + + int expectResourceReadySignalCounter = 0; + + for(auto& url : testUrlList) + { + TestBrokenMaskResourceReadyUrl(url, TEST_LOCATION); + expectResourceReadySignalCounter++; + } + + // Remain 1 signal due to we use #URL + 1 mask image. + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectResourceReadySignalCounter + 1), true, TEST_LOCATION); + + DALI_TEST_EQUALS(gResourceReadySignalCounter, expectResourceReadySignalCounter, TEST_LOCATION); + + 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 2890e6a..ff81b22 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -629,6 +629,10 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( { pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask); } + else + { + DALI_LOG_ERROR("Mask image cached invalid pixel buffer!\n"); + } } else { @@ -883,6 +887,13 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::P // Send New Task to Thread ApplyMask(textureInfo, textureInfo.maskTextureId); } + else // maskLoadState == LoadState::LOAD_FAILED + { + // Url texture load success, But alpha mask texture load failed. Run as normal image upload. + DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n"); + UploadTexture(pixelBuffer, textureInfo); + NotifyObservers(textureInfo, true); + } } } else @@ -911,8 +922,16 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::P else { textureInfo.loadState = LoadState::LOAD_FAILED; - CheckForWaitingTexture(textureInfo); - NotifyObservers(textureInfo, false); + if(textureInfo.storageType != StorageType::KEEP_PIXEL_BUFFER) + { + NotifyObservers(textureInfo, false); + } + else // if(textureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) // image mask case + { + // Check if there was another texture waiting for this load to complete + // (e.g. if this was an image mask, and its load is on a different thread) + CheckForWaitingTexture(textureInfo); + } } } @@ -922,6 +941,8 @@ void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTex // maskTextureId: const TextureCacheIndex size = static_cast(mTextureCacheManager.size()); + const bool maskLoadSuccess = maskTextureInfo.loadState == LoadState::LOAD_FINISHED ? true : false; + for(TextureCacheIndex cacheIndex = 0; cacheIndex < size; ++cacheIndex) { if(mTextureCacheManager[cacheIndex].maskTextureId == maskTextureInfo.textureId && @@ -929,16 +950,17 @@ void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTex { TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]); - if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED) + if(maskLoadSuccess) { // Send New Task to Thread ApplyMask(textureInfo, maskTextureInfo.textureId); } else { - textureInfo.pixelBuffer.Reset(); - textureInfo.loadState = LoadState::LOAD_FAILED; - NotifyObservers(textureInfo, false); + // Url texture load success, But alpha mask texture load failed. Run as normal image upload. + DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n"); + UploadTexture(textureInfo.pixelBuffer, textureInfo); + NotifyObservers(textureInfo, true); } } }