/*
- * Copyright (c) 2019 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.
#include <dali/devel-api/adaptor-framework/environment-variable.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/common/hash.h>
-#include <dali/devel-api/images/texture-set-image.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
#include <dali/integration-api/debug.h>
+#include <dali/public-api/rendering/geometry.h>
// INTERNAL HEADERS
#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/rendering-addon.h>
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};
Debug::Filter* gTextureManagerLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_TEXTURE_MANAGER" );
#define GET_LOAD_STATE_STRING( loadState ) \
- loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" : \
- loadState == TextureManager::LOADING ? "LOADING" : \
- loadState == TextureManager::LOAD_FINISHED ? "LOAD_FINISHED" : \
- loadState == TextureManager::WAITING_FOR_MASK ? "WAITING_FOR_MASK" : \
- loadState == TextureManager::MASK_APPLYING ? "MASK_APPLYING" : \
- loadState == TextureManager::MASK_APPLIED ? "MASK_APPLIED" : \
- loadState == TextureManager::UPLOADED ? "UPLOADED" : \
- loadState == TextureManager::CANCELLED ? "CANCELLED" : \
- loadState == TextureManager::LOAD_FAILED ? "LOAD_FAILED" : "Unknown"
+ 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
mCurrentTextureId( 0 ),
mQueueLoadFlag(false)
{
+ // Initialize the AddOn
+ RenderingAddOn::Get();
}
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,
+ 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,
{
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 );
if( !data )
{
// use broken image
- textureSet = TextureSet::New();
Devel::PixelBuffer pixelBuffer = LoadImageFromFile( mBrokenImageUrl );
if( pixelBuffer )
{
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,
}
TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
- 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::LOADING ||
- loadState == TextureManager::WAITING_FOR_MASK ||
- loadState == TextureManager::MASK_APPLYING ||
- loadState == TextureManager::MASK_APPLIED ||
- loadState == TextureManager::NOT_STARTED ||
+ 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 );
}
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(
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 )
// 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(
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 );
+ 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)
+ {
+ textureHash = GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, isAnimatedImage, frameIndex);
+
+ // 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, isAnimatedImage, frameIndex);
+ }
- // 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 );
+ TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
// Check if the requested Texture exists in the cache.
if( cacheIndex != INVALID_CACHE_INDEX )
++( mTextureInfoContainer[ cacheIndex ].referenceCount );
}
textureId = mTextureInfoContainer[ cacheIndex ].textureId;
+
+ // 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 );
}
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::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n",
// Force reloading of texture by setting loadState unless already loading or cancelled.
if ( TextureManager::ReloadPolicy::FORCED == reloadPolicy &&
- TextureManager::LOADING != textureInfo.loadState &&
- TextureManager::WAITING_FOR_MASK != textureInfo.loadState &&
- TextureManager::MASK_APPLYING != textureInfo.loadState &&
- TextureManager::MASK_APPLIED != textureInfo.loadState &&
- TextureManager::CANCELLED != textureInfo.loadState )
+ 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:
{
LoadOrQueueTexture( textureInfo, observer ); // If called inside NotifyObservers, queues until afterwards
break;
}
- case TextureManager::LOADING:
- case TextureManager::WAITING_FOR_MASK:
- case TextureManager::MASK_APPLYING:
- case TextureManager::MASK_APPLIED:
+ 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 )
{
}
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:
- // 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) url:%s\n cacheIdx:%d loadState:%s\n",
+ "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 ) );
+ 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 )
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 )
{
}
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
{
mTextureInfoContainer.erase( mTextureInfoContainer.begin() + textureInfoIndex );
}
}
+
+ if( observer )
+ {
+ // Remove element from the LoadQueue
+ for( auto&& element : mLoadQueue )
+ {
+ if( element.mObserver == observer )
+ {
+ mLoadQueue.Erase( &element );
+ break;
+ }
+ }
+ }
}
}
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 )
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 )
return TextureSet();
}
-
void TextureManager::AddObserver( TextureManager::LifecycleObserver& observer )
{
// make sure an observer doesn't observe the same object twice
{
switch( textureInfo.loadState )
{
- case NOT_STARTED:
- case LOAD_FAILED:
+ case LoadState::NOT_STARTED:
+ case LoadState::LOAD_FAILED:
{
if( mQueueLoadFlag )
{
}
break;
}
- case UPLOADED:
+ case LoadState::UPLOADED:
{
if( mQueueLoadFlag )
{
}
break;
}
- case LOADING:
- case CANCELLED:
- case LOAD_FINISHED:
- case WAITING_FOR_MASK:
- case MASK_APPLYING:
- case MASK_APPLIED:
+ case LoadState::LOADING:
+ case LoadState::CANCELLED:
+ case LoadState::LOAD_FINISHED:
+ case LoadState::WAITING_FOR_MASK:
+ case LoadState::MASK_APPLYING:
+ case LoadState::MASK_APPLIED:
{
break;
}
{
auto textureId = textureInfo.textureId;
mLoadQueue.PushBack( LoadQueueElement( textureId, observer) );
+
+ observer->DestructionSignal().Connect( this, &TextureManager::ObserverDestroyed );
}
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 = LOADING;
+ textureInfo.loadState = LoadState::LOADING;
if( !textureInfo.loadSynchronously )
{
auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
auto loadingHelperIt = loadersContainer.GetNext();
- auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
+ auto premultiplyOnLoad = ( textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID ) ?
+ DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
- loadingHelperIt->Load(textureInfo.textureId, textureInfo.url,
- textureInfo.desiredSize, textureInfo.fittingMode,
- textureInfo.samplingMode, textureInfo.orientationCorrection,
- premultiplyOnLoad );
+ if( textureInfo.animatedImageLoading )
+ {
+ loadingHelperIt->LoadAnimatedImage( textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex );
+ }
+ else
+ {
+ loadingHelperIt->Load(textureInfo.textureId, textureInfo.url,
+ textureInfo.desiredSize, textureInfo.fittingMode,
+ textureInfo.samplingMode, textureInfo.orientationCorrection,
+ premultiplyOnLoad );
+ }
}
ObserveTexture( textureInfo, observer );
}
{
for( auto&& element : mLoadQueue )
{
+ if( !element.mObserver )
+ {
+ continue;
+ }
+
int cacheIndex = GetCacheIndexFromId( element.mTextureId );
if( cacheIndex != INVALID_CACHE_INDEX )
{
TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
- if( textureInfo.loadState == UPLOADED )
+ 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 );
" 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 )
{
- if( textureInfo.maskApplied )
- {
- textureInfo.loadState = MASK_APPLIED;
- }
// textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified)
PostLoad( textureInfo, pixelBuffer );
}
else
{
- Remove( textureInfo.textureId );
+ Remove( textureInfo.textureId, nullptr );
}
}
}
{
// 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 )
{
- if( textureInfo.loadState == MASK_APPLIED )
+ if( textureInfo.loadState == LoadState::MASK_APPLYING )
{
+ textureInfo.loadState = LoadState::MASK_APPLIED;
UploadTexture( pixelBuffer, textureInfo );
NotifyObservers( textureInfo, true );
}
{
LoadState maskLoadState = GetTextureStateInternal( textureInfo.maskTextureId );
textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
- if( maskLoadState == LOADING )
+ if( maskLoadState == LoadState::LOADING )
{
- textureInfo.loadState = WAITING_FOR_MASK;
+ textureInfo.loadState = LoadState::WAITING_FOR_MASK;
}
- else if( maskLoadState == LOAD_FINISHED )
+ else if( maskLoadState == LoadState::LOAD_FINISHED )
{
// Send New Task to Thread
ApplyMask( textureInfo, textureInfo.maskTextureId );
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
{
// @todo If the load was unsuccessful, upload the broken image.
- textureInfo.loadState = LOAD_FAILED;
+ textureInfo.loadState = LoadState::LOAD_FAILED;
CheckForWaitingTexture( textureInfo );
NotifyObservers( textureInfo, false );
}
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] );
- if( maskTextureInfo.loadState == LOAD_FINISHED )
+ if( maskTextureInfo.loadState == LoadState::LOAD_FINISHED )
{
// Send New Task to Thread
ApplyMask( textureInfo, maskTextureInfo.textureId );
else
{
textureInfo.pixelBuffer.Reset();
- textureInfo.loadState = LOAD_FAILED;
+ textureInfo.loadState = LoadState::LOAD_FAILED;
NotifyObservers( textureInfo, false );
}
}
DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n",
textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously?"T":"F" );
- textureInfo.loadState = MASK_APPLYING;
- textureInfo.maskApplied = true;
+ 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 );
+ loadingHelperIt->ApplyMask( textureInfo.textureId, pixelBuffer, maskPixelBuffer, textureInfo.scaleFactor, textureInfo.cropToMask, premultiplyOnLoad );
}
}
// 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() );
// 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 )
DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "NotifyObservers() url:%s loadState:%s\n",
textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState ) );
- observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect,
- info->preMultiplied );
+ // It is possible for the observer to be deleted.
+ // Disconnect and remove the observer first.
observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
+ info->observerList.Erase( info->observerList.begin() );
+
+ if( info->storageType == StorageType::RETURN_PIXEL_BUFFER )
+ {
+ observer->LoadComplete( success, info->pixelBuffer, info->url, info->preMultiplied );
+ }
+ else
+ {
+ observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect,
+ info->preMultiplied );
+ }
+
// Get the textureInfo from the container again as it may have been invalidated.
int textureInfoIndex = GetCacheIndexFromId( textureId );
if( textureInfoIndex == INVALID_CACHE_INDEX)
break; // texture has been removed - can stop.
}
info = &mTextureInfoContainer[ textureInfoIndex ];
-
- // 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 );
- break;
- }
- }
}
mQueueLoadFlag = false;
ProcessQueuedTextures();
+
+ if( info->storageType == StorageType::RETURN_PIXEL_BUFFER && info->observerList.Count() == 0 )
+ {
+ Remove( info->textureId, nullptr );
+ }
}
TextureManager::TextureId TextureManager::GenerateUniqueTextureId()
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode,
const UseAtlas useAtlas,
- TextureId maskTextureId )
+ TextureId maskTextureId,
+ bool isAnimationImage,
+ uint32_t frameIndex )
{
std::string hashTarget( url );
const size_t urlLength = hashTarget.length();
}
}
+ if( isAnimationImage )
+ {
+ auto textureIdIndex = hashTarget.length();
+ hashTarget.resize( hashTarget.length() + sizeof( uint32_t ) );
+ char* hashTargetPtr = &( hashTarget[ textureIdIndex ] );
+
+ for( size_t byteIter = 0; byteIter < sizeof( uint32_t ); ++byteIter )
+ {
+ *hashTargetPtr++ = frameIndex & 0xff;
+ frameIndex >>= 8u;
+ }
+ }
+
if( maskTextureId != INVALID_TEXTURE_ID )
{
auto textureIdIndex = hashTarget.length();
const Dali::SamplingMode::Type samplingMode,
const bool useAtlas,
TextureId maskTextureId,
- TextureManager::MultiplyOnLoad preMultiplyOnLoad )
+ TextureManager::MultiplyOnLoad preMultiplyOnLoad,
+ bool isAnimatedImage,
+ uint32_t frameIndex )
{
// Default to an invalid ID, in case we do not find a match.
int cacheIndex = INVALID_CACHE_INDEX;
( size == textureInfo.desiredSize ) &&
( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
( fittingMode == textureInfo.fittingMode &&
- samplingMode == textureInfo.samplingMode ) ) )
+ samplingMode == textureInfo.samplingMode ) ) &&
+ ( isAnimatedImage == ( ( textureInfo.animatedImageLoading ) ? true : false ) ) &&
+ ( frameIndex == textureInfo.frameIndex ) )
{
// 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.
}
}
}
+
+ // Remove element from the LoadQueue
+ for( auto&& element : mLoadQueue )
+ {
+ if( element.mObserver == observer )
+ {
+ element.mObserver = nullptr;
+ }
+ }
}
{
}
-void TextureManager::AsyncLoadingHelper::Load(TextureId textureId,
- const VisualUrl& url,
- ImageDimensions desiredSize,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- bool orientationCorrection,
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+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));
+ 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 )
+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 = DevelAsyncImageLoader::ApplyMask( mLoader, pixelBuffer, maskPixelBuffer, contentScale, cropToMask );
+ mLoadingInfoContainer.push_back( AsyncLoadingInfo( textureId ) );
+ auto id = DevelAsyncImageLoader::ApplyMask( mLoader, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad );
mLoadingInfoContainer.back().loadId = id;
}
mBrokenImageUrl = brokenImageUrl;
}
+const std::string TextureManager::GetBrokenImageUrl()
+{
+ return mBrokenImageUrl;
+}
+
+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