#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
// EXTERNAL HEADERS
-#include <dali/devel-api/adaptor-framework/environment-variable.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
#include <dali/integration-api/adaptor-framework/adaptor.h>
constexpr auto TEXTURE_INDEX = 0u; ///< The Index for texture
constexpr auto MASK_TEXTURE_INDEX = 1u; ///< The Index for mask texture
-
-constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV = "DALI_TEXTURE_LOCAL_THREADS";
-constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS";
-constexpr auto LOAD_IMAGE_YUV_PLANES_ENV = "DALI_LOAD_IMAGE_YUV_PLANES";
-
-bool NeedToLoadYuvPlanes()
-{
- auto loadYuvPlanesString = Dali::EnvironmentVariable::GetEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV);
- bool loadYuvPlanes = loadYuvPlanesString ? std::atoi(loadYuvPlanesString) : false;
- return loadYuvPlanes;
-}
} // namespace
namespace Dali
{
}
-TextureManager::TextureManager()
+TextureManager::TextureManager(bool loadYuvPlanes)
: mTextureCacheManager(),
mAsyncLoader(std::unique_ptr<TextureAsyncLoadingHelper>(new TextureAsyncLoadingHelper(*this))),
mLifecycleObservers(),
mLoadQueue(),
mLoadingQueueTextureId(INVALID_TEXTURE_ID),
mRemoveQueue(),
- mLoadYuvPlanes(NeedToLoadYuvPlanes()),
+ mLoadYuvPlanes(loadYuvPlanes),
mRemoveProcessorRegistered(false)
{
// Initialize the AddOn
}
}
- textureId = RequestLoadInternal(url, alphaMaskId, contentScaleFactor, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false);
+ textureId = RequestLoadInternal(url, alphaMaskId, textureId, contentScaleFactor, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false);
TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
if(loadState == TextureManager::LoadState::UPLOADED)
}
else
{
- RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
+ RequestLoadInternal(url, INVALID_TEXTURE_ID, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
}
return pixelBuffer;
auto externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(id);
if(externalTextureInfo.textureSet)
{
- textureId = id;
-
if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
{
// Change preMultiplyOnLoad value so make caller determine to preMultiplyAlpha or not.
{
maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, StorageType::KEEP_TEXTURE, synchronousLoading);
alphaMaskId = maskInfo->mAlphaMaskId;
- textureId = RequestLoad(url, alphaMaskId, 1.0f, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, false, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad, synchronousLoading);
+
+ // Create new textureId. this textureId is not same as location
+ textureId = RequestLoad(url, alphaMaskId, textureId, 1.0f, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, false, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad, synchronousLoading);
TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
if(loadState == TextureManager::LoadState::UPLOADED)
}
else
{
+ // TextureId is same as location
+ textureId = id;
+
textureSet = TextureSet::New();
textureSet.SetTexture(TEXTURE_INDEX, externalTextureInfo.textureSet.GetTexture(TEXTURE_INDEX));
}
textureId = RequestLoad(
url,
alphaMaskId,
+ textureId,
contentScaleFactor,
desiredSize,
fittingMode,
TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
const 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, synchronousLoading);
+ return RequestLoadInternal(url, INVALID_TEXTURE_ID, 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(
const VisualUrl& url,
const TextureManager::TextureId& maskTextureId,
+ const TextureManager::TextureId& previousTextureId,
const float& contentScale,
const Dali::ImageDimensions& desiredSize,
const Dali::FittingMode::Type& fittingMode,
TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
const bool& synchronousLoading)
{
- return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
+ return RequestLoadInternal(url, maskTextureId, previousTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
}
TextureManager::TextureId TextureManager::RequestMaskLoad(
{
// Use the normal load procedure to get the alpha mask.
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, UseAtlas::NO_ATLAS, false, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
+ return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, UseAtlas::NO_ATLAS, false, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
}
TextureManager::TextureId TextureManager::RequestLoadInternal(
const VisualUrl& url,
const TextureManager::TextureId& maskTextureId,
+ const TextureManager::TextureId& previousTextureId,
const float& contentScale,
const Dali::ImageDimensions& desiredSize,
const Dali::FittingMode::Type& fittingMode,
// Check if the requested Texture exists in the cache.
if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(TextureManager::ReloadPolicy::CACHED == reloadPolicy)
+ if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || TextureManager::INVALID_TEXTURE_ID == previousTextureId)
{
- // Mark this texture being used by another client resource. Forced reload would replace the current texture
+ // Mark this texture being used by another client resource, or Reload forced without request load before.
+ // Forced reload which have current texture before, would replace the current texture.
// without the need for incrementing the reference count.
++(mTextureCacheManager[cacheIndex].referenceCount);
}
// Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info.
preMultiplyOnLoad = mTextureCacheManager[cacheIndex].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d, maskTextureId=%d, frameindex=%d, premultiplied=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, frameIndex, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d, maskTextureId=%d, prevTextureId=%d, frameindex=%d, premultiplied=%d, refCount=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, previousTextureId, frameIndex, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0, static_cast<int>(mTextureCacheManager[cacheIndex].referenceCount));
}
if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
{
if(textureInfo.loadState != LoadState::UPLOADED)
{
+ textureInfo.preMultiplied = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
textureInfo.loadState = TextureManager::LoadState::WAITING_FOR_MASK;
}
}
TextureManager::LoadState::CANCELLED != textureInfo.loadState &&
TextureManager::LoadState::MASK_CANCELLED != textureInfo.loadState)
{
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d, maskTextureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d, maskTextureId=%d, prevTextureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, previousTextureId);
textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
}
case TextureManager::LoadState::MASK_APPLYING:
case TextureManager::LoadState::MASK_APPLIED:
{
- ObserveTexture(textureInfo, observer);
+ // Do not observe even we reload forced when texture is already loading state.
+ if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || TextureManager::INVALID_TEXTURE_ID == previousTextureId)
+ {
+ ObserveTexture(textureInfo, observer);
+ }
break;
}
case TextureManager::LoadState::UPLOADED:
// Queue to remove.
if(textureId != INVALID_TEXTURE_ID)
{
- if(observer)
+ TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
+ if(textureCacheIndex != INVALID_CACHE_INDEX)
{
- // Remove observer from cached texture info
- TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
- if(textureCacheIndex != INVALID_CACHE_INDEX)
+ if(observer)
{
+ // Remove observer from cached texture info
TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]);
RemoveTextureObserver(textureInfo, observer);
}
- }
- mRemoveQueue.PushBack(textureId);
- if(!mRemoveProcessorRegistered && Adaptor::IsAvailable())
- {
- mRemoveProcessorRegistered = true;
- Adaptor::Get().RegisterProcessor(*this, true);
+ mRemoveQueue.PushBack(textureId);
+
+ if(!mRemoveProcessorRegistered && Adaptor::IsAvailable())
+ {
+ mRemoveProcessorRegistered = true;
+ Adaptor::Get().RegisterProcessor(*this, true);
+ }
}
}
}
}
}
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove( textureId=%d ) cacheIndex:%d removal maskTextureId=%d, loadingQueueTextureId=%d, loadState=%s\n", textureId, textureCacheIndex.GetIndex(), maskTextureId, mLoadingQueueTextureId, GET_LOAD_STATE_STRING(textureInfo.loadState));
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove( textureId=%d ) cacheIndex:%d removal maskTextureId=%d, loadState=%s\n", textureId, textureCacheIndex.GetIndex(), maskTextureId, GET_LOAD_STATE_STRING(textureInfo.loadState));
// Remove textureId in CacheManager. Now, textureInfo is invalidate.
mTextureCacheManager.RemoveCache(textureInfo);
if(maskCacheIndex != INVALID_CACHE_INDEX)
{
TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove mask texture( maskTextureId=%d ) cacheIndex:%d, loadState=%s\n", maskTextureId, maskCacheIndex.GetIndex(), GET_LOAD_STATE_STRING(maskTextureInfo.loadState));
+
mTextureCacheManager.RemoveCache(maskTextureInfo);
}
}
{
// The Texture has already loaded. The other observers have already been notified.
// We need to send a "late" loaded notification for this observer.
- EmitLoadComplete(observer, textureInfo, true);
+ if(observer)
+ {
+ EmitLoadComplete(observer, textureInfo, true);
+ }
}
break;
}
if(observer)
{
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Connect DestructionSignal to observer:%p\n", observer);
observer->DestructionSignal().Connect(this, &TextureManager::ObserverDestroyed);
}
}
if(cacheIndex != INVALID_CACHE_INDEX)
{
TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::ProcessLoadQueue() textureId=%d, observer=%p, cacheIndex=@%d, loadState:%s\n", element.mTextureId, element.mObserver, cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState));
+
if((textureInfo.loadState == LoadState::UPLOADED) || (textureInfo.loadState == LoadState::LOAD_FINISHED && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER))
{
if(element.mObserver)
if(observer)
{
textureInfo.observerList.PushBack(observer);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Connect DestructionSignal to observer:%p\n", observer);
observer->DestructionSignal().Connect(this, &TextureManager::ObserverDestroyed);
}
}
}
else
{
- RequestRemove(textureInfo.textureId, nullptr);
+ Remove(textureInfo.textureId);
}
}
}
// invalidating the reference to the textureInfo struct.
// Texture load requests for the same URL are deferred until the end of this
// method.
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() textureId:%d url:%s loadState:%s\n", textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState));
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() observer:%p textureId:%d url:%s loadState:%s\n", observer, textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState));
// It is possible for the observer to be deleted.
// Disconnect and remove the observer first.
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer);
observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
info->observerList.Erase(info->observerList.End() - 1u);
void TextureManager::ObserverDestroyed(TextureUploadObserver* observer)
{
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::ObserverDestroyed() observer:%p\n", observer);
+
const std::size_t size = mTextureCacheManager.size();
for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
{
if(iter != iterEnd)
{
// Disconnect and remove the observer.
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer);
observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
textureInfo.observerList.Erase(iter);
}