X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftexture-manager%2Ftexture-manager-impl.cpp;h=445ad658ea0b3d2e71bcfea2b818e5cc10d459cd;hb=5a936aac073676657d48db5c42e5d2ad3f5cac9f;hp=31c57c6cbb6c0d16c9c80186a4f384ecc33104f9;hpb=68c18cf776be4010ffa0a70209deb465a21a269c;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp index 31c57c6..445ad65 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -113,16 +113,21 @@ TextureManager::MaskingData::MaskingData() : mAlphaMaskUrl(), mAlphaMaskId(INVALID_TEXTURE_ID), mContentScaleFactor(1.0f), - mCropToMask(true) + mCropToMask(true), + mPreappliedMasking(true), + mMaskImageLoadingFailed(false) { } TextureManager::TextureManager() : mTextureCacheManager(), - mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }), - mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }), + mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() + { return TextureAsyncLoadingHelper(*this); }), + mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() + { return TextureAsyncLoadingHelper(*this); }), mLifecycleObservers(), mLoadQueue(), + mRemoveQueue(), mQueueLoadFlag(false) { // Initialize the AddOn @@ -138,14 +143,17 @@ TextureManager::~TextureManager() } TextureSet TextureManager::LoadAnimatedImageTexture( + const VisualUrl& url, Dali::AnimatedImageLoading animatedImageLoading, - const std::uint32_t& frameIndex, - const Dali::SamplingMode::Type& samplingMode, - const bool& synchronousLoading, + const uint32_t& frameIndex, TextureManager::TextureId& textureId, + MaskingDataPointer& maskInfo, + const Dali::SamplingMode::Type& samplingMode, const Dali::WrapMode::Type& wrapModeU, const Dali::WrapMode::Type& wrapModeV, - TextureUploadObserver* textureObserver) + const bool& synchronousLoading, + TextureUploadObserver* textureObserver, + TextureManager::MultiplyOnLoad& preMultiplyOnLoad) { TextureSet textureSet; @@ -162,6 +170,34 @@ TextureSet TextureManager::LoadAnimatedImageTexture( } else { + Texture maskTexture; + if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) + { + Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); + if(maskPixelBuffer) + { + if(!maskInfo->mPreappliedMasking) + { + PixelData maskPixelData = Devel::PixelBuffer::Convert(maskPixelBuffer); // takes ownership of buffer + maskTexture = Texture::New(Dali::TextureType::TEXTURE_2D, maskPixelData.GetPixelFormat(), maskPixelData.GetWidth(), maskPixelData.GetHeight()); + maskTexture.Upload(maskPixelData); + } + else + { + pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + } + } + else + { + DALI_LOG_ERROR("TextureManager::LoadAnimatedImageTexture: Synchronous mask image loading is failed\n"); + } + } + + if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) + { + PreMultiply(pixelBuffer, preMultiplyOnLoad); + } + PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer if(!textureSet) { @@ -169,13 +205,31 @@ TextureSet TextureManager::LoadAnimatedImageTexture( texture.Upload(pixelData); textureSet = TextureSet::New(); textureSet.SetTexture(0u, texture); + if(maskTexture) + { + textureSet.SetTexture(1u, maskTexture); + } } } } 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); + TextureId alphaMaskId = INVALID_TEXTURE_ID; + float contentScaleFactor = 1.0f; + bool cropToMask = false; + if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) + { + maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? StorageType::KEEP_PIXEL_BUFFER : StorageType::KEEP_TEXTURE); + alphaMaskId = maskInfo->mAlphaMaskId; + if(maskInfo->mPreappliedMasking) + { + contentScaleFactor = maskInfo->mContentScaleFactor; + cropToMask = maskInfo->mCropToMask; + } + } + + textureId = RequestLoadInternal(url, alphaMaskId, contentScaleFactor, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false); + TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId); if(loadState == TextureManager::LoadState::UPLOADED) { @@ -211,7 +265,7 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer( { if(url.IsBufferResource()) { - const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl()); + const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url); if(encodedImageBuffer) { pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection); @@ -279,43 +333,48 @@ TextureSet TextureManager::LoadTexture( else { // For Atlas - if(synchronousLoading && atlasingStatus && imageAtlasManager->CheckAtlasAvailable(url, desiredSize)) + if(synchronousLoading && atlasingStatus) { - Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection); - - if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) + const bool synchronousAtlasAvaliable = (desiredSize != ImageDimensions() || url.IsLocalResource()) ? imageAtlasManager->CheckAtlasAvailable(url, desiredSize) + : false; + if(synchronousAtlasAvaliable) { - Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); - if(maskPixelBuffer) + Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection); + + if(pixelBuffer && maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { - pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); + if(maskPixelBuffer) + { + pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + } } - } - - PixelData data; - if(pixelBuffer) - { - PreMultiply(pixelBuffer, preMultiplyOnLoad); - data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer - if(data) + PixelData data; + if(pixelBuffer) { - textureSet = imageAtlasManager->Add(textureRect, data); - if(textureSet) + PreMultiply(pixelBuffer, preMultiplyOnLoad); + data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer + + if(data) { - textureRectSize.SetWidth(data.GetWidth()); - textureRectSize.SetHeight(data.GetHeight()); + textureSet = imageAtlasManager->Add(textureRect, data); + if(textureSet) + { + textureRectSize.SetWidth(data.GetWidth()); + textureRectSize.SetHeight(data.GetHeight()); + } + } + else + { + DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n"); } } - else + if(!textureSet) { - DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n"); + atlasingStatus = false; } } - if(!textureSet) - { - atlasingStatus = false; - } } if(!textureSet) @@ -327,44 +386,52 @@ TextureSet TextureManager::LoadTexture( Dali::ImageDimensions atlasDesiredSize = desiredSize; if(atlasingStatus) { - textureSet = imageAtlasManager->Add(textureRect, url.GetUrl(), atlasDesiredSize, fittingMode, true, atlasObserver); + if(url.IsBufferResource()) + { + const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl()); + if(encodedImageBuffer) + { + textureSet = imageAtlasManager->Add(textureRect, encodedImageBuffer, desiredSize, fittingMode, true, atlasObserver); + } + } + else + { + textureSet = imageAtlasManager->Add(textureRect, url, atlasDesiredSize, fittingMode, true, atlasObserver); + } } if(!textureSet) // big image, no atlasing or atlasing failed { atlasingStatus = false; - if(!maskInfo || !maskInfo->mAlphaMaskUrl.IsValid()) - { - textureId = RequestLoad( - url, - desiredSize, - fittingMode, - samplingMode, - UseAtlas::NO_ATLAS, - textureObserver, - orientationCorrection, - reloadPolicy, - preMultiplyOnLoad, - synchronousLoading); - } - else + + TextureId alphaMaskId = INVALID_TEXTURE_ID; + float contentScaleFactor = 1.0f; + bool cropToMask = false; + if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { - maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, synchronousLoading); - textureId = RequestLoad( - url, - maskInfo->mAlphaMaskId, - maskInfo->mContentScaleFactor, - desiredSize, - fittingMode, - samplingMode, - UseAtlas::NO_ATLAS, - maskInfo->mCropToMask, - textureObserver, - orientationCorrection, - reloadPolicy, - preMultiplyOnLoad, - synchronousLoading); + maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? StorageType::KEEP_PIXEL_BUFFER : StorageType::KEEP_TEXTURE, synchronousLoading); + alphaMaskId = maskInfo->mAlphaMaskId; + if(maskInfo && maskInfo->mPreappliedMasking) + { + contentScaleFactor = maskInfo->mContentScaleFactor; + cropToMask = maskInfo->mCropToMask; + } } + textureId = RequestLoad( + url, + alphaMaskId, + contentScaleFactor, + desiredSize, + fittingMode, + samplingMode, + UseAtlas::NO_ATLAS, + cropToMask, + textureObserver, + orientationCorrection, + reloadPolicy, + preMultiplyOnLoad, + synchronousLoading); + TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId); if(loadState == TextureManager::LoadState::UPLOADED) { @@ -438,11 +505,12 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl, + StorageType storageType, const bool& synchronousLoading) { // Use the normal load procedure to get the alpha mask. auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; - return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, UseAtlas::NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading); + return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, UseAtlas::NO_ATLAS, false, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading); } TextureManager::TextureId TextureManager::RequestLoadInternal( @@ -463,17 +531,14 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( const std::uint32_t& frameIndex, const bool& synchronousLoading) { - // First check if the requested Texture is cached. - bool isAnimatedImage = (animatedImageLoading) ? true : false; - TextureHash textureHash = INITIAL_HASH_NUMBER; TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX; - if(storageType != StorageType::RETURN_PIXEL_BUFFER && !isAnimatedImage) + if(storageType != StorageType::RETURN_PIXEL_BUFFER && frameIndex == 0) { - textureHash = mTextureCacheManager.GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId); + textureHash = mTextureCacheManager.GenerateHash(url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, frameIndex); // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. - cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad); + cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, useAtlas, storageType, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false, frameIndex); } TextureManager::TextureId textureId = INVALID_TEXTURE_ID; @@ -491,41 +556,19 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( // Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info. preMultiplyOnLoad = mTextureCacheManager[cacheIndex].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d, frameindex=%d, premultiplied=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, frameIndex, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0); } if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required { - if(VisualUrl::BUFFER == url.GetProtocolType()) - { - std::string location = url.GetLocation(); - if(location.size() > 0u) - { - TextureId targetId = std::stoi(location); - const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(targetId); - if(encodedImageBuffer) - { - textureId = targetId; - - // Increase EncodedImageBuffer reference during it contains mTextureInfoContainer. - // TODO! We should change action when reload policy is FORCE. - // Eunki Hong will fix it after refactoring patch merged. - mTextureCacheManager.UseExternalResource(url.GetUrl()); - } - } - } - - if(textureId == INVALID_TEXTURE_ID) - { - textureId = mTextureCacheManager.GenerateUniqueTextureId(); - } + textureId = mTextureCacheManager.GenerateTextureId(); bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); // Cache new texutre, and get cacheIndex. cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d, frameindex=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, frameIndex); } // The below code path is common whether we are using the cache or not. @@ -546,7 +589,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( TextureManager::LoadState::MASK_APPLIED != textureInfo.loadState && TextureManager::LoadState::CANCELLED != textureInfo.loadState) { - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId); textureInfo.loadState = TextureManager::LoadState::NOT_STARTED; } @@ -602,12 +645,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( { // If the image is already finished to load, use cached texture. // We don't need to consider Observer because this is synchronous loading. - if(textureInfo.loadState == TextureManager::LoadState::UPLOADED || - textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED) - { - return textureId; - } - else + if(!(textureInfo.loadState == TextureManager::LoadState::UPLOADED || + textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED)) { Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection); @@ -625,15 +664,31 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( } else // For the image loading. { + Texture maskTexture; if(maskTextureId != INVALID_TEXTURE_ID) { TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(maskTextureId); if(maskCacheIndex != INVALID_CACHE_INDEX) { - Devel::PixelBuffer maskPixelBuffer = mTextureCacheManager[maskCacheIndex].pixelBuffer; - if(maskPixelBuffer) + if(mTextureCacheManager[maskCacheIndex].storageType == StorageType::KEEP_TEXTURE) + { + TextureSet maskTextures = mTextureCacheManager[maskCacheIndex].textureSet; + if(maskTextures && maskTextures.GetTextureCount()) + { + maskTexture = maskTextures.GetTexture(0u); + } + } + else if(mTextureCacheManager[maskCacheIndex].storageType == StorageType::KEEP_PIXEL_BUFFER) { - pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask); + Devel::PixelBuffer maskPixelBuffer = mTextureCacheManager[maskCacheIndex].pixelBuffer; + if(maskPixelBuffer) + { + pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask); + } + else + { + DALI_LOG_ERROR("Mask image cached invalid pixel buffer!\n"); + } } } else @@ -645,29 +700,42 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( // Upload texture UploadTexture(pixelBuffer, textureInfo); + if(maskTexture && textureInfo.textureSet) + { + textureInfo.textureSet.SetTexture(1u, maskTexture); + } } } } - - // Return the TextureId for which this Texture can now be referenced by externally. return textureId; } void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureUploadObserver* observer) { - // Remove textureId in CacheManager. - mTextureCacheManager.RemoveCache(textureId); - - if(observer) + if(textureId != INVALID_TEXTURE_ID) { - // Remove element from the LoadQueue - for(auto&& element : mLoadQueue) + if(mQueueLoadFlag) + { + // Remove textureId after NotifyObserver finished + mRemoveQueue.PushBack(textureId); + } + else + { + // Remove textureId in CacheManager. + mTextureCacheManager.RemoveCache(textureId); + } + + if(observer) { - if(element.mObserver == observer) + // Remove element from the LoadQueue + for(auto&& element : mLoadQueue) { - // Do not erase the item. We will clear it later in ProcessQueuedTextures(). - element.mObserver = nullptr; - break; + if(element.mObserver == observer) + { + // Do not erase the item. We will clear it later in ProcessLoadQueue(). + element.mObserver = nullptr; + break; + } } } } @@ -683,7 +751,7 @@ Devel::PixelBuffer TextureManager::LoadImageSynchronously( Devel::PixelBuffer pixelBuffer; if(url.IsBufferResource()) { - const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl()); + const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url); if(encodedImageBuffer) { pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection); @@ -746,7 +814,7 @@ 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. - observer->LoadComplete(true, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureInfo.textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied)); + EmitLoadComplete(observer, textureInfo, true); } break; } @@ -783,7 +851,7 @@ void TextureManager::LoadTexture(TextureManager::TextureInfo& textureInfo, Textu DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); if(textureInfo.animatedImageLoading) { - loadingHelperIt->LoadAnimatedImage(textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex); + loadingHelperIt->LoadAnimatedImage(textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex, premultiplyOnLoad); } else { @@ -793,7 +861,7 @@ void TextureManager::LoadTexture(TextureManager::TextureInfo& textureInfo, Textu ObserveTexture(textureInfo, observer); } -void TextureManager::ProcessQueuedTextures() +void TextureManager::ProcessLoadQueue() { for(auto&& element : mLoadQueue) { @@ -806,13 +874,9 @@ void TextureManager::ProcessQueuedTextures() if(cacheIndex != INVALID_CACHE_INDEX) { TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]); - if(textureInfo.loadState == LoadState::UPLOADED) + if((textureInfo.loadState == LoadState::UPLOADED) || (textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER)) { - element.mObserver->LoadComplete(true, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureInfo.textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied)); - } - else if(textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) - { - element.mObserver->LoadComplete(true, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, textureInfo.pixelBuffer, textureInfo.url.GetUrl(), textureInfo.preMultiplied)); + EmitLoadComplete(element.mObserver, textureInfo, true); } else { @@ -823,6 +887,15 @@ void TextureManager::ProcessQueuedTextures() mLoadQueue.Clear(); } +void TextureManager::ProcessRemoveQueue() +{ + for(const auto& textureId : mRemoveQueue) + { + mTextureCacheManager.RemoveCache(textureId); + } + mRemoveQueue.Clear(); +} + void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer) { @@ -837,13 +910,13 @@ void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo, void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, Devel::PixelBuffer pixelBuffer) { - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d )\n", textureId); TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d CacheIndex:%d )\n", textureId, cacheIndex.GetIndex()); if(cacheIndex != INVALID_CACHE_INDEX) { TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]); - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, " textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex, GET_LOAD_STATE_STRING(textureInfo.loadState)); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, " textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState)); if(textureInfo.loadState != LoadState::CANCELLED) { @@ -890,10 +963,38 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::P { textureInfo.loadState = LoadState::WAITING_FOR_MASK; } - else if(maskLoadState == LoadState::LOAD_FINISHED) + else if(maskLoadState == LoadState::LOAD_FINISHED || maskLoadState == LoadState::UPLOADED) { // Send New Task to Thread - ApplyMask(textureInfo, textureInfo.maskTextureId); + TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId); + if(maskCacheIndex != INVALID_CACHE_INDEX) + { + TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]); + if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) + { + // Send New Task to Thread + ApplyMask(textureInfo, textureInfo.maskTextureId); + } + else if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + { + // Upload image texture. textureInfo.loadState will be UPLOADED. + UploadTexture(textureInfo.pixelBuffer, textureInfo); + if(maskTextureInfo.textureSet.GetTextureCount() > 0u) + { + Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u); + textureInfo.textureSet.SetTexture(1u, maskTexture); + } + // notify mask texture set. + NotifyObservers(textureInfo, true); + } + } + } + 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); } } } @@ -912,7 +1013,7 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::P { NotifyObservers(textureInfo, true); } - else + else // for the StorageType::KEEP_PIXEL_BUFFER and StorageType::KEEP_TEXTURE { // 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) @@ -923,18 +1024,34 @@ 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 || textureInfo.storageType == StorageType::KEEP_TEXTURE) + { + // 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); + } + else + { + NotifyObservers(textureInfo, false); + } } } void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTextureInfo) { + if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED && + maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + { + // Upload mask texture. textureInfo.loadState will be UPLOADED. + UploadTexture(maskTextureInfo.pixelBuffer, maskTextureInfo); + } + // Search the cache, checking if any texture has this texture id as a // maskTextureId: - const TextureCacheIndex size = static_cast(mTextureCacheManager.size()); + const std::size_t size = mTextureCacheManager.size(); - for(TextureCacheIndex cacheIndex = 0; cacheIndex < size; ++cacheIndex) + // TODO : Refactorize here to not iterate whole cached image. + for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index) { if(mTextureCacheManager[cacheIndex].maskTextureId == maskTextureInfo.textureId && mTextureCacheManager[cacheIndex].loadState == LoadState::WAITING_FOR_MASK) @@ -943,14 +1060,33 @@ void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTex if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED) { - // Send New Task to Thread - ApplyMask(textureInfo, maskTextureInfo.textureId); + if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) + { + // Send New Task to Thread + ApplyMask(textureInfo, maskTextureInfo.textureId); + } + } + else if(maskTextureInfo.loadState == LoadState::UPLOADED) + { + if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + { + // Upload image texture. textureInfo.loadState will be UPLOADED. + UploadTexture(textureInfo.pixelBuffer, textureInfo); + if(maskTextureInfo.textureSet.GetTextureCount() > 0u) + { + Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u); + textureInfo.textureSet.SetTexture(1u, maskTexture); + } + // notify mask texture set. + NotifyObservers(textureInfo, true); + } } 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); } } } @@ -1017,11 +1153,25 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c // and erase it from the list TextureInfo* info = &textureInfo; + if(info->animatedImageLoading) + { + // If loading failed, we don't need to get frameCount and frameInterval. + if(success) + { + info->frameCount = info->animatedImageLoading.GetImageCount(); + info->frameInterval = info->animatedImageLoading.GetFrameInterval(info->frameIndex); + } + info->animatedImageLoading.Reset(); + } + mQueueLoadFlag = true; + // Reverse observer list that we can pop_back the observer. + std::reverse(info->observerList.Begin(), info->observerList.End()); + while(info->observerList.Count()) { - TextureUploadObserver* observer = info->observerList[0]; + TextureUploadObserver* observer = *(info->observerList.End() - 1u); // During LoadComplete() a Control ResourceReady() signal is emitted. // During that signal the app may add remove /add Textures (e.g. via @@ -1031,22 +1181,15 @@ 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, textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState)); + 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)); // It is possible for the observer to be deleted. // Disconnect and remove the observer first. observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed); - info->observerList.Erase(info->observerList.Begin()); + info->observerList.Erase(info->observerList.End() - 1u); - if(info->storageType == StorageType::RETURN_PIXEL_BUFFER) - { - observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, info->pixelBuffer, info->url.GetUrl(), info->preMultiplied)); - } - else - { - observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, info->textureId, info->textureSet, (info->useAtlas == UseAtlas::USE_ATLAS) ? true : false, info->atlasRect, info->preMultiplied)); - } + EmitLoadComplete(observer, *info, success); // Get the textureInfo from the container again as it may have been invalidated. TextureCacheIndex textureInfoIndex = mTextureCacheManager.GetCacheIndexFromId(textureId); @@ -1058,7 +1201,8 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c } mQueueLoadFlag = false; - ProcessQueuedTextures(); + ProcessLoadQueue(); + ProcessRemoveQueue(); if(info->storageType == StorageType::RETURN_PIXEL_BUFFER && info->observerList.Count() == 0) { @@ -1068,10 +1212,10 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c void TextureManager::ObserverDestroyed(TextureUploadObserver* observer) { - const TextureCacheIndex count = static_cast(mTextureCacheManager.size()); - for(TextureCacheIndex i = 0; i < count; ++i) + const std::size_t size = mTextureCacheManager.size(); + for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index) { - TextureInfo& textureInfo(mTextureCacheManager[i]); + TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]); for(TextureInfo::ObserverListType::Iterator j = textureInfo.observerList.Begin(); j != textureInfo.observerList.End();) { @@ -1101,6 +1245,22 @@ Dali::Geometry TextureManager::GetRenderGeometry(const TextureManager::TextureId return RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().GetGeometry(textureId, frontElements, backElements) : Geometry(); } +void TextureManager::EmitLoadComplete(TextureUploadObserver* observer, TextureManager::TextureInfo& textureInfo, const bool& success) +{ + if(textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) + { + observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, textureInfo.pixelBuffer, textureInfo.url.GetUrl(), textureInfo.preMultiplied)); + } + else if(textureInfo.isAnimatedImageFormat) + { + observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::ANIMATED_IMAGE_TEXTURE, textureInfo.textureId, textureInfo.frameCount, textureInfo.frameInterval)); + } + else + { + observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureInfo.textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied)); + } +} + } // namespace Internal } // namespace Toolkit