X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftexture-manager%2Ftexture-manager-impl.cpp;h=0c89aadc6fa14203e7fd2257c9d8f2d6ca4ff58e;hb=ca51ee97baf5f41ecf741e22d865ff6c9e0bf769;hp=20aedab8bce8ab958fa091492391a8b06fb9f7ac;hpb=6a957043921b7a50ce14db1d03d370b11c0ac63d;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 20aedab..0c89aad 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -37,8 +37,12 @@ constexpr auto INITIAL_HASH_NUMBER = size_t{0u}; constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS = size_t{4u}; constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u}; +constexpr auto TEXTURE_INDEX = 0u; ///< The Index for texture +constexpr auto MASK_TEXTURE_INDEX = 1u; ///< The Index for mask texture + constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV = "DALI_TEXTURE_LOCAL_THREADS"; constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS"; +constexpr auto LOAD_IMAGE_YUV_PLANES_ENV = "DALI_LOAD_IMAGE_YUV_PLANES"; size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue) { @@ -60,6 +64,12 @@ size_t GetNumberOfRemoteLoaderThreads() return GetNumberOfThreads(NUMBER_OF_REMOTE_LOADER_THREADS_ENV, DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS); } +bool NeedToLoadYuvPlanes() +{ + auto loadYuvPlanesString = Dali::EnvironmentVariable::GetEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV); + bool loadYuvPlanes = loadYuvPlanesString ? std::atoi(loadYuvPlanesString) : false; + return loadYuvPlanes; +} } // namespace namespace Dali @@ -113,7 +123,9 @@ TextureManager::MaskingData::MaskingData() : mAlphaMaskUrl(), mAlphaMaskId(INVALID_TEXTURE_ID), mContentScaleFactor(1.0f), - mCropToMask(true) + mCropToMask(true), + mPreappliedMasking(true), + mMaskImageLoadingFailed(false) { } @@ -124,7 +136,8 @@ TextureManager::TextureManager() mLifecycleObservers(), mLoadQueue(), mRemoveQueue(), - mQueueLoadFlag(false) + mLoadingQueueTextureId(INVALID_TEXTURE_ID), + mLoadYuvPlanes(NeedToLoadYuvPlanes()) { // Initialize the AddOn RenderingAddOn::Get(); @@ -145,8 +158,6 @@ TextureSet TextureManager::LoadAnimatedImageTexture( TextureManager::TextureId& textureId, MaskingDataPointer& maskInfo, const Dali::SamplingMode::Type& samplingMode, - const Dali::WrapMode::Type& wrapModeU, - const Dali::WrapMode::Type& wrapModeV, const bool& synchronousLoading, TextureUploadObserver* textureObserver, TextureManager::MultiplyOnLoad& preMultiplyOnLoad) @@ -166,12 +177,22 @@ 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) { - pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + 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 { @@ -190,7 +211,11 @@ TextureSet TextureManager::LoadAnimatedImageTexture( Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight()); texture.Upload(pixelData); textureSet = TextureSet::New(); - textureSet.SetTexture(0u, texture); + textureSet.SetTexture(TEXTURE_INDEX, texture); + if(maskTexture) + { + textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTexture); + } } } } @@ -201,13 +226,16 @@ TextureSet TextureManager::LoadAnimatedImageTexture( bool cropToMask = false; if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { - maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl); + maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? StorageType::KEEP_PIXEL_BUFFER : StorageType::KEEP_TEXTURE); alphaMaskId = maskInfo->mAlphaMaskId; - contentScaleFactor = maskInfo->mContentScaleFactor; - cropToMask = maskInfo->mCropToMask; + 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); + 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) @@ -217,13 +245,6 @@ TextureSet TextureManager::LoadAnimatedImageTexture( } } - if(textureSet) - { - Sampler sampler = Sampler::New(); - sampler.SetWrapMode(wrapModeU, wrapModeV); - textureSet.SetSampler(0u, sampler); - } - return textureSet; } @@ -280,8 +301,6 @@ TextureSet TextureManager::LoadTexture( Dali::ImageDimensions& textureRectSize, bool& atlasingStatus, bool& loadingStatus, - const Dali::WrapMode::Type& wrapModeU, - const Dali::WrapMode::Type& wrapModeV, TextureUploadObserver* textureObserver, AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, @@ -318,22 +337,24 @@ TextureSet TextureManager::LoadTexture( : false; if(synchronousAtlasAvaliable) { - Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection); + std::vector pixelBuffers; + LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, false, pixelBuffers); - if(pixelBuffer && maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) + if(!pixelBuffers.empty() && maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { - Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); - if(maskPixelBuffer) + std::vector maskPixelBuffers; + LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true, false, maskPixelBuffers); + if(!maskPixelBuffers.empty()) { - pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + pixelBuffers[0].ApplyMask(maskPixelBuffers[0], maskInfo->mContentScaleFactor, maskInfo->mCropToMask); } } PixelData data; - if(pixelBuffer) + if(!pixelBuffers.empty()) { - PreMultiply(pixelBuffer, preMultiplyOnLoad); - data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer + PreMultiply(pixelBuffers[0], preMultiplyOnLoad); + data = Devel::PixelBuffer::Convert(pixelBuffers[0]); // takes ownership of buffer if(data) { @@ -381,44 +402,41 @@ TextureSet TextureManager::LoadTexture( 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) { // LoadComplete has already been called - keep the same texture set - textureSet = mTextureCacheManager.GetTextureSet(textureId); + textureSet = GetTextureSet(textureId); } // If we are loading the texture, or waiting for the ready signal handler to complete, inform @@ -428,7 +446,7 @@ TextureSet TextureManager::LoadTexture( loadState == TextureManager::LoadState::MASK_APPLYING || loadState == TextureManager::LoadState::MASK_APPLIED || loadState == TextureManager::LoadState::NOT_STARTED || - mQueueLoadFlag); + mLoadingQueueTextureId != INVALID_TEXTURE_ID); } else { @@ -437,13 +455,6 @@ TextureSet TextureManager::LoadTexture( } } - if(!atlasingStatus && textureSet) - { - Sampler sampler = Sampler::New(); - sampler.SetWrapMode(wrapModeU, wrapModeV); - textureSet.SetSampler(0u, sampler); - } - if(synchronousLoading) { loadingStatus = false; @@ -487,11 +498,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( @@ -512,14 +524,16 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( const std::uint32_t& frameIndex, const bool& synchronousLoading) { - TextureHash textureHash = INITIAL_HASH_NUMBER; - TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX; - if(storageType != StorageType::RETURN_PIXEL_BUFFER && frameIndex == 0) + TextureHash textureHash = INITIAL_HASH_NUMBER; + TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX; + bool loadYuvPlanes = (mLoadYuvPlanes && maskTextureId == INVALID_TEXTURE_ID && storageType == StorageType::UPLOAD_TO_TEXTURE); + + if(storageType != StorageType::RETURN_PIXEL_BUFFER) { 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, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false, frameIndex); + cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, useAtlas, storageType, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false, frameIndex); } TextureManager::TextureId textureId = INVALID_TEXTURE_ID; @@ -547,9 +561,9 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( 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)); + cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex, loadYuvPlanes)); - 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); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d, frameindex=%d premultiply=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, frameIndex, preMultiply); } // The below code path is common whether we are using the cache or not. @@ -629,9 +643,10 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( if(!(textureInfo.loadState == TextureManager::LoadState::UPLOADED || textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED)) { - Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection); + std::vector pixelBuffers; + LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, loadYuvPlanes, pixelBuffers); - if(!pixelBuffer) + if(pixelBuffers.empty()) { // If pixelBuffer loading is failed in synchronously, call Remove() method. Remove(textureId, nullptr); @@ -640,24 +655,35 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( if(storageType == StorageType::KEEP_PIXEL_BUFFER) // For the mask image loading. { - textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data + textureInfo.pixelBuffer = pixelBuffers[0]; // Store the pixel data textureInfo.loadState = LoadState::LOAD_FINISHED; } 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) { - pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask); + if(!mTextureCacheManager[maskCacheIndex].textures.empty()) + { + maskTexture = mTextureCacheManager[maskCacheIndex].textures[0]; + } } - else + else if(mTextureCacheManager[maskCacheIndex].storageType == StorageType::KEEP_PIXEL_BUFFER) { - DALI_LOG_ERROR("Mask image cached invalid pixel buffer!\n"); + Devel::PixelBuffer maskPixelBuffer = mTextureCacheManager[maskCacheIndex].pixelBuffer; + if(maskPixelBuffer) + { + pixelBuffers[0].ApplyMask(maskPixelBuffer, contentScale, cropToMask); + } + else + { + DALI_LOG_ERROR("Mask image cached invalid pixel buffer!\n"); + } } } else @@ -665,13 +691,14 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( DALI_LOG_ERROR("Mask image is not stored in cache.\n"); } } - PreMultiply(pixelBuffer, preMultiplyOnLoad); + PreMultiply(pixelBuffers[0], preMultiplyOnLoad); // Upload texture - UploadTexture(pixelBuffer, textureInfo); + UploadTextures(pixelBuffers, textureInfo); } } } + return textureId; } @@ -679,15 +706,60 @@ void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureU { if(textureId != INVALID_TEXTURE_ID) { - if(mQueueLoadFlag) + TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId); + if(textureCacheIndex != INVALID_CACHE_INDEX) { - // Remove textureId after NotifyObserver finished - mRemoveQueue.PushBack(textureId); - } - else - { - // Remove textureId in CacheManager. - mTextureCacheManager.RemoveCache(textureId); + TextureManager::TextureId maskTextureId = INVALID_TEXTURE_ID; + TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]); + if(textureInfo.maskTextureId != INVALID_TEXTURE_ID) + { + maskTextureId = textureInfo.maskTextureId; + } + + // the case that LoadingQueue is working. + if(mLoadingQueueTextureId != INVALID_TEXTURE_ID) + { + // If textureId is not same, this observer need to delete when ProcessRemoveQueue() is called. + TextureUploadObserver* queueObserver = nullptr; + if(mLoadingQueueTextureId != textureId) + { + queueObserver = observer; + } + + // Remove textureId after NotifyObserver finished + if(maskTextureId != INVALID_TEXTURE_ID) + { + if(textureInfo.loadState != LoadState::CANCELLED) + { + mRemoveQueue.PushBack(QueueElement(maskTextureId, nullptr)); + } + } + mRemoveQueue.PushBack(QueueElement(textureId, queueObserver)); + } + else + { + // Remove its observer + RemoveTextureObserver(textureInfo, observer); + + // Remove maskTextureId in CacheManager + if(maskTextureId != INVALID_TEXTURE_ID) + { + TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(maskTextureId); + if(maskCacheIndex != INVALID_CACHE_INDEX) + { + TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]); + + // Only Remove maskTexture when texture's loadState is not CANCELLED. because it is already deleted. + if(textureInfo.loadState != LoadState::CANCELLED) + { + mTextureCacheManager.RemoveCache(maskTextureInfo); + } + } + } + + // Remove textureId in CacheManager + mTextureCacheManager.RemoveCache(textureInfo); + } } if(observer) @@ -706,12 +778,14 @@ void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureU } } -Devel::PixelBuffer TextureManager::LoadImageSynchronously( - const VisualUrl& url, - const Dali::ImageDimensions& desiredSize, - const Dali::FittingMode::Type& fittingMode, - const Dali::SamplingMode::Type& samplingMode, - const bool& orientationCorrection) +void TextureManager::LoadImageSynchronously( + const VisualUrl& url, + const Dali::ImageDimensions& desiredSize, + const Dali::FittingMode::Type& fittingMode, + const Dali::SamplingMode::Type& samplingMode, + const bool& orientationCorrection, + const bool& loadYuvPlanes, + std::vector& pixelBuffers) { Devel::PixelBuffer pixelBuffer; if(url.IsBufferResource()) @@ -724,9 +798,20 @@ Devel::PixelBuffer TextureManager::LoadImageSynchronously( } else { - pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + if(loadYuvPlanes) + { + Dali::LoadImagePlanesFromFile(url.GetUrl(), pixelBuffers, desiredSize, fittingMode, samplingMode, orientationCorrection); + } + else + { + pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } + } + + if(pixelBuffer) + { + pixelBuffers.push_back(pixelBuffer); } - return pixelBuffer; } void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer) @@ -759,7 +844,7 @@ void TextureManager::LoadOrQueueTexture(TextureManager::TextureInfo& textureInfo case LoadState::NOT_STARTED: case LoadState::LOAD_FAILED: { - if(mQueueLoadFlag) + if(mLoadingQueueTextureId != INVALID_TEXTURE_ID) { QueueLoadTexture(textureInfo, observer); } @@ -771,7 +856,7 @@ void TextureManager::LoadOrQueueTexture(TextureManager::TextureInfo& textureInfo } case LoadState::UPLOADED: { - if(mQueueLoadFlag) + if(mLoadingQueueTextureId != INVALID_TEXTURE_ID) { QueueLoadTexture(textureInfo, observer); } @@ -798,7 +883,7 @@ void TextureManager::LoadOrQueueTexture(TextureManager::TextureInfo& textureInfo void TextureManager::QueueLoadTexture(const TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer) { const auto& textureId = textureInfo.textureId; - mLoadQueue.PushBack(LoadQueueElement(textureId, observer)); + mLoadQueue.PushBack(QueueElement(textureId, observer)); observer->DestructionSignal().Connect(this, &TextureManager::ObserverDestroyed); } @@ -820,7 +905,7 @@ void TextureManager::LoadTexture(TextureManager::TextureInfo& textureInfo, Textu } else { - loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, textureInfo.orientationCorrection, premultiplyOnLoad); + loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, textureInfo.orientationCorrection, premultiplyOnLoad, textureInfo.loadYuvPlanes); } } ObserveTexture(textureInfo, observer); @@ -843,6 +928,12 @@ void TextureManager::ProcessLoadQueue() { EmitLoadComplete(element.mObserver, textureInfo, true); } + else if(textureInfo.loadState == LoadState::LOADING) + { + // Note : LOADING state texture cannot be queue. + // This case be occured when same texture id are queue in mLoadQueue. + ObserveTexture(textureInfo, element.mObserver); + } else { LoadTexture(textureInfo, element.mObserver); @@ -854,9 +945,16 @@ void TextureManager::ProcessLoadQueue() void TextureManager::ProcessRemoveQueue() { - for(const auto& textureId : mRemoveQueue) + TextureCacheIndex textureCacheIndex = INVALID_CACHE_INDEX; + for(auto&& element : mRemoveQueue) { - mTextureCacheManager.RemoveCache(textureId); + textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(element.mTextureId); + if(textureCacheIndex != INVALID_CACHE_INDEX) + { + TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]); + RemoveTextureObserver(textureInfo, element.mObserver); + mTextureCacheManager.RemoveCache(textureInfo); + } } mRemoveQueue.Clear(); } @@ -873,7 +971,7 @@ void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo, } } -void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, Devel::PixelBuffer pixelBuffer) +void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, std::vector& pixelBuffers) { TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId); DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d CacheIndex:%d )\n", textureId, cacheIndex.GetIndex()); @@ -886,7 +984,7 @@ void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureI if(textureInfo.loadState != LoadState::CANCELLED) { // textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified) - PostLoad(textureInfo, pixelBuffer); + PostLoad(textureInfo, pixelBuffers); } else { @@ -895,100 +993,141 @@ void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureI } } -void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer) +void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, std::vector& pixelBuffers) { // Was the load successful? - if(pixelBuffer && (pixelBuffer.GetWidth() != 0) && (pixelBuffer.GetHeight() != 0)) + if(!pixelBuffers.empty()) { - // No atlas support for now - textureInfo.useAtlas = UseAtlas::NO_ATLAS; - textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); - - if(textureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE) + if(pixelBuffers.size() == 1) { - // If there is a mask texture ID associated with this texture, then apply the mask - // if it's already loaded. If it hasn't, and the mask is still loading, - // wait for the mask to finish loading. - // note, If the texture is already uploaded synchronously during loading, - // we don't need to apply mask. - if(textureInfo.loadState != LoadState::UPLOADED && - textureInfo.maskTextureId != INVALID_TEXTURE_ID) + Devel::PixelBuffer pixelBuffer = pixelBuffers[0]; + if(pixelBuffer && (pixelBuffer.GetWidth() != 0) && (pixelBuffer.GetHeight() != 0)) { - if(textureInfo.loadState == LoadState::MASK_APPLYING) - { - textureInfo.loadState = LoadState::MASK_APPLIED; - UploadTexture(pixelBuffer, textureInfo); - NotifyObservers(textureInfo, true); - } - else + // No atlas support for now + textureInfo.useAtlas = UseAtlas::NO_ATLAS; + textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); + + if(textureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE) { - LoadState maskLoadState = mTextureCacheManager.GetTextureStateInternal(textureInfo.maskTextureId); - textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily - if(maskLoadState == LoadState::LOADING) + // If there is a mask texture ID associated with this texture, then apply the mask + // if it's already loaded. If it hasn't, and the mask is still loading, + // wait for the mask to finish loading. + // note, If the texture is already uploaded synchronously during loading, + // we don't need to apply mask. + if(textureInfo.loadState != LoadState::UPLOADED && + textureInfo.maskTextureId != INVALID_TEXTURE_ID) { - textureInfo.loadState = LoadState::WAITING_FOR_MASK; + if(textureInfo.loadState == LoadState::MASK_APPLYING) + { + textureInfo.loadState = LoadState::MASK_APPLIED; + UploadTextures(pixelBuffers, textureInfo); + NotifyObservers(textureInfo, true); + } + else + { + LoadState maskLoadState = mTextureCacheManager.GetTextureStateInternal(textureInfo.maskTextureId); + textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily + if(maskLoadState == LoadState::LOADING) + { + textureInfo.loadState = LoadState::WAITING_FOR_MASK; + } + else if(maskLoadState == LoadState::LOAD_FINISHED || maskLoadState == LoadState::UPLOADED) + { + // Send New Task to Thread + 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. + UploadTextures(pixelBuffers, textureInfo); + + // 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"); + UploadTextures(pixelBuffers, textureInfo); + NotifyObservers(textureInfo, true); + } + } } - else if(maskLoadState == LoadState::LOAD_FINISHED) + else { - // Send New Task to Thread - ApplyMask(textureInfo, textureInfo.maskTextureId); + UploadTextures(pixelBuffers, textureInfo); + NotifyObservers(textureInfo, true); } - else // maskLoadState == LoadState::LOAD_FAILED + } + else + { + textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data + textureInfo.loadState = LoadState::LOAD_FINISHED; + + if(textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) { - // 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 // 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) + CheckForWaitingTexture(textureInfo); + } } } - else - { - UploadTexture(pixelBuffer, textureInfo); - NotifyObservers(textureInfo, true); - } } else { - textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data - textureInfo.loadState = LoadState::LOAD_FINISHED; + // YUV case + // No atlas support for now + textureInfo.useAtlas = UseAtlas::NO_ATLAS; + textureInfo.preMultiplied = false; - if(textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) - { - NotifyObservers(textureInfo, true); - } - else - { - // 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); - } + UploadTextures(pixelBuffers, textureInfo); + NotifyObservers(textureInfo, true); } } else { textureInfo.loadState = LoadState::LOAD_FAILED; - if(textureInfo.storageType != StorageType::KEEP_PIXEL_BUFFER) - { - NotifyObservers(textureInfo, false); - } - else // if(textureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) // image mask case + 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. + std::vector pixelBuffers; + pixelBuffers.push_back(maskTextureInfo.pixelBuffer); + UploadTextures(pixelBuffers, maskTextureInfo); + } + // Search the cache, checking if any texture has this texture id as a // maskTextureId: const std::size_t size = mTextureCacheManager.size(); - const bool maskLoadSuccess = maskTextureInfo.loadState == LoadState::LOAD_FINISHED ? true : false; - // 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) { @@ -997,16 +1136,34 @@ void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTex { TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]); - if(maskLoadSuccess) + 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. + std::vector pixelBuffers; + pixelBuffers.push_back(textureInfo.pixelBuffer); + UploadTextures(pixelBuffers, textureInfo); + + // notify mask texture set. + NotifyObservers(textureInfo, true); + } } else { // 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); + std::vector pixelBuffers; + pixelBuffers.push_back(textureInfo.pixelBuffer); + UploadTextures(pixelBuffers, textureInfo); NotifyObservers(textureInfo, true); } } @@ -1033,30 +1190,31 @@ void TextureManager::ApplyMask(TextureManager::TextureInfo& textureInfo, const T } } -void TextureManager::UploadTexture(Devel::PixelBuffer& pixelBuffer, TextureManager::TextureInfo& textureInfo) +void TextureManager::UploadTextures(std::vector& pixelBuffers, TextureManager::TextureInfo& textureInfo) { - if(textureInfo.loadState != LoadState::UPLOADED && textureInfo.useAtlas != UseAtlas::USE_ATLAS) + if(!pixelBuffers.empty() && textureInfo.loadState != LoadState::UPLOADED && textureInfo.useAtlas != UseAtlas::USE_ATLAS) { - DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId); + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTextures() New Texture for textureId:%d\n", textureInfo.textureId); // Check if this pixelBuffer is premultiplied - textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); + textureInfo.preMultiplied = pixelBuffers[0].IsAlphaPreMultiplied(); auto& renderingAddOn = RenderingAddOn::Get(); if(renderingAddOn.IsValid()) { - renderingAddOn.CreateGeometry(textureInfo.textureId, pixelBuffer); + renderingAddOn.CreateGeometry(textureInfo.textureId, pixelBuffers[0]); } - Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight()); + // Remove previous textures and insert new textures + textureInfo.textures.clear(); - PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); - texture.Upload(pixelData); - if(!textureInfo.textureSet) + for(auto&& pixelBuffer : pixelBuffers) { - textureInfo.textureSet = TextureSet::New(); + Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight()); + PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); + texture.Upload(pixelData); + textureInfo.textures.push_back(texture); } - textureInfo.textureSet.SetTexture(0u, texture); } // Update the load state. @@ -1085,7 +1243,7 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c info->animatedImageLoading.Reset(); } - mQueueLoadFlag = true; + mLoadingQueueTextureId = textureId; // Reverse observer list that we can pop_back the observer. std::reverse(info->observerList.Begin(), info->observerList.End()); @@ -1121,7 +1279,7 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c info = &mTextureCacheManager[textureInfoIndex]; } - mQueueLoadFlag = false; + mLoadingQueueTextureId = INVALID_TEXTURE_ID; ProcessLoadQueue(); ProcessRemoveQueue(); @@ -1172,13 +1330,90 @@ void TextureManager::EmitLoadComplete(TextureUploadObserver* observer, TextureMa { observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, textureInfo.pixelBuffer, textureInfo.url.GetUrl(), textureInfo.preMultiplied)); } - else if(textureInfo.isAnimatedImageFormat) + else { - observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::ANIMATED_IMAGE_TEXTURE, textureInfo.textureId, textureInfo.frameCount, textureInfo.frameInterval)); + TextureSet textureSet = GetTextureSet(textureInfo); + if(textureInfo.isAnimatedImageFormat) + { + observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::ANIMATED_IMAGE_TEXTURE, textureInfo.textureId, textureSet, textureInfo.frameCount, textureInfo.frameInterval)); + } + else + { + observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied)); + } + } +} + +TextureSet TextureManager::GetTextureSet(const TextureManager::TextureId& textureId) +{ + TextureSet textureSet; + TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId); + if(loadState == TextureManager::LoadState::UPLOADED) + { + // LoadComplete has already been called - keep the same texture set + TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId); + if(textureCacheIndex != INVALID_CACHE_INDEX) + { + TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]); + textureSet = GetTextureSet(textureInfo); + } } else { - observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureInfo.textureSet, (textureInfo.useAtlas == UseAtlas::USE_ATLAS) ? true : false, textureInfo.atlasRect, textureInfo.preMultiplied)); + DALI_LOG_ERROR("GetTextureSet is failed. texture is not uploaded \n"); + } + return textureSet; +} + +TextureSet TextureManager::GetTextureSet(const TextureManager::TextureInfo& textureInfo) +{ + TextureSet textureSet; + + // LoadComplete has already been called - keep the same texture set + textureSet = TextureSet::New(); + if(!textureInfo.textures.empty()) + { + if(textureInfo.textures.size() > 1) // For YUV case + { + uint32_t index = 0u; + for(auto&& texture : textureInfo.textures) + { + textureSet.SetTexture(index++, texture); + } + } + else + { + textureSet.SetTexture(TEXTURE_INDEX, textureInfo.textures[0]); + TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId); + if(maskCacheIndex != INVALID_CACHE_INDEX) + { + TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]); + if(maskTextureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE || maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + { + if(!maskTextureInfo.textures.empty()) + { + textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTextureInfo.textures[0]); + } + } + } + } + } + return textureSet; +} + +void TextureManager::RemoveTextureObserver(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer) +{ + // Remove its observer + if(observer) + { + const auto iterEnd = textureInfo.observerList.End(); + const auto iter = std::find(textureInfo.observerList.Begin(), iterEnd, observer); + if(iter != iterEnd) + { + // Disconnect and remove the observer. + observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed); + textureInfo.observerList.Erase(iter); + } } }