X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Ftexture-manager-impl.cpp;h=49867c4f40f67fd39e260f36517c3c8ec78d7a85;hp=a4499974cc1211549c81319be2d423a6865b42a0;hb=48000ec3ab1ca2d1f8001d192112e32357bb1dfc;hpb=7923c3d4f1d8ef3866e07eb43e5f6806cb108ef2 diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index a449997..49867c4 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -30,6 +30,7 @@ #include // INTERNAL HEADERS +#include #include #include #include @@ -121,8 +122,10 @@ TextureManager::MaskingData::MaskingData() } TextureManager::TextureManager() -: mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); }), - mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); }), +: mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() + { return AsyncLoadingHelper(*this); }), + mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() + { return AsyncLoadingHelper(*this); }), mExternalTextures(), mLifecycleObservers(), mLoadQueue(), @@ -172,7 +175,7 @@ TextureSet TextureManager::LoadAnimatedImageTexture( 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, TextureManager::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex); + textureId = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex, false); TextureManager::LoadState loadState = GetTextureStateInternal(textureId); if(loadState == TextureManager::LoadState::UPLOADED) { @@ -199,7 +202,18 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer( { if(url.IsValid()) { - pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + if(url.IsBufferResource()) + { + const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl()); + if(encodedImageBuffer) + { + pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } + } + else + { + pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } if(pixelBuffer && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) { PreMultiply(pixelBuffer, preMultiplyOnLoad); @@ -208,7 +222,7 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer( } else { - RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u); + RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false); } return pixelBuffer; @@ -239,101 +253,100 @@ TextureSet TextureManager::LoadTexture( } } } - else if(synchronousLoading) + else { - PixelData data; - if(url.IsValid()) + // For Atlas + if(synchronousLoading && atlasingStatus && imageAtlasManager->CheckAtlasAvailable(url, desiredSize)) { - Devel::PixelBuffer pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection); + if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { - Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); + Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl.GetUrl(), 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) + { + 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"); + } } - } - if(!data) - { - DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous loading is failed\n"); - } - else - { - if(atlasingStatus) // attempt atlasing - { - textureSet = imageAtlasManager->Add(textureRect, data); - } - if(!textureSet) // big image, no atlasing or atlasing failed - { - atlasingStatus = false; - Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), data.GetWidth(), data.GetHeight()); - texture.Upload(data); - textureSet = TextureSet::New(); - textureSet.SetTexture(0u, texture); - } - else + if(!textureSet) { - textureRectSize.SetWidth(data.GetWidth()); - textureRectSize.SetHeight(data.GetHeight()); + atlasingStatus = false; } } - } - else - { - loadingStatus = true; - if(atlasingStatus) - { - textureSet = imageAtlasManager->Add(textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver); - } - if(!textureSet) // big image, no atlasing or atlasing failed + + if(!textureSet) { - atlasingStatus = false; - if(!maskInfo || !maskInfo->mAlphaMaskUrl.IsValid()) + loadingStatus = true; + if(atlasingStatus) { - textureId = RequestLoad(url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad); + textureSet = imageAtlasManager->Add(textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver); } - else + if(!textureSet) // big image, no atlasing or atlasing failed { - maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl); - textureId = RequestLoad(url, - maskInfo->mAlphaMaskId, - maskInfo->mContentScaleFactor, - desiredSize, - fittingMode, - samplingMode, - TextureManager::NO_ATLAS, - maskInfo->mCropToMask, - textureObserver, - orientationCorrection, - reloadPolicy, - preMultiplyOnLoad); - } + atlasingStatus = false; + if(!maskInfo || !maskInfo->mAlphaMaskUrl.IsValid()) + { + textureId = RequestLoad(url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad, synchronousLoading); + } + else + { + maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, synchronousLoading); + textureId = RequestLoad(url, + maskInfo->mAlphaMaskId, + maskInfo->mContentScaleFactor, + desiredSize, + fittingMode, + samplingMode, + TextureManager::NO_ATLAS, + maskInfo->mCropToMask, + textureObserver, + orientationCorrection, + reloadPolicy, + preMultiplyOnLoad, + synchronousLoading); + } - TextureManager::LoadState loadState = GetTextureStateInternal(textureId); - if(loadState == TextureManager::LoadState::UPLOADED) + TextureManager::LoadState loadState = GetTextureStateInternal(textureId); + if(loadState == TextureManager::LoadState::UPLOADED) + { + // UploadComplete has already been called - keep the same texture set + textureSet = GetTextureSet(textureId); + } + + // If we are loading the texture, or waiting for the ready signal handler to complete, inform + // caller that they need to wait. + loadingStatus = (loadState == TextureManager::LoadState::LOADING || + loadState == TextureManager::LoadState::WAITING_FOR_MASK || + loadState == TextureManager::LoadState::MASK_APPLYING || + loadState == TextureManager::LoadState::MASK_APPLIED || + loadState == TextureManager::LoadState::NOT_STARTED || + mQueueLoadFlag); + } + else { - // UploadComplete has already been called - keep the same texture set - textureSet = GetTextureSet(textureId); + textureRectSize = desiredSize; } - - // If we are loading the texture, or waiting for the ready signal handler to complete, inform - // caller that they need to wait. - loadingStatus = (loadState == TextureManager::LoadState::LOADING || - loadState == TextureManager::LoadState::WAITING_FOR_MASK || - loadState == TextureManager::LoadState::MASK_APPLYING || - loadState == TextureManager::LoadState::MASK_APPLIED || - loadState == TextureManager::LoadState::NOT_STARTED || - mQueueLoadFlag); - } - else - { - textureRectSize = desiredSize; } } @@ -344,6 +357,11 @@ TextureSet TextureManager::LoadTexture( textureSet.SetSampler(0u, sampler); } + if(synchronousLoading) + { + loadingStatus = false; + } + return textureSet; } @@ -356,9 +374,10 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureUploadObserver* observer, bool orientationCorrection, TextureManager::ReloadPolicy reloadPolicy, - TextureManager::MultiplyOnLoad& preMultiplyOnLoad) + TextureManager::MultiplyOnLoad& preMultiplyOnLoad, + bool synchronousLoading) { - return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u); + return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading); } TextureManager::TextureId TextureManager::RequestLoad( @@ -373,16 +392,17 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureUploadObserver* observer, bool orientationCorrection, TextureManager::ReloadPolicy reloadPolicy, - TextureManager::MultiplyOnLoad& preMultiplyOnLoad) + TextureManager::MultiplyOnLoad& preMultiplyOnLoad, + bool synchronousLoading) { - return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u); + return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading); } -TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl) +TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl, 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, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u); + return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading); } TextureManager::TextureId TextureManager::RequestLoadInternal( @@ -400,7 +420,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad, Dali::AnimatedImageLoading animatedImageLoading, - uint32_t frameIndex) + uint32_t frameIndex, + bool synchronousLoading) { // First check if the requested Texture is cached. bool isAnimatedImage = (animatedImageLoading) ? true : false; @@ -435,10 +456,30 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required { - // We need a new Texture. - textureId = GenerateUniqueTextureId(); + if(VisualUrl::BUFFER == url.GetProtocolType()) + { + std::string location = url.GetLocation(); + if(location.size() > 0u) + { + TextureId targetId = std::stoi(location); + const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(targetId); + if(encodedImageBuffer) + { + textureId = targetId; + + // Increase EncodedImageBuffer reference during it contains mTextureInfoContainer. + UseExternalResource(url.GetUrl()); + } + } + } + + if(textureId == INVALID_TEXTURE_ID) + { + textureId = GenerateUniqueTextureId(); + } + bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); - mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url.GetUrl(), desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); + mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); cacheIndex = mTextureInfoContainer.size() - 1u; 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); @@ -467,48 +508,101 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( textureInfo.loadState = TextureManager::LoadState::NOT_STARTED; } - // Check if we should add the observer. - // Only do this if we have not loaded yet and it will not have loaded by the end of this method. - switch(textureInfo.loadState) + if(!synchronousLoading) { - case TextureManager::LoadState::LOAD_FAILED: // Failed notifies observer which then stops observing. - case TextureManager::LoadState::NOT_STARTED: - { - LoadOrQueueTexture(textureInfo, observer); // If called inside NotifyObservers, queues until afterwards - break; - } - case TextureManager::LoadState::LOADING: - case TextureManager::LoadState::WAITING_FOR_MASK: - case TextureManager::LoadState::MASK_APPLYING: - case TextureManager::LoadState::MASK_APPLIED: + // Check if we should add the observer. + // Only do this if we have not loaded yet and it will not have loaded by the end of this method. + switch(textureInfo.loadState) { - ObserveTexture(textureInfo, observer); - break; - } - case TextureManager::LoadState::UPLOADED: - { - if(observer) + case TextureManager::LoadState::LOAD_FAILED: // Failed notifies observer which then stops observing. + case TextureManager::LoadState::NOT_STARTED: { - LoadOrQueueTexture(textureInfo, observer); + LoadOrQueueTexture(textureInfo, observer); // If called inside NotifyObservers, queues until afterwards + break; + } + case TextureManager::LoadState::LOADING: + case TextureManager::LoadState::WAITING_FOR_MASK: + case TextureManager::LoadState::MASK_APPLYING: + case TextureManager::LoadState::MASK_APPLIED: + { + ObserveTexture(textureInfo, observer); + break; + } + case TextureManager::LoadState::UPLOADED: + { + if(observer) + { + LoadOrQueueTexture(textureInfo, observer); + } + break; + } + case TextureManager::LoadState::CANCELLED: + { + // A cancelled texture hasn't finished loading yet. Treat as a loading texture + // (it's ref count has already been incremented, above) + textureInfo.loadState = TextureManager::LoadState::LOADING; + ObserveTexture(textureInfo, observer); + break; + } + case TextureManager::LoadState::LOAD_FINISHED: + { + // Loading has already completed. + if(observer && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) + { + LoadOrQueueTexture(textureInfo, observer); + } + break; } - break; } - case TextureManager::LoadState::CANCELLED: + } + else + { + // If the image is already finished to load, use cached texture. + // We don't need to consider Observer becaouse this is synchronous loading. + if(textureInfo.loadState == TextureManager::LoadState::UPLOADED || + textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED) { - // A cancelled texture hasn't finished loading yet. Treat as a loading texture - // (it's ref count has already been incremented, above) - textureInfo.loadState = TextureManager::LoadState::LOADING; - ObserveTexture(textureInfo, observer); - break; + return textureId; } - case TextureManager::LoadState::LOAD_FINISHED: + else { - // Loading has already completed. - if(observer && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) + Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);; + + if(!pixelBuffer) { - LoadOrQueueTexture(textureInfo, observer); + // If pixelBuffer loading is failed in synchronously, call Remove() method. + Remove(textureId, nullptr); + return INVALID_TEXTURE_ID; + } + + if(storageType == StorageType::KEEP_PIXEL_BUFFER) // For the mask image loading. + { + textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data + textureInfo.loadState = LoadState::LOAD_FINISHED; + } + else // For the image loading. + { + if(maskTextureId != INVALID_TEXTURE_ID) + { + int maskCacheIndex = GetCacheIndexFromId(maskTextureId); + if(maskCacheIndex != INVALID_CACHE_INDEX) + { + Devel::PixelBuffer maskPixelBuffer = mTextureInfoContainer[maskCacheIndex].pixelBuffer; + if(maskPixelBuffer) + { + pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask); + } + } + else + { + DALI_LOG_ERROR("Mask image is not stored in cache.\n"); + } + } + PreMultiply(pixelBuffer, preMultiplyOnLoad); + + // Upload texture + UploadTexture(pixelBuffer, textureInfo); } - break; } } @@ -519,6 +613,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( void TextureManager::Remove(const TextureManager::TextureId textureId, TextureUploadObserver* observer) { int textureInfoIndex = GetCacheIndexFromId(textureId); + if(textureInfoIndex != INVALID_INDEX) { TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex]); @@ -556,6 +651,11 @@ void TextureManager::Remove(const TextureManager::TextureId textureId, TextureUp // If the state allows us to remove the TextureInfo data, we do so. if(removeTextureInfo) { + // If url location is BUFFER, decrease reference count of EncodedImageBuffer. + if(textureInfo.url.IsBufferResource()) + { + RemoveExternalEncodedImageBuffer(textureInfo.url.GetUrl()); + } // Permanently remove the textureInfo struct. mTextureInfoContainer.erase(mTextureInfoContainer.begin() + textureInfoIndex); } @@ -630,6 +730,28 @@ TextureManager::LoadState TextureManager::GetTextureStateInternal(TextureId text return loadState; } +Devel::PixelBuffer TextureManager::LoadImageSynchronously(const VisualUrl& url, + const ImageDimensions desiredSize, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode, + bool orientationCorrection) +{ + Devel::PixelBuffer pixelBuffer; + if(url.IsBufferResource()) + { + const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl()); + if(encodedImageBuffer) + { + pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } + } + else + { + pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } + return pixelBuffer; +} + TextureSet TextureManager::GetTextureSet(TextureId textureId) { TextureSet textureSet; // empty handle @@ -654,24 +776,70 @@ TextureSet TextureManager::GetTextureSet(TextureId textureId) return textureSet; } +EncodedImageBuffer TextureManager::GetEncodedImageBuffer(TextureId textureId) +{ + EncodedImageBuffer encodedImageBuffer; // empty handle + for(auto&& elem : mEncodedBufferTextures) + { + if(elem.textureId == textureId) + { + encodedImageBuffer = elem.encodedImageBuffer; + break; + } + } + return encodedImageBuffer; +} + +EncodedImageBuffer TextureManager::GetEncodedImageBuffer(const std::string& url) +{ + EncodedImageBuffer encodedImageBuffer; // empty handle + if(url.size() > 0 && VisualUrl::BUFFER == VisualUrl::GetProtocolType(url)) + { + std::string location = VisualUrl::GetLocation(url); + if(location.size() > 0u) + { + TextureId targetId = std::stoi(location); + return GetEncodedImageBuffer(targetId); + } + } + return encodedImageBuffer; +} + std::string TextureManager::AddExternalTexture(TextureSet& textureSet) { TextureManager::ExternalTextureInfo info; info.textureId = GenerateUniqueTextureId(); info.textureSet = textureSet; mExternalTextures.emplace_back(info); + return VisualUrl::CreateTextureUrl(std::to_string(info.textureId)); } +std::string TextureManager::AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer) +{ + // Duplication check + for(auto&& elem : mEncodedBufferTextures) + { + if(elem.encodedImageBuffer == encodedImageBuffer) + { + // If same buffer added, increase reference count and return. + elem.referenceCount++; + return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId)); + } + } + TextureManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer); + mEncodedBufferTextures.emplace_back(info); + return VisualUrl::CreateBufferUrl(std::to_string(info.textureId)); +} + TextureSet TextureManager::RemoveExternalTexture(const std::string& url) { if(url.size() > 0u) { - // get the location from the Url - VisualUrl parseUrl(url); - if(VisualUrl::TEXTURE == parseUrl.GetProtocolType()) + if(VisualUrl::TEXTURE == VisualUrl::GetProtocolType(url)) { - std::string location = parseUrl.GetLocation(); + // get the location from the Url + std::string location = VisualUrl::GetLocation(url); if(location.size() > 0u) { TextureId id = std::stoi(location); @@ -681,7 +849,10 @@ TextureSet TextureManager::RemoveExternalTexture(const std::string& url) if(iter->textureId == id) { auto textureSet = iter->textureSet; - mExternalTextures.erase(iter); + if(--(iter->referenceCount) <= 0) + { + mExternalTextures.erase(iter); + } return textureSet; } } @@ -691,6 +862,72 @@ TextureSet TextureManager::RemoveExternalTexture(const std::string& url) return TextureSet(); } +EncodedImageBuffer TextureManager::RemoveExternalEncodedImageBuffer(const std::string& url) +{ + if(url.size() > 0u) + { + if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(url)) + { + // get the location from the Url + std::string location = VisualUrl::GetLocation(url); + if(location.size() > 0u) + { + TextureId id = std::stoi(location); + const auto end = mEncodedBufferTextures.end(); + for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter) + { + if(iter->textureId == id) + { + auto encodedImageBuffer = iter->encodedImageBuffer; + if(--(iter->referenceCount) <= 0) + { + mEncodedBufferTextures.erase(iter); + } + return encodedImageBuffer; + } + } + } + } + } + return EncodedImageBuffer(); +} + +void TextureManager::UseExternalResource(const VisualUrl& url) +{ + if(VisualUrl::TEXTURE == url.GetProtocolType()) + { + std::string location = url.GetLocation(); + if(location.size() > 0u) + { + TextureId id = std::stoi(location); + for(auto&& elem : mExternalTextures) + { + if(elem.textureId == id) + { + elem.referenceCount++; + return; + } + } + } + } + else if(VisualUrl::BUFFER == url.GetProtocolType()) + { + std::string location = url.GetLocation(); + if(location.size() > 0u) + { + TextureId id = std::stoi(location); + for(auto&& elem : mEncodedBufferTextures) + { + if(elem.textureId == id) + { + elem.referenceCount++; + return; + } + } + } + } +} + void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer) { // make sure an observer doesn't observe the same object twice @@ -772,7 +1009,7 @@ void TextureManager::LoadTexture(TextureInfo& textureInfo, TextureUploadObserver textureInfo.loadState = LoadState::LOADING; if(!textureInfo.loadSynchronously) { - auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders; + auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders; auto loadingHelperIt = loadersContainer.GetNext(); auto premultiplyOnLoad = (textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID) ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF; DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); @@ -877,7 +1114,10 @@ void TextureManager::PostLoad(TextureInfo& textureInfo, Devel::PixelBuffer& pixe // 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. - if(textureInfo.maskTextureId != INVALID_TEXTURE_ID) + // 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) { if(textureInfo.loadState == LoadState::MASK_APPLYING) { @@ -971,7 +1211,7 @@ void TextureManager::ApplyMask(TextureInfo& textureInfo, TextureId maskTextureId DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F"); textureInfo.loadState = LoadState::MASK_APPLYING; - auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders; + auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders; auto loadingHelperIt = loadersContainer.GetNext(); auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF; DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); @@ -981,7 +1221,7 @@ void TextureManager::ApplyMask(TextureInfo& textureInfo, TextureId maskTextureId void TextureManager::UploadTexture(Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo) { - if(textureInfo.useAtlas != USE_ATLAS) + if(textureInfo.loadState != LoadState::UPLOADED && textureInfo.useAtlas != USE_ATLAS) { DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId); @@ -1243,7 +1483,7 @@ void TextureManager::AsyncLoadingHelper::LoadAnimatedImage(TextureId uint32_t frameIndex) { mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId)); - auto id = DevelAsyncImageLoader::LoadAnimatedImage(mLoader, animatedImageLoading, frameIndex); + auto id = GetImplementation(mLoader).LoadAnimatedImage(animatedImageLoading, frameIndex); mLoadingInfoContainer.back().loadId = id; } @@ -1256,8 +1496,16 @@ void TextureManager::AsyncLoadingHelper::Load(TextureId DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) { mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId)); - auto id = DevelAsyncImageLoader::Load(mLoader, url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad); - mLoadingInfoContainer.back().loadId = id; + if(DALI_UNLIKELY(url.IsBufferResource())) + { + auto id = GetImplementation(mLoader).LoadEncodedImageBuffer(mTextureManager.GetEncodedImageBuffer(url.GetUrl()), desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad); + mLoadingInfoContainer.back().loadId = id; + } + else + { + auto id = GetImplementation(mLoader).Load(url, desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad); + mLoadingInfoContainer.back().loadId = id; + } } void TextureManager::AsyncLoadingHelper::ApplyMask(TextureId textureId, @@ -1268,7 +1516,7 @@ void TextureManager::AsyncLoadingHelper::ApplyMask(TextureId DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) { mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId)); - auto id = DevelAsyncImageLoader::ApplyMask(mLoader, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad); + auto id = GetImplementation(mLoader).ApplyMask(pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad); mLoadingInfoContainer.back().loadId = id; }