From: seungho Date: Thu, 28 Apr 2022 05:54:59 +0000 (+0900) Subject: CPU Alpha Masking for Animated Image Visual X-Git-Tag: dali_2.1.22~3 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=4464c30c30e68c6eee56cda1a201b22eb164fd20 CPU Alpha Masking for Animated Image Visual Change-Id: I3b6abac73d248f70998bb992945b96a25c6fb7c8 Signed-off-by: seungho --- diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp index 1fffc97..55745fb 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp @@ -46,8 +46,9 @@ void dali_animated_image_visual_cleanup(void) namespace { -const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/application-icon-%02d.png"; -const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif"; +const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/application-icon-%02d.png"; +const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif"; +const char* TEST_MASK_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/mask.png"; } // namespace void CopyUrlsIntoArray(Property::Array& urls, int startIndex = 0) @@ -78,6 +79,9 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void) .Add(ImageVisual::Property::PIXEL_AREA, Vector4()) .Add(ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT) .Add(ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT) + .Add(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME) + .Add(ImageVisual::Property::MASK_CONTENT_SCALE, 1.6f) + .Add(ImageVisual::Property::CROP_TO_MASK, true) .Add(DevelVisual::Property::CORNER_RADIUS, 22.2f) .Add(DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE) .Add(DevelVisual::Property::BORDERLINE_WIDTH, 33.3f) @@ -115,6 +119,23 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void) DALI_TEST_CHECK(value); DALI_TEST_EQUALS(value->Get(), 0.3f, TEST_LOCATION); + // Check mask properties + value = resultMap.Find(ImageVisual::Property::ALPHA_MASK_URL, Property::STRING); + DALI_TEST_CHECK(value); + DALI_TEST_CHECK(value->Get() == TEST_MASK_IMAGE_FILE_NAME); + + value = resultMap.Find(ImageVisual::Property::MASK_CONTENT_SCALE, Property::FLOAT); + DALI_TEST_CHECK(value); + DALI_TEST_EQUALS(value->Get(), 1.6f, TEST_LOCATION); + + value = resultMap.Find(ImageVisual::Property::CROP_TO_MASK, Property::BOOLEAN); + DALI_TEST_CHECK(value); + DALI_TEST_EQUALS(value->Get(), true, TEST_LOCATION); + + Vector2 naturalSize; + animatedImageVisual.GetNaturalSize(naturalSize); + DALI_TEST_EQUALS(naturalSize, Vector2(100, 100), TEST_LOCATION); + // request AnimatedImageVisual with an URL Visual::Base animatedImageVisual2 = factory.CreateVisual(TEST_GIF_FILE_NAME, ImageDimensions()); resultMap.Clear(); @@ -152,6 +173,9 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void) .Add("pixelArea", Vector4()) .Add("wrapModeU", WrapMode::REPEAT) .Add("wrapModeV", WrapMode::DEFAULT) + .Add("alphaMaskUrl", TEST_MASK_IMAGE_FILE_NAME) + .Add("maskContentScale", 1.6f) + .Add("cropToMask", true) .Add("cornerRadius", Vector4(50.0f, 25.0f, 12.5f, 33.0f)) .Add("cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE) .Add("borderlineWidth", 20.0f) @@ -211,6 +235,19 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void) DALI_TEST_CHECK(value); DALI_TEST_EQUALS(value->Get(), -1.0f, TEST_LOCATION); + // Check mask properties + value = resultMap.Find(ImageVisual::Property::ALPHA_MASK_URL, "alphaMaskUrl"); + DALI_TEST_CHECK(value); + DALI_TEST_CHECK(value->Get() == TEST_MASK_IMAGE_FILE_NAME); + + value = resultMap.Find(ImageVisual::Property::MASK_CONTENT_SCALE, "maskContentScale"); + DALI_TEST_CHECK(value); + DALI_TEST_EQUALS(value->Get(), 1.6f, TEST_LOCATION); + + value = resultMap.Find(ImageVisual::Property::CROP_TO_MASK, "cropToMask"); + DALI_TEST_CHECK(value); + DALI_TEST_EQUALS(value->Get(), true, TEST_LOCATION); + END_TEST; } @@ -235,6 +272,9 @@ int UtcDaliAnimatedImageVisualGetPropertyMap03(void) .Add("pixelArea", Vector4()) .Add("wrapModeU", WrapMode::REPEAT) .Add("wrapModeV", WrapMode::DEFAULT) + .Add("alphaMaskUrl", TEST_MASK_IMAGE_FILE_NAME) + .Add("maskContentScale", 1.6f) + .Add("cropToMask", true) .Add("cornerRadius", 50.5f)); Property::Map resultMap; @@ -290,6 +330,19 @@ int UtcDaliAnimatedImageVisualGetPropertyMap03(void) DALI_TEST_CHECK(value); DALI_TEST_EQUALS(value->Get(), 0.0f, TEST_LOCATION); + // Check mask properties + value = resultMap.Find(ImageVisual::Property::ALPHA_MASK_URL, "alphaMaskUrl"); + DALI_TEST_CHECK(value); + DALI_TEST_CHECK(value->Get() == TEST_MASK_IMAGE_FILE_NAME); + + value = resultMap.Find(ImageVisual::Property::MASK_CONTENT_SCALE, "maskContentScale"); + DALI_TEST_CHECK(value); + DALI_TEST_EQUALS(value->Get(), 1.6f, TEST_LOCATION); + + value = resultMap.Find(ImageVisual::Property::CROP_TO_MASK, "cropToMask"); + DALI_TEST_CHECK(value); + DALI_TEST_EQUALS(value->Get(), true, TEST_LOCATION); + END_TEST; } @@ -472,6 +525,63 @@ int UtcDaliAnimatedImageVisualSynchronousLoading(void) END_TEST; } + +int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask(void) +{ + ToolkitTestApplication application; + TestGlAbstraction& gl = application.GetGlAbstraction(); + + { + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME); + propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2); + propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 2); + propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20); + propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true); + propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME); + propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, 0.23f); + propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual(propertyMap); + + Property::Map testMap; + visual.CreatePropertyMap(testMap); + DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL), Property::Value(TEST_MASK_IMAGE_FILE_NAME), TEST_LOCATION); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual); + + dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + application.GetScene().Add(dummyControl); + + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.SendNotification(); + application.Render(20); + + // The first frame is loaded synchronously and load next batch with masking + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::GetTimerCount(), 1, TEST_LOCATION); + DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 2, TEST_LOCATION); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(16); + DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION); + + END_TEST; +} + int UtcDaliAnimatedImageVisualJumpToAction(void) { ToolkitTestApplication application; @@ -737,6 +847,52 @@ int UtcDaliAnimatedImageVisualAnimatedImage01(void) END_TEST; } +int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask01(void) +{ + ToolkitTestApplication application; + TestGlAbstraction& gl = application.GetGlAbstraction(); + + { + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME); + propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2); + propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 4); + propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20); + propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME); + + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual(propertyMap); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual); + + dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + application.GetScene().Add(dummyControl); + + application.SendNotification(); + application.Render(); + + // load two frame(batch size), load mask image, and request two masking + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(5), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(20); + + DALI_TEST_EQUALS(gl.GetLastGenTextureId(), 2, TEST_LOCATION); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(20); + DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION); + + END_TEST; +} + int UtcDaliAnimatedImageVisualMultiImage01(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp index 390bb20..880a075 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -138,15 +138,17 @@ TextureManager::~TextureManager() } } -TextureSet TextureManager::LoadAnimatedImageTexture(Dali::AnimatedImageLoading animatedImageLoading, - const uint32_t& frameIndex, - TextureManager::TextureId& textureId, - const Dali::SamplingMode::Type& samplingMode, - const Dali::WrapMode::Type& wrapModeU, - const Dali::WrapMode::Type& wrapModeV, - const bool& synchronousLoading, - const bool& useCache, - TextureUploadObserver* textureObserver) +TextureSet TextureManager::LoadAnimatedImageTexture( + Dali::AnimatedImageLoading animatedImageLoading, + const uint32_t& frameIndex, + TextureManager::TextureId& textureId, + MaskingDataPointer& maskInfo, + const Dali::SamplingMode::Type& samplingMode, + const Dali::WrapMode::Type& wrapModeU, + const Dali::WrapMode::Type& wrapModeV, + const bool& synchronousLoading, + const bool& useCache, + TextureUploadObserver* textureObserver) { TextureSet textureSet; @@ -163,6 +165,18 @@ TextureSet TextureManager::LoadAnimatedImageTexture(Dali::AnimatedImageLoading } else { + if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) + { + Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); + if(maskPixelBuffer) + { + pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + } + else + { + DALI_LOG_ERROR("TextureManager::LoadAnimatedImageTexture: Synchronous mask image loading is failed\n"); + } + } PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer if(!textureSet) { @@ -175,8 +189,20 @@ TextureSet TextureManager::LoadAnimatedImageTexture(Dali::AnimatedImageLoading } else { - auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; - textureId = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex, false, useCache); + TextureId alphaMaskId = INVALID_TEXTURE_ID; + float contentScaleFactor = 1.0f; + bool cropToMask = false; + if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) + { + maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl); + alphaMaskId = maskInfo->mAlphaMaskId; + contentScaleFactor = maskInfo->mContentScaleFactor; + cropToMask = maskInfo->mCropToMask; + } + + auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + textureId = RequestLoadInternal(animatedImageLoading.GetUrl(), alphaMaskId, contentScaleFactor, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex, false, useCache); + TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId); if(loadState == TextureManager::LoadState::UPLOADED) { diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.h b/dali-toolkit/internal/texture-manager/texture-manager-impl.h index ee1f065..36219cc 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.h +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.h @@ -115,6 +115,7 @@ public: * @param[in] animatedImageLoading The AnimatedImageLoading that contain the animated image information * @param[in] frameIndex The frame index to load. * @param[out] textureId The textureId of the frame + * @param[in, out] maskInfo Mask info structure * @param[in] samplingMode The SamplingMode to use * @param[in] wrapModeU Horizontal Wrap mode * @param[in] wrapModeV Vertical Wrap mode @@ -128,6 +129,7 @@ public: TextureSet LoadAnimatedImageTexture(Dali::AnimatedImageLoading animatedImageLoading, const uint32_t& frameIndex, TextureManager::TextureId& textureId, + MaskingDataPointer& maskInfo, const Dali::SamplingMode::Type& samplingMode, const Dali::WrapMode::Type& wrapModeU, const Dali::WrapMode::Type& wrapModeV, 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 be73cca..b704d34 100644 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -175,7 +175,7 @@ void AnimatedImageVisual::CreateImageCache() if(mAnimatedImageLoading) { - mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, *this, mCacheSize, mBatchSize, IsSynchronousLoadingRequired()); + mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, IsSynchronousLoadingRequired()); } else if(mImageUrls) { @@ -186,11 +186,11 @@ void AnimatedImageVisual::CreateImageCache() uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE); if(cacheSize < numUrls) { - mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, cacheSize, batchSize, mFrameDelay); + mImageCache = new RollingImageCache(textureManager, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay); } else { - mImageCache = new FixedImageCache(textureManager, *mImageUrls, *this, batchSize, mFrameDelay); + mImageCache = new FixedImageCache(textureManager, *mImageUrls, mMaskingData, *this, batchSize, mFrameDelay); } } @@ -219,6 +219,7 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image mCurrentLoopIndex(FIRST_LOOP), mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED), mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED), + mMaskingData(), mFrameCount(0), mImageSize(), mActionStatus(DevelAnimatedImageVisual::Action::PLAY), @@ -246,6 +247,19 @@ void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize) { if(mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0) { + if(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid() && + mMaskingData->mCropToMask) + { + ImageDimensions dimensions = Dali::GetClosestImageSize(mMaskingData->mAlphaMaskUrl.GetUrl()); + if(dimensions != ImageDimensions(0, 0)) + { + mImageSize = dimensions; + naturalSize.x = dimensions.GetWidth(); + naturalSize.y = dimensions.GetHeight(); + return; + } + } + if(mImageUrl.IsValid()) { mImageSize = mAnimatedImageLoading.GetImageSize(); @@ -298,6 +312,13 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior); + if(mMaskingData != nullptr) + { + map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl()); + map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor); + map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask); + } + map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy); map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy); } @@ -413,6 +434,18 @@ void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap) { DoSetProperty(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second); } + else if(keyValue.first == ALPHA_MASK_URL) + { + DoSetProperty(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second); + } + else if(keyValue.first == MASK_CONTENT_SCALE_NAME) + { + DoSetProperty(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second); + } + else if(keyValue.first == CROP_TO_MASK_NAME) + { + DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second); + } else if(keyValue.first == LOAD_POLICY_NAME) { DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second); @@ -554,6 +587,39 @@ void AnimatedImageVisual::DoSetProperty(Property::Index index, break; } + case Toolkit::ImageVisual::Property::ALPHA_MASK_URL: + { + std::string alphaUrl = ""; + if(value.Get(alphaUrl)) + { + AllocateMaskData(); + mMaskingData->mAlphaMaskUrl = alphaUrl; + } + break; + } + + case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE: + { + float scale = 1.0f; + if(value.Get(scale)) + { + AllocateMaskData(); + mMaskingData->mContentScaleFactor = scale; + } + break; + } + + case Toolkit::ImageVisual::Property::CROP_TO_MASK: + { + bool crop = false; + if(value.Get(crop)) + { + AllocateMaskData(); + mMaskingData->mCropToMask = crop; + } + break; + } + case Toolkit::ImageVisual::Property::RELEASE_POLICY: { int releasePolicy = 0; @@ -851,6 +917,14 @@ TextureSet AnimatedImageVisual::SetLoadingFailed() return textureSet; } +void AnimatedImageVisual::AllocateMaskData() +{ + if(!mMaskingData) + { + mMaskingData.reset(new TextureManager::MaskingData()); + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h index 5e70964..4acb736 100644 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h @@ -241,6 +241,12 @@ private: */ TextureSet SetLoadingFailed(); + /** + * @brief Allocate mask data. + * This is allocated only once. + */ + void AllocateMaskData(); + // Undefined AnimatedImageVisual(const AnimatedImageVisual& animatedImageVisual); @@ -268,9 +274,10 @@ private: int16_t mLoopCount; int16_t mCurrentLoopIndex; - // Variables for image visual policy. + // Variables for image visual properties. Dali::Toolkit::ImageVisual::LoadPolicy::Type mLoadPolicy; Dali::Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy; + TextureManager::MaskingDataPointer mMaskingData; // Shared variables uint32_t mFrameCount; // Number of frames 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 192a3c4..8cc69ff 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp @@ -35,9 +35,13 @@ constexpr bool ENABLE_ORIENTATION_CORRECTION(true); constexpr uint32_t FIRST_FRAME_INDEX = 0u; } // namespace -FixedImageCache::FixedImageCache( - TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint32_t batchSize, uint32_t interval) -: ImageCache(textureManager, observer, batchSize, interval), +FixedImageCache::FixedImageCache(TextureManager& textureManager, + UrlList& urlList, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint32_t batchSize, + uint32_t interval) +: ImageCache(textureManager, maskingData, observer, batchSize, interval), mImageUrls(urlList), mFront(FIRST_FRAME_INDEX) { @@ -122,7 +126,6 @@ void FixedImageCache::LoadBatch() bool synchronousLoading = false; bool atlasingStatus = false; bool loadingStatus = false; - TextureManager::MaskingDataPointer maskInfo = nullptr; AtlasUploadObserver* atlasObserver = nullptr; ImageAtlasManagerPtr imageAtlasManager = nullptr; Vector4 textureRect; @@ -130,7 +133,7 @@ void FixedImageCache::LoadBatch() auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; mTextureManager.LoadTexture( - url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[frameIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply); + url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, mMaskingData, synchronousLoading, mImageUrls[frameIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply); mRequestingLoad = false; } @@ -157,10 +160,21 @@ void FixedImageCache::ClearCache() { mTextureManager.Remove(mImageUrls[i].mTextureId, this); mImageUrls[i].mTextureId = TextureManager::INVALID_TEXTURE_ID; + + if(mMaskingData && mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID) + { + // In the CPU alpha masking, each frame increases reference count of masking texture. + // We should call TextureManager::Remove to decrease reference count when each frame is removed. + mTextureManager.Remove(mMaskingData->mAlphaMaskId, this); + } } } mReadyFlags.clear(); mLoadState = TextureManager::LoadState::NOT_STARTED; + if(mMaskingData) + { + mMaskingData->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID; + } } void FixedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation) diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h index 2d446f0..c798a66 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h @@ -33,19 +33,21 @@ public: /** * Constructor. * @param[in] textureManager The texture manager - * @param[in] urlList List of urls to cache - * @param[in] observer FrameReady observer - * @param[in] batchSize The size of a batch to load - * @param[in] interval Time interval between each frame + * @param[in] urlList List of urls to cache + * @param[in] maskingData Masking data to be applied. + * @param[in] observer FrameReady observer + * @param[in] batchSize The size of a batch to load + * @param[in] interval Time interval between each frame * * This will start loading textures immediately, according to the * batch and cache sizes. The cache is as large as the number of urls. */ - FixedImageCache(TextureManager& textureManager, - UrlList& urlList, - ImageCache::FrameReadyObserver& observer, - uint32_t batchSize, - uint32_t interval); + FixedImageCache(TextureManager& textureManager, + UrlList& urlList, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint32_t batchSize, + uint32_t interval); ~FixedImageCache() override; diff --git a/dali-toolkit/internal/visuals/animated-image/image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/image-cache.cpp index 27c3ef2..59f0520 100644 --- a/dali-toolkit/internal/visuals/animated-image/image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/image-cache.cpp @@ -22,12 +22,14 @@ namespace Toolkit { namespace Internal { -ImageCache::ImageCache(TextureManager& textureManager, - ImageCache::FrameReadyObserver& observer, - uint32_t batchSize, - uint32_t interval) +ImageCache::ImageCache(TextureManager& textureManager, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint32_t batchSize, + uint32_t interval) : mTextureManager(textureManager), mObserver(observer), + mMaskingData(maskingData), mBatchSize(batchSize), mInterval(interval), mLoadState(TextureManager::LoadState::NOT_STARTED), diff --git a/dali-toolkit/internal/visuals/animated-image/image-cache.h b/dali-toolkit/internal/visuals/animated-image/image-cache.h index 19a8f52..65f39df 100644 --- a/dali-toolkit/internal/visuals/animated-image/image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/image-cache.h @@ -61,16 +61,18 @@ public: * @param[in] textureManager The texture manager * @param[in] urlList List of urls to cache * @param[in] observer FrameReady observer + * @param[in] maskingData Masking data to be applied. * @param[in] batchSize The size of a batch to load - * @param[in] interval Time interval(ms) between each frame + * @param[in] interval Time interval(ms) between each frame * * This will start loading textures immediately, according to the * batch and cache sizes. The cache is as large as the number of urls. */ - ImageCache(TextureManager& textureManager, - ImageCache::FrameReadyObserver& observer, - uint32_t batchSize, - uint32_t interval); + ImageCache(TextureManager& textureManager, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint32_t batchSize, + uint32_t interval); virtual ~ImageCache(); @@ -132,18 +134,21 @@ private: */ void TextureManagerDestroyed() final; + void AllocateMaskData(); + protected: - TextureManager& mTextureManager; - FrameReadyObserver& mObserver; - uint32_t mBatchSize; - uint32_t mInterval; - TextureManager::LoadState mLoadState; - bool mRequestingLoad : 1; - bool mTextureManagerAlive : 1; + TextureManager& mTextureManager; + FrameReadyObserver& mObserver; + TextureManager::MaskingDataPointer& mMaskingData; + uint32_t mBatchSize; + uint32_t mInterval; + TextureManager::LoadState mLoadState; + bool mRequestingLoad : 1; + bool mTextureManagerAlive : 1; }; -} //namespace Internal -} //namespace Toolkit -} //namespace Dali +} // namespace Internal +} // namespace Toolkit +} // namespace Dali #endif // DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H 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 473f276..e5ea68e 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 @@ -59,9 +59,14 @@ static constexpr uint32_t SINGLE_IMAGE_COUNT = 1u; static constexpr uint32_t FIRST_FRAME_INDEX = 0u; } // namespace -RollingAnimatedImageCache::RollingAnimatedImageCache( - TextureManager& textureManager, AnimatedImageLoading& animatedImageLoading, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, bool isSynchronousLoading) -: ImageCache(textureManager, observer, batchSize, 0u), +RollingAnimatedImageCache::RollingAnimatedImageCache(TextureManager& textureManager, + AnimatedImageLoading& animatedImageLoading, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint16_t cacheSize, + uint16_t batchSize, + bool isSynchronousLoading) +: ImageCache(textureManager, maskingData, observer, batchSize, 0u), mAnimatedImageLoading(animatedImageLoading), mFrameCount(SINGLE_IMAGE_COUNT), mFrameIndex(FIRST_FRAME_INDEX), @@ -84,10 +89,8 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex) bool popExist = false; while(!mQueue.IsEmpty() && mQueue.Front().mFrameNumber != frameIndex) { - ImageFrame imageFrame = mQueue.PopFront(); - mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this); - mImageUrls[imageFrame.mFrameNumber].mTextureId = TextureManager::INVALID_TEXTURE_ID; - popExist = true; + PopFrontCache(); + popExist = true; } TextureSet textureSet; @@ -191,6 +194,7 @@ TextureSet RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex, b TextureSet textureSet = mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading, frameIndex, loadTextureId, + mMaskingData, SamplingMode::BOX_THEN_LINEAR, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, @@ -252,13 +256,27 @@ TextureManager::TextureId RollingAnimatedImageCache::GetCachedTextureId(int inde return mImageUrls[mQueue[index].mFrameNumber].mTextureId; } +void RollingAnimatedImageCache::PopFrontCache() +{ + ImageFrame imageFrame = mQueue.PopFront(); + mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this); + mImageUrls[imageFrame.mFrameNumber].mTextureId = TextureManager::INVALID_TEXTURE_ID; + + if(mMaskingData && mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID) + { + mTextureManager.Remove(mMaskingData->mAlphaMaskId, this); + if(mQueue.IsEmpty()) + { + mMaskingData->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID; + } + } +} + void RollingAnimatedImageCache::ClearCache() { while(mTextureManagerAlive && !mQueue.IsEmpty()) { - ImageFrame imageFrame = mQueue.PopFront(); - mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this); - mImageUrls[imageFrame.mFrameNumber].mTextureId = TextureManager::INVALID_TEXTURE_ID; + PopFrontCache(); } mLoadWaitingQueue.clear(); mLoadState = TextureManager::LoadState::NOT_STARTED; diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h index 605fbb9..1b383b5 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h @@ -41,22 +41,24 @@ class RollingAnimatedImageCache : public ImageCache, public TextureUploadObserve public: /** * @brief Constructor. - * @param[in] textureManager The texture manager - * @param[in] animatedImageLoader The loaded animated image - * @param[in] observer FrameReady observer - * @param[in] cacheSize The size of the cache - * @param[in] batchSize The size of a batch to load + * @param[in] textureManager The texture manager + * @param[in] animatedImageLoading The loaded animated image + * @param[in] maskingData Masking data to be applied. + * @param[in] observer FrameReady observer + * @param[in] cacheSize The size of the cache + * @param[in] batchSize The size of a batch to load * @param[in] isSynchronousLoading The flag to define whether to load first frame synchronously * * This will start loading textures immediately, according to the * batch and cache sizes. */ - RollingAnimatedImageCache(TextureManager& textureManager, - AnimatedImageLoading& animatedImageLoader, - ImageCache::FrameReadyObserver& observer, - uint16_t cacheSize, - uint16_t batchSize, - bool isSynchronousLoading); + RollingAnimatedImageCache(TextureManager& textureManager, + AnimatedImageLoading& animatedImageLoading, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint16_t cacheSize, + uint16_t batchSize, + bool isSynchronousLoading); /** * @brief Destructor @@ -149,6 +151,11 @@ private: */ void MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval); + /** + * @brief Pop front entity of Cache. + */ + void PopFrontCache(); + protected: /** * @copydoc Toolkit::TextureUploadObserver::LoadComplete() 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 08fe0d0..c0c598a 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp @@ -56,9 +56,14 @@ namespace Toolkit { namespace Internal { -RollingImageCache::RollingImageCache( - TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, uint32_t interval) -: ImageCache(textureManager, observer, batchSize, interval), +RollingImageCache::RollingImageCache(TextureManager& textureManager, + UrlList& urlList, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint16_t cacheSize, + uint16_t batchSize, + uint32_t interval) +: ImageCache(textureManager, maskingData, observer, batchSize, interval), mImageUrls(urlList), mQueue(cacheSize) { @@ -75,9 +80,7 @@ TextureSet RollingImageCache::Frame(uint32_t frameIndex) bool popExist = false; while(!mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex) { - ImageFrame imageFrame = mQueue.PopFront(); - mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this); - mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID; + PopFrontCache(); popExist = true; } @@ -156,7 +159,6 @@ void RollingImageCache::LoadBatch(uint32_t frameIndex) bool synchronousLoading = false; bool atlasingStatus = false; bool loadingStatus = false; - TextureManager::MaskingDataPointer maskInfo = nullptr; AtlasUploadObserver* atlasObserver = nullptr; ImageAtlasManagerPtr imageAtlasManager = nullptr; Vector4 textureRect; @@ -165,7 +167,7 @@ void RollingImageCache::LoadBatch(uint32_t frameIndex) TextureManager::TextureId loadTextureId = TextureManager::INVALID_TEXTURE_ID; TextureSet textureSet = mTextureManager.LoadTexture( - url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, loadTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply); + url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, mMaskingData, synchronousLoading, loadTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply); mImageUrls[imageFrame.mUrlIndex].mTextureId = loadTextureId; mRequestingLoad = false; @@ -186,13 +188,27 @@ TextureManager::TextureId RollingImageCache::GetCachedTextureId(int index) const return mImageUrls[mQueue[index].mUrlIndex].mTextureId; } +void RollingImageCache::PopFrontCache() +{ + ImageFrame imageFrame = mQueue.PopFront(); + mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this); + mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID; + + if(mMaskingData && mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID) + { + mTextureManager.Remove(mMaskingData->mAlphaMaskId, this); + if(mQueue.IsEmpty()) + { + mMaskingData->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID; + } + } +} + void RollingImageCache::ClearCache() { while(mTextureManagerAlive && !mQueue.IsEmpty()) { - ImageFrame imageFrame = mQueue.PopFront(); - mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this); - mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID; + PopFrontCache(); } mLoadState = TextureManager::LoadState::NOT_STARTED; } diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h index 98ba45c..e01f17f 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h @@ -38,21 +38,23 @@ public: /** * Constructor. * @param[in] textureManager The texture manager - * @param[in] urlList List of urls to cache - * @param[in] observer FrameReady observer - * @param[in] cacheSize The size of the cache - * @param[in] batchSize The size of a batch to load - * @param[in] interval Time interval between each frame + * @param[in] urlList List of urls to cache + * @param[in] maskingData Masking data to be applied. + * @param[in] observer FrameReady observer + * @param[in] cacheSize The size of the cache + * @param[in] batchSize The size of a batch to load + * @param[in] interval Time interval between each frame * * This will start loading textures immediately, according to the * batch and cache sizes. */ - RollingImageCache(TextureManager& textureManager, - UrlList& urlList, - ImageCache::FrameReadyObserver& observer, - uint16_t cacheSize, - uint16_t batchSize, - uint32_t interval); + RollingImageCache(TextureManager& textureManager, + UrlList& urlList, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint16_t cacheSize, + uint16_t batchSize, + uint32_t interval); /** * Destructor @@ -119,11 +121,9 @@ private: TextureManager::TextureId GetCachedTextureId(int index) const; /** - * @brief Check if the front frame has become ready - if so, inform observer - * - * @param[in] wasReady Readiness before call. + * @brief Pop front entity of Cache. */ - void CheckFrontFrame(bool wasReady); + void PopFrontCache(); protected: /**