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=bcde348559f0ad0c2256516b9002daafc0adf8b0;hp=39e180bf7417b0e95b1a91e467281341aa5d21b8;hb=e9ce8b35ce64531e5c6c6214527a5bf9b9747a36;hpb=aff52b6dbc13a5be62bbd5db2e4c76d3746d9e40 diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index 39e180b..bcde348 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,18 +25,20 @@ #include #include #include -#include #include #include +#include // INTERNAL HEADERS #include #include #include +#include namespace { +constexpr auto INITIAL_CACHE_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}; @@ -79,6 +81,18 @@ namespace #ifdef DEBUG_ENABLED Debug::Filter* gTextureManagerLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_TEXTURE_MANAGER" ); + +#define GET_LOAD_STATE_STRING( loadState ) \ + loadState == TextureManager::LoadState::NOT_STARTED ? "NOT_STARTED" : \ + loadState == TextureManager::LoadState::LOADING ? "LOADING" : \ + loadState == TextureManager::LoadState::LOAD_FINISHED ? "LOAD_FINISHED" : \ + loadState == TextureManager::LoadState::WAITING_FOR_MASK ? "WAITING_FOR_MASK" : \ + loadState == TextureManager::LoadState::MASK_APPLYING ? "MASK_APPLYING" : \ + loadState == TextureManager::LoadState::MASK_APPLIED ? "MASK_APPLIED" : \ + loadState == TextureManager::LoadState::UPLOADED ? "UPLOADED" : \ + loadState == TextureManager::LoadState::CANCELLED ? "CANCELLED" : \ + loadState == TextureManager::LoadState::LOAD_FAILED ? "LOAD_FAILED" : "Unknown" + #endif const uint32_t DEFAULT_ATLAS_SIZE( 1024u ); ///< This size can fit 8 by 8 images of average size 128 * 128 @@ -115,9 +129,15 @@ TextureManager::MaskingData::MaskingData() TextureManager::TextureManager() : mAsyncLocalLoaders( GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ), mAsyncRemoteLoaders( GetNumberOfRemoteLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ), + mExternalTextures(), + mLifecycleObservers(), + mLoadQueue(), mBrokenImageUrl(""), - mCurrentTextureId( 0 ) + mCurrentTextureId( 0 ), + mQueueLoadFlag(false) { + // Initialize the AddOn + RenderingAddOn::Get(); } TextureManager::~TextureManager() @@ -128,14 +148,105 @@ TextureManager::~TextureManager() } } +TextureSet TextureManager::LoadAnimatedImageTexture( + Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, Dali::SamplingMode::Type samplingMode, + bool synchronousLoading, TextureManager::TextureId& textureId, Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver ) +{ + TextureSet textureSet; + + if( synchronousLoading ) + { + Devel::PixelBuffer pixelBuffer; + if( animatedImageLoading ) + { + pixelBuffer = animatedImageLoading.LoadFrame( frameIndex ); + } + if( !pixelBuffer ) + { + // use broken image + pixelBuffer = LoadImageFromFile( mBrokenImageUrl ); + PixelData pixelData; + if( pixelBuffer ) + { + pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer + } + Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), + pixelData.GetWidth(), pixelData.GetHeight() ); + texture.Upload( pixelData ); + textureSet = TextureSet::New(); + textureSet.SetTexture( 0u, texture ); + } + else + { + PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer + if( !textureSet ) + { + Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), + pixelData.GetWidth(), pixelData.GetHeight() ); + texture.Upload( pixelData ); + textureSet = TextureSet::New(); + textureSet.SetTexture( 0u, texture ); + } + } + } + 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 ); + TextureManager::LoadState loadState = GetTextureStateInternal( textureId ); + if( loadState == TextureManager::LoadState::UPLOADED ) + { + // UploadComplete has already been called - keep the same texture set + textureSet = GetTextureSet( textureId ); + } + } + + if( textureSet ) + { + Sampler sampler = Sampler::New(); + sampler.SetWrapMode( wrapModeU, wrapModeV ); + textureSet.SetSampler( 0u, sampler ); + } + + return textureSet; +} + +Devel::PixelBuffer TextureManager::LoadPixelBuffer( + const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, bool synchronousLoading, TextureUploadObserver* textureObserver, bool orientationCorrection, TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) +{ + Devel::PixelBuffer pixelBuffer; + if( synchronousLoading ) + { + if( url.IsValid() ) + { + pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode, + orientationCorrection ); + if( pixelBuffer && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) + { + PreMultiply( pixelBuffer, preMultiplyOnLoad ); + } + } + } + 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 ); + } + + return pixelBuffer; +} + TextureSet TextureManager::LoadTexture( - const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, - Dali::SamplingMode::Type samplingMode, const MaskingDataPointer& maskInfo, - bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect, - bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU, - Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver, - AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) + const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode, MaskingDataPointer& maskInfo, + bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect, + Dali::ImageDimensions& textureRectSize, bool& atlasingStatus, bool& loadingStatus, + Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver, + AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, bool orientationCorrection, + TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) { TextureSet textureSet; @@ -166,6 +277,15 @@ TextureSet TextureManager::LoadTexture( { Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), 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 ); + if( maskPixelBuffer ) + { + pixelBuffer.ApplyMask( maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask ); + } + } if( pixelBuffer ) { PreMultiply( pixelBuffer, preMultiplyOnLoad ); @@ -175,7 +295,6 @@ TextureSet TextureManager::LoadTexture( if( !data ) { // use broken image - textureSet = TextureSet::New(); Devel::PixelBuffer pixelBuffer = LoadImageFromFile( mBrokenImageUrl ); if( pixelBuffer ) { @@ -203,6 +322,11 @@ TextureSet TextureManager::LoadTexture( textureSet = TextureSet::New(); textureSet.SetTexture( 0u, texture ); } + else + { + textureRectSize.SetWidth(data.GetWidth()); + textureRectSize.SetHeight(data.GetHeight()); + } } } else @@ -210,18 +334,19 @@ TextureSet TextureManager::LoadTexture( loadingStatus = true; if( atlasingStatus ) { - textureSet = imageAtlasManager->Add( textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver ); + textureSet = imageAtlasManager->Add( textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver); } if( !textureSet ) // big image, no atlasing or atlasing failed { atlasingStatus = false; - if( !maskInfo ) + if( !maskInfo || !maskInfo->mAlphaMaskUrl.IsValid() ) { textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad ); } else { + maskInfo->mAlphaMaskId = RequestMaskLoad( maskInfo->mAlphaMaskUrl ); textureId = RequestLoad( url, maskInfo->mAlphaMaskId, maskInfo->mContentScaleFactor, @@ -235,13 +360,25 @@ TextureSet TextureManager::LoadTexture( } TextureManager::LoadState loadState = GetTextureStateInternal( textureId ); - loadingStatus = ( loadState == TextureManager::LOADING ); - - if( loadState == TextureManager::UPLOADED ) + 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 + { + textureRectSize = desiredSize; } } @@ -267,8 +404,8 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) { return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, - false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, - preMultiplyOnLoad ); + false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, + preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u ); } TextureManager::TextureId TextureManager::RequestLoad( @@ -286,8 +423,8 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) { return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, - cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, - preMultiplyOnLoad ); + cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, + preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u ); } TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl ) @@ -295,8 +432,8 @@ TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& mask // 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, KEEP_PIXEL_BUFFER, NULL, true, - TextureManager::ReloadPolicy::CACHED, preMultiply ); + SamplingMode::NO_FILTER, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, + TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u ); } TextureManager::TextureId TextureManager::RequestLoadInternal( @@ -312,18 +449,24 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( TextureUploadObserver* observer, bool orientationCorrection, TextureManager::ReloadPolicy reloadPolicy, - TextureManager::MultiplyOnLoad& preMultiplyOnLoad) + TextureManager::MultiplyOnLoad& preMultiplyOnLoad, + Dali::AnimatedImageLoading animatedImageLoading, + uint32_t frameIndex ) { // First check if the requested Texture is cached. - const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, - maskTextureId, preMultiplyOnLoad ); + bool isAnimatedImage = ( animatedImageLoading ) ? true : false; - TextureManager::TextureId textureId = INVALID_TEXTURE_ID; + TextureHash textureHash = INITIAL_CACHE_NUMBER; + int cacheIndex = INVALID_CACHE_INDEX; + if(storageType != StorageType::RETURN_PIXEL_BUFFER && !isAnimatedImage) + { + textureHash = GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId); - // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. - int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, - maskTextureId, preMultiplyOnLoad ); + // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. + cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad); + } + TextureManager::TextureId textureId = INVALID_TEXTURE_ID; // Check if the requested Texture exists in the cache. if( cacheIndex != INVALID_CACHE_INDEX ) { @@ -334,7 +477,11 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( ++( mTextureInfoContainer[ cacheIndex ].referenceCount ); } textureId = mTextureInfoContainer[ cacheIndex ].textureId; - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n", + + // Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info. + preMultiplyOnLoad = mTextureInfoContainer[ 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 ); } @@ -346,10 +493,10 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(), desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, - preMultiply ) ); + preMultiply, animatedImageLoading, frameIndex ) ); cacheIndex = mTextureInfoContainer.size() - 1u; - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", + 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 ); } @@ -361,80 +508,83 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( textureInfo.storageType = storageType; textureInfo.orientationCorrection = orientationCorrection; - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureInfo loadState:%s\n", - textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" : - textureInfo.loadState == TextureManager::LOADING ? "LOADING" : - textureInfo.loadState == TextureManager::UPLOADED ? "UPLOADED" : - textureInfo.loadState == TextureManager::CANCELLED ? "CANCELLED" : "Unknown" ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureInfo loadState:%s\n", + GET_LOAD_STATE_STRING(textureInfo.loadState ) ); // Force reloading of texture by setting loadState unless already loading or cancelled. - if ( TextureManager::ReloadPolicy::FORCED == reloadPolicy && TextureManager::LOADING != textureInfo.loadState && - TextureManager::CANCELLED != textureInfo.loadState ) + if ( TextureManager::ReloadPolicy::FORCED == reloadPolicy && + TextureManager::LoadState::LOADING != textureInfo.loadState && + TextureManager::LoadState::WAITING_FOR_MASK != textureInfo.loadState && + TextureManager::LoadState::MASK_APPLYING != textureInfo.loadState && + 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 ); - textureInfo.loadState = TextureManager::NOT_STARTED; + + 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 ) { - case TextureManager::LOAD_FAILED: // Failed notifies observer which then stops observing. - case TextureManager::NOT_STARTED: + case TextureManager::LoadState::LOAD_FAILED: // Failed notifies observer which then stops observing. + case TextureManager::LoadState::NOT_STARTED: { - LoadTexture( textureInfo ); - ObserveTexture( textureInfo, observer ); + LoadOrQueueTexture( textureInfo, observer ); // If called inside NotifyObservers, queues until afterwards break; } - case TextureManager::LOADING: + 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::UPLOADED: + case TextureManager::LoadState::UPLOADED: { if( observer ) { - // The Texture has already loaded. The other observers have already been notified. - // We need to send a "late" loaded notification for this observer. - observer->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet, - textureInfo.useAtlas, textureInfo.atlasRect, - textureInfo.preMultiplied ); + LoadOrQueueTexture( textureInfo, observer ); } break; } - case TextureManager::CANCELLED: + 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::LOADING; + textureInfo.loadState = TextureManager::LoadState::LOADING; ObserveTexture( textureInfo, observer ); break; } - case TextureManager::LOAD_FINISHED: - case TextureManager::WAITING_FOR_MASK: - // Loading has already completed. Do nothing. + case TextureManager::LoadState::LOAD_FINISHED: + { + // Loading has already completed. + if( observer && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER ) + { + LoadOrQueueTexture( textureInfo, observer ); + } break; + } } // Return the TextureId for which this Texture can now be referenced by externally. return textureId; } -void TextureManager::Remove( const TextureManager::TextureId textureId ) +void TextureManager::Remove( const TextureManager::TextureId textureId, TextureUploadObserver* observer ) { int textureInfoIndex = GetCacheIndexFromId( textureId ); if( textureInfoIndex != INVALID_INDEX ) { TextureInfo& textureInfo( mTextureInfoContainer[ textureInfoIndex ] ); - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::Remove(%d) cacheIdx:%d loadState:%s\n", - textureId, textureInfoIndex, - textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" : - textureInfo.loadState == TextureManager::LOADING ? "LOADING" : - textureInfo.loadState == TextureManager::UPLOADED ? "UPLOADED" : - textureInfo.loadState == TextureManager::CANCELLED ? "CANCELLED" : "Unknown" ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, + "TextureManager::Remove(%d) url:%s\n cacheIdx:%d loadState:%s reference count = %d\n", + textureId, textureInfo.url.GetUrl().c_str(), + textureInfoIndex, GET_LOAD_STATE_STRING( textureInfo.loadState ), textureInfo.referenceCount ); // Decrement the reference count and check if this is the last user of this Texture. if( --textureInfo.referenceCount <= 0 ) @@ -444,7 +594,7 @@ void TextureManager::Remove( const TextureManager::TextureId textureId ) bool removeTextureInfo = false; // If loaded, we can remove the TextureInfo and the Atlas (if atlased). - if( textureInfo.loadState == UPLOADED ) + if( textureInfo.loadState == LoadState::UPLOADED ) { if( textureInfo.atlas ) { @@ -452,11 +602,11 @@ void TextureManager::Remove( const TextureManager::TextureId textureId ) } removeTextureInfo = true; } - else if( textureInfo.loadState == LOADING ) + else if( textureInfo.loadState == LoadState::LOADING ) { // We mark the textureInfo for removal. // Once the load has completed, this method will be called again. - textureInfo.loadState = CANCELLED; + textureInfo.loadState = LoadState::CANCELLED; } else { @@ -471,6 +621,19 @@ void TextureManager::Remove( const TextureManager::TextureId textureId ) mTextureInfoContainer.erase( mTextureInfoContainer.begin() + textureInfoIndex ); } } + + if( observer ) + { + // Remove element from the LoadQueue + for( auto&& element : mLoadQueue ) + { + if( element.mObserver == observer ) + { + mLoadQueue.Erase( &element ); + break; + } + } + } } } @@ -492,7 +655,7 @@ VisualUrl TextureManager::GetVisualUrl( TextureId textureId ) TextureManager::LoadState TextureManager::GetTextureState( TextureId textureId ) { - LoadState loadState = TextureManager::NOT_STARTED; + LoadState loadState = TextureManager::LoadState::NOT_STARTED; int cacheIndex = GetCacheIndexFromId( textureId ); if( cacheIndex != INVALID_CACHE_INDEX ) @@ -516,7 +679,7 @@ TextureManager::LoadState TextureManager::GetTextureState( TextureId textureId ) TextureManager::LoadState TextureManager::GetTextureStateInternal( TextureId textureId ) { - LoadState loadState = TextureManager::NOT_STARTED; + LoadState loadState = TextureManager::LoadState::NOT_STARTED; int cacheIndex = GetCacheIndexFromId( textureId ); if( cacheIndex != INVALID_CACHE_INDEX ) @@ -589,7 +752,6 @@ TextureSet TextureManager::RemoveExternalTexture( const std::string& url ) return TextureSet(); } - void TextureManager::AddObserver( TextureManager::LifecycleObserver& observer ) { // make sure an observer doesn't observe the same object twice @@ -613,32 +775,125 @@ void TextureManager::RemoveObserver( TextureManager::LifecycleObserver& observer DALI_ASSERT_DEBUG(endIter != mLifecycleObservers.End()); } +void TextureManager::LoadOrQueueTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) +{ + switch( textureInfo.loadState ) + { + case LoadState::NOT_STARTED: + case LoadState::LOAD_FAILED: + { + if( mQueueLoadFlag ) + { + QueueLoadTexture( textureInfo, observer ); + } + else + { + LoadTexture( textureInfo, observer ); + } + break; + } + case LoadState::UPLOADED: + { + if( mQueueLoadFlag ) + { + QueueLoadTexture( textureInfo, observer ); + } + else + { + // The Texture has already loaded. The other observers have already been notified. + // We need to send a "late" loaded notification for this observer. + observer->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet, + textureInfo.useAtlas, textureInfo.atlasRect, + textureInfo.preMultiplied ); + } + break; + } + case LoadState::LOADING: + case LoadState::CANCELLED: + case LoadState::LOAD_FINISHED: + case LoadState::WAITING_FOR_MASK: + case LoadState::MASK_APPLYING: + case LoadState::MASK_APPLIED: + { + break; + } + } +} -bool TextureManager::LoadTexture( TextureInfo& textureInfo ) +void TextureManager::QueueLoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) { - bool success = true; + auto textureId = textureInfo.textureId; + mLoadQueue.PushBack( LoadQueueElement( textureId, observer) ); - if( textureInfo.loadState == NOT_STARTED ) - { - textureInfo.loadState = LOADING; + observer->DestructionSignal().Connect( this, &TextureManager::ObserverDestroyed ); +} - if( !textureInfo.loadSynchronously ) +void TextureManager::LoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) +{ + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::LoadTexture(): url:%s sync:%s\n", + textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously?"T":"F" ); + + textureInfo.loadState = LoadState::LOADING; + if( !textureInfo.loadSynchronously ) + { + auto& loadersContainer = textureInfo.url.IsLocalResource() ? 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()); + if( textureInfo.animatedImageLoading ) + { + loadingHelperIt->LoadAnimatedImage( textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex ); + } + else { - auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders; - auto loadingHelperIt = loadersContainer.GetNext(); - DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, - textureInfo.samplingMode, textureInfo.orientationCorrection ); + textureInfo.samplingMode, textureInfo.orientationCorrection, + premultiplyOnLoad ); } } + ObserveTexture( textureInfo, observer ); +} + +void TextureManager::ProcessQueuedTextures() +{ + for( auto&& element : mLoadQueue ) + { + if( !element.mObserver ) + { + continue; + } - return success; + int cacheIndex = GetCacheIndexFromId( element.mTextureId ); + if( cacheIndex != INVALID_CACHE_INDEX ) + { + TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] ); + if( textureInfo.loadState == LoadState::UPLOADED ) + { + element.mObserver->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet, + textureInfo.useAtlas, textureInfo.atlasRect, + textureInfo.preMultiplied ); + } + else if ( textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER ) + { + element.mObserver->LoadComplete( true, textureInfo.pixelBuffer, textureInfo.url, textureInfo.preMultiplied ); + } + else + { + LoadTexture( textureInfo, element.mObserver ); + } + } + } + mLoadQueue.Clear(); } void TextureManager::ObserveTexture( TextureInfo& textureInfo, TextureUploadObserver* observer ) { + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::ObserveTexture(): url:%s observer:%p\n", + textureInfo.url.GetUrl().c_str(), observer ); + if( observer ) { textureInfo.observerList.PushBack( observer ); @@ -662,16 +917,18 @@ void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingCo { TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] ); - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " CacheIndex:%d LoadState: %d\n", cacheIndex, textureInfo.loadState ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, + " textureId:%d Url:%s CacheIndex:%d LoadState: %d\n", + textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex, textureInfo.loadState ); - if( textureInfo.loadState != CANCELLED ) + if( textureInfo.loadState != LoadState::CANCELLED ) { // textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified) PostLoad( textureInfo, pixelBuffer ); } else { - Remove( textureInfo.textureId ); + Remove( textureInfo.textureId, nullptr ); } } } @@ -687,26 +944,35 @@ void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pix { // No atlas support for now textureInfo.useAtlas = NO_ATLAS; + textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); - if( textureInfo.storageType == UPLOAD_TO_TEXTURE ) + if( textureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE ) { // 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 ) { - LoadState maskLoadState = GetTextureStateInternal( textureInfo.maskTextureId ); - if( maskLoadState == LOADING ) + if( textureInfo.loadState == LoadState::MASK_APPLYING ) { - textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily - textureInfo.loadState = WAITING_FOR_MASK; - } - else if( maskLoadState == LOAD_FINISHED ) - { - ApplyMask( pixelBuffer, textureInfo.maskTextureId, textureInfo.scaleFactor, textureInfo.cropToMask ); + textureInfo.loadState = LoadState::MASK_APPLIED; UploadTexture( pixelBuffer, textureInfo ); NotifyObservers( textureInfo, true ); } + else + { + LoadState maskLoadState = 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 ) + { + // Send New Task to Thread + ApplyMask( textureInfo, textureInfo.maskTextureId ); + } + } } else { @@ -717,18 +983,23 @@ void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pix else { textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data - textureInfo.loadState = LOAD_FINISHED; + textureInfo.loadState = LoadState::LOAD_FINISHED; - // 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 ); + 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 ); + } } } else { - DALI_LOG_ERROR( "TextureManager::AsyncImageLoad(%s) failed\n", textureInfo.url.GetUrl().c_str() ); - // @todo If the load was unsuccessful, upload the broken image. - textureInfo.loadState = LOAD_FAILED; + textureInfo.loadState = LoadState::LOAD_FAILED; CheckForWaitingTexture( textureInfo ); NotifyObservers( textureInfo, false ); } @@ -743,54 +1014,60 @@ void TextureManager::CheckForWaitingTexture( TextureInfo& maskTextureInfo ) for( unsigned int cacheIndex = 0; cacheIndex < size; ++cacheIndex ) { if( mTextureInfoContainer[cacheIndex].maskTextureId == maskTextureInfo.textureId && - mTextureInfoContainer[cacheIndex].loadState == WAITING_FOR_MASK ) + mTextureInfoContainer[cacheIndex].loadState == LoadState::WAITING_FOR_MASK ) { TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] ); - Devel::PixelBuffer pixelBuffer = textureInfo.pixelBuffer; - textureInfo.pixelBuffer.Reset(); - if( maskTextureInfo.loadState == LOAD_FINISHED ) + if( maskTextureInfo.loadState == LoadState::LOAD_FINISHED ) { - ApplyMask( pixelBuffer, maskTextureInfo.textureId, textureInfo.scaleFactor, textureInfo.cropToMask ); - UploadTexture( pixelBuffer, textureInfo ); - NotifyObservers( textureInfo, true ); + // Send New Task to Thread + ApplyMask( textureInfo, maskTextureInfo.textureId ); } else { - DALI_LOG_ERROR( "TextureManager::ApplyMask to %s failed\n", textureInfo.url.GetUrl().c_str() ); - textureInfo.loadState = LOAD_FAILED; + textureInfo.pixelBuffer.Reset(); + textureInfo.loadState = LoadState::LOAD_FAILED; NotifyObservers( textureInfo, false ); } } } } -void TextureManager::ApplyMask( - Devel::PixelBuffer& pixelBuffer, TextureId maskTextureId, - float contentScale, bool cropToMask ) +void TextureManager::ApplyMask( TextureInfo& textureInfo, TextureId maskTextureId ) { int maskCacheIndex = GetCacheIndexFromId( maskTextureId ); if( maskCacheIndex != INVALID_CACHE_INDEX ) { Devel::PixelBuffer maskPixelBuffer = mTextureInfoContainer[maskCacheIndex].pixelBuffer; - pixelBuffer.ApplyMask( maskPixelBuffer, contentScale, cropToMask ); + Devel::PixelBuffer pixelBuffer = textureInfo.pixelBuffer; + textureInfo.pixelBuffer.Reset(); + + 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 loadingHelperIt = loadersContainer.GetNext(); + auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF; + DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); + loadingHelperIt->ApplyMask( textureInfo.textureId, pixelBuffer, maskPixelBuffer, textureInfo.scaleFactor, textureInfo.cropToMask, premultiplyOnLoad ); } } - void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo ) { if( textureInfo.useAtlas != USE_ATLAS ) { - DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId ); + DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId ); - // If the texture doesn't have an alpha channel, can't pre-multiply it. - // Ensure that we don't change the load parameter (it's used for hashing), and instead set - // the status for use in the observer. - auto preMultiply = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : - TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; - PreMultiply( pixelBuffer, preMultiply ); - textureInfo.preMultiplied = (preMultiply == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ); + // Check if this pixelBuffer is premultiplied + textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); + + auto& renderingAddOn = RenderingAddOn::Get(); + if( renderingAddOn.IsValid() ) + { + renderingAddOn.CreateGeometry( textureInfo.textureId, pixelBuffer ); + } Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() ); @@ -808,7 +1085,7 @@ void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo // Note: This is regardless of success as we care about whether a // load attempt is in progress or not. If unsuccessful, a broken // image is still loaded. - textureInfo.loadState = UPLOADED; + textureInfo.loadState = LoadState::UPLOADED; } void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success ) @@ -817,52 +1094,56 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success ) // If there is an observer: Notify the load is complete, whether successful or not, // and erase it from the list - unsigned int observerCount = textureInfo.observerList.Count(); TextureInfo* info = &textureInfo; - while( observerCount ) + mQueueLoadFlag = true; + + while( info->observerList.Count() ) { TextureUploadObserver* observer = info->observerList[0]; // During UploadComplete() a Control ResourceReady() signal is emitted. // During that signal the app may add remove /add Textures (e.g. via - // ImageViews). At this point no more observers can be added to the - // observerList, because textureInfo.loadState = UPLOADED. However it is - // possible for observers to be removed, hence we check the observer list - // count every iteration. - - // The reference to the textureInfo struct can also become invalidated, - // because new load requests can modify the mTextureInfoContainer list - // (e.g. if more requests are pushed back it can cause the list to be - // resized invalidating the reference to the TextureInfo ). - observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect, - info->preMultiplied ); + // ImageViews). + // It is possible for observers to be removed from the observer list, + // and it is also possible for the mTextureInfoContainer to be modified, + // 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, "NotifyObservers() url:%s loadState:%s\n", + textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState ) ); + + // It is possible for the observer to be deleted. + // Disconnect and remove the observer first. observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed ); - // Get the textureInfo from the container again as it may have been - // invalidated, + info->observerList.Erase( info->observerList.begin() ); - int textureInfoIndex = GetCacheIndexFromId( textureId ); - if( textureInfoIndex == INVALID_CACHE_INDEX) + if( info->storageType == StorageType::RETURN_PIXEL_BUFFER ) + { + observer->LoadComplete( success, info->pixelBuffer, info->url, info->preMultiplied ); + } + else { - return; // texture has been removed - can stop. + observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect, + info->preMultiplied ); } - info = &mTextureInfoContainer[ textureInfoIndex ]; - observerCount = info->observerList.Count(); - if ( observerCount > 0 ) + // Get the textureInfo from the container again as it may have been invalidated. + int textureInfoIndex = GetCacheIndexFromId( textureId ); + if( textureInfoIndex == INVALID_CACHE_INDEX) { - // remove the observer that was just triggered if it's still in the list - for( TextureInfo::ObserverListType::Iterator j = info->observerList.Begin(); j != info->observerList.End(); ++j ) - { - if( *j == observer ) - { - info->observerList.Erase( j ); - observerCount--; - break; - } - } + break; // texture has been removed - can stop. } + info = &mTextureInfoContainer[ textureInfoIndex ]; + } + + mQueueLoadFlag = false; + ProcessQueuedTextures(); + + if( info->storageType == StorageType::RETURN_PIXEL_BUFFER && info->observerList.Count() == 0 ) + { + Remove( info->textureId, nullptr ); } } @@ -892,8 +1173,7 @@ TextureManager::TextureHash TextureManager::GenerateHash( const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas, - TextureId maskTextureId, - TextureManager::MultiplyOnLoad preMultiplyOnLoad) + TextureId maskTextureId) { std::string hashTarget( url ); const size_t urlLength = hashTarget.length(); @@ -921,8 +1201,21 @@ TextureManager::TextureHash TextureManager::GenerateHash( { // We are not including sizing information, but we still need an extra byte for atlasing. hashTarget.resize( urlLength + 1u ); + // Add the atlasing to the hash input. - hashTarget[ urlLength ] = useAtlas; + switch( useAtlas ) + { + case UseAtlas::NO_ATLAS: + { + hashTarget[ urlLength ] = 'f'; + break; + } + case UseAtlas::USE_ATLAS: + { + hashTarget[ urlLength ] = 't'; + break; + } + } } if( maskTextureId != INVALID_TEXTURE_ID ) @@ -940,22 +1233,6 @@ TextureManager::TextureHash TextureManager::GenerateHash( } } - auto premultipliedIndex = hashTarget.length(); - hashTarget.resize( premultipliedIndex + 1 ); - switch( preMultiplyOnLoad ) - { - case TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD: - { - hashTarget[ premultipliedIndex ] = 't'; - break; - } - case TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY: - { - hashTarget[ premultipliedIndex ] = 'f'; - break; - } - } - return Dali::CalculateHash( hashTarget ); } @@ -967,7 +1244,7 @@ int TextureManager::FindCachedTexture( const Dali::SamplingMode::Type samplingMode, const bool useAtlas, TextureId maskTextureId, - TextureManager::MultiplyOnLoad preMultiplyOnLoad ) + TextureManager::MultiplyOnLoad preMultiplyOnLoad) { // Default to an invalid ID, in case we do not find a match. int cacheIndex = INVALID_CACHE_INDEX; @@ -980,21 +1257,24 @@ int TextureManager::FindCachedTexture( { // We have a match, now we check all the original parameters in case of a hash collision. TextureInfo& textureInfo( mTextureInfoContainer[i] ); - auto multiplyOnLoad = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : - TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; if( ( url == textureInfo.url.GetUrl() ) && ( useAtlas == textureInfo.useAtlas ) && ( maskTextureId == textureInfo.maskTextureId ) && ( size == textureInfo.desiredSize ) && - ( preMultiplyOnLoad == multiplyOnLoad ) && ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) || ( fittingMode == textureInfo.fittingMode && samplingMode == textureInfo.samplingMode ) ) ) { - // The found Texture is a match. - cacheIndex = i; - break; + // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different. + // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false. + if( ( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad ) + || ( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied ) ) + { + // The found Texture is a match. + cacheIndex = i; + break; + } } } } @@ -1021,6 +1301,15 @@ void TextureManager::ObserverDestroyed( TextureUploadObserver* observer ) } } } + + // Remove element from the LoadQueue + for( auto&& element : mLoadQueue ) + { + if( element.mObserver == observer ) + { + element.mObserver = nullptr; + } + } } @@ -1030,15 +1319,37 @@ TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureMa { } -void TextureManager::AsyncLoadingHelper::Load(TextureId textureId, - const VisualUrl& url, - ImageDimensions desiredSize, - FittingMode::Type fittingMode, - SamplingMode::Type samplingMode, - bool orientationCorrection) +void TextureManager::AsyncLoadingHelper::LoadAnimatedImage( TextureId textureId, + Dali::AnimatedImageLoading animatedImageLoading, + uint32_t frameIndex ) +{ + mLoadingInfoContainer.push_back( AsyncLoadingInfo( textureId ) ); + auto id = DevelAsyncImageLoader::LoadAnimatedImage( mLoader, animatedImageLoading, frameIndex ); + mLoadingInfoContainer.back().loadId = id; +} + +void TextureManager::AsyncLoadingHelper::Load( TextureId textureId, + const VisualUrl& url, + ImageDimensions desiredSize, + FittingMode::Type fittingMode, + SamplingMode::Type samplingMode, + bool orientationCorrection, + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad ) +{ + mLoadingInfoContainer.push_back( AsyncLoadingInfo( textureId ) ); + auto id = DevelAsyncImageLoader::Load( mLoader, url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad ); + mLoadingInfoContainer.back().loadId = id; +} + +void TextureManager::AsyncLoadingHelper::ApplyMask( TextureId textureId, + Devel::PixelBuffer pixelBuffer, + Devel::PixelBuffer maskPixelBuffer, + float contentScale, + bool cropToMask, + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad ) { - mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId)); - auto id = mLoader.Load(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + mLoadingInfoContainer.push_back( AsyncLoadingInfo( textureId ) ); + auto id = DevelAsyncImageLoader::ApplyMask( mLoader, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad ); mLoadingInfoContainer.back().loadId = id; } @@ -1060,9 +1371,9 @@ TextureManager::AsyncLoadingHelper::AsyncLoadingHelper( } void TextureManager::AsyncLoadingHelper::AsyncLoadComplete(uint32_t id, - Devel::PixelBuffer pixelBuffer) + Devel::PixelBuffer pixelBuffer ) { - mTextureManager.AsyncLoadComplete(mLoadingInfoContainer, id, pixelBuffer); + mTextureManager.AsyncLoadComplete( mLoadingInfoContainer, id, pixelBuffer ); } void TextureManager::SetBrokenImageUrl(const std::string& brokenImageUrl) @@ -1070,6 +1381,13 @@ void TextureManager::SetBrokenImageUrl(const std::string& brokenImageUrl) mBrokenImageUrl = brokenImageUrl; } +Geometry TextureManager::GetRenderGeometry(TextureId textureId, uint32_t& frontElements, uint32_t& backElements ) +{ + return RenderingAddOn::Get().IsValid() ? + RenderingAddOn::Get().GetGeometry( textureId, frontElements, backElements) : + Geometry(); +} + } // namespace Internal } // namespace Toolkit