TestObserver()
: mCompleteType( CompleteType::NOT_COMPLETED ),
mLoaded(false),
- mObserverCalled(false)
+ mObserverCalled(false),
+ mTextureSet()
{
}
mCompleteType = CompleteType::UPLOAD_COMPLETE;
mLoaded = loadSuccess;
mObserverCalled = true;
+ mTextureSet = textureSet;
}
virtual void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override
CompleteType mCompleteType;
bool mLoaded;
bool mObserverCalled;
+ TextureSet mTextureSet;
};
END_TEST;
}
+
+int UtcTextureManagerSynchronousLoadingFail(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcTextureManagerSynchronousLoadingFail" );
+
+ TextureManager textureManager; // Create new texture manager
+
+ std::string maskname("");
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ maskInfo.reset(new TextureManager::MaskingData());
+ maskInfo->mAlphaMaskUrl = maskname;
+ maskInfo->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
+ maskInfo->mCropToMask = true;
+ maskInfo->mContentScaleFactor = 1.0f;
+
+ std::string filename("dummy");
+ auto textureId( TextureManager::INVALID_TEXTURE_ID );
+ Vector4 atlasRect( 0.f, 0.f, 0.f, 0.f );
+ Dali::ImageDimensions atlasRectSize( 0,0 );
+ bool atlasingStatus(false);
+ bool loadingStatus(false);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ ImageAtlasManagerPtr atlasManager = nullptr;
+ Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+ // load image synchronously.
+ TestObserver observer;
+ TextureSet textureSet = textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ true, // synchronous loading.
+ textureId,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ loadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &observer,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply
+ );
+
+ DALI_TEST_EQUALS(loadingStatus, false, TEST_LOCATION);
+ DALI_TEST_CHECK(!textureSet); // texture loading fail.
+ DALI_TEST_CHECK(textureId == TextureManager::INVALID_TEXTURE_ID); // invalid texture id is returned.
+
+ END_TEST;
+}
+
+int UtcTextureManagerCachingSynchronousLoading(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcTextureManagerCachingSynchronousLoading" );
+
+ TextureManager textureManager; // Create new texture manager
+
+ std::string filename( TEST_IMAGE_FILE_NAME );
+
+ std::string maskname("");
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ maskInfo.reset(new TextureManager::MaskingData());
+ maskInfo->mAlphaMaskUrl = maskname;
+ maskInfo->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
+ maskInfo->mCropToMask = true;
+ maskInfo->mContentScaleFactor = 1.0f;
+
+ Vector4 atlasRect( 0.f, 0.f, 0.f, 0.f );
+ Dali::ImageDimensions atlasRectSize( 0,0 );
+ bool atlasingStatus(false);
+ bool loadingStatus(false);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ ImageAtlasManagerPtr atlasManager = nullptr;
+ Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+ // load image synchronously.
+ TestObserver observer;
+ auto textureId( TextureManager::INVALID_TEXTURE_ID );
+ TextureSet textureSet = textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ true, // synchronous loading.
+ textureId,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ loadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &observer,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply
+ );
+
+ DALI_TEST_EQUALS(loadingStatus, false, TEST_LOCATION);
+ DALI_TEST_CHECK(textureSet); // texture is loaded.
+
+ // observer isn't called in synchronous loading.
+ DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION);
+
+
+ // load same image asynchronously.
+ TestObserver asyncObserver;
+ auto asyncTextureId( TextureManager::INVALID_TEXTURE_ID );
+ loadingStatus = false;
+ TextureSet asyncTextureSet = textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ false, // asynchronous loading.
+ asyncTextureId,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ loadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &asyncObserver,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply
+ );
+
+ DALI_TEST_EQUALS(asyncTextureId, textureId, TEST_LOCATION); // texture is loaded.
+ DALI_TEST_EQUALS(loadingStatus, false, TEST_LOCATION);
+ DALI_TEST_CHECK(asyncTextureSet); // Cached texture.
+
+ // observer is directly called because textureSet is retrieved by cache.
+ DALI_TEST_EQUALS(asyncObserver.mLoaded, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(asyncObserver.mObserverCalled, true, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcTextureManagerAsyncSyncAsync(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcTextureManagerAsyncSyncAsync" );
+
+ TextureManager textureManager; // Create new texture manager
+
+ std::string filename( TEST_IMAGE_FILE_NAME );
+
+ std::string maskname("");
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ maskInfo.reset(new TextureManager::MaskingData());
+ maskInfo->mAlphaMaskUrl = maskname;
+ maskInfo->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
+ maskInfo->mCropToMask = true;
+ maskInfo->mContentScaleFactor = 1.0f;
+
+ Vector4 atlasRect( 0.f, 0.f, 0.f, 0.f );
+ Dali::ImageDimensions atlasRectSize( 0,0 );
+ bool atlasingStatus(false);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ ImageAtlasManagerPtr atlasManager = nullptr;
+ Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+ // load image asynchronously.
+ TestObserver asyncObserver1;
+ auto asyncTextureId1( TextureManager::INVALID_TEXTURE_ID );
+ bool asyncLoadingStatus1 = false;
+ TextureSet asyncTextureSet1 = textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ false, // asynchronous loading.
+ asyncTextureId1,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ asyncLoadingStatus1,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &asyncObserver1,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply
+ );
+
+ DALI_TEST_EQUALS(asyncLoadingStatus1, true, TEST_LOCATION); // texture is loading now.
+ DALI_TEST_CHECK(!asyncTextureSet1); // texture is not loaded yet.
+
+ // observer is still not called.
+ DALI_TEST_EQUALS(asyncObserver1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(asyncObserver1.mObserverCalled, false, TEST_LOCATION);
+
+
+ // load same image synchronously just after asynchronous loading.
+ TestObserver syncObserver;
+ auto textureId( TextureManager::INVALID_TEXTURE_ID );
+ bool syncLoadingStatus = false;
+ TextureSet syncTextureSet = textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ true, // synchronous loading.
+ textureId,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ syncLoadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &syncObserver,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply
+ );
+
+ DALI_TEST_EQUALS(asyncTextureId1, textureId, TEST_LOCATION); // texture is loaded.
+ DALI_TEST_EQUALS(syncLoadingStatus, false, TEST_LOCATION); // texture is loaded.
+ DALI_TEST_CHECK(syncTextureSet); // texture is loaded.
+
+ // syncObserver isn't called in synchronous loading.
+ DALI_TEST_EQUALS(syncObserver.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(syncObserver.mObserverCalled, false, TEST_LOCATION);
+
+ // asyncObserver1 is still not called too.
+ DALI_TEST_EQUALS(asyncObserver1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(asyncObserver1.mObserverCalled, false, TEST_LOCATION);
+
+
+
+ // load image asynchronously.
+ TestObserver asyncObserver2;
+ auto asyncTextureId2( TextureManager::INVALID_TEXTURE_ID );
+ bool asyncLoadingStatus2 = false;
+ TextureSet asyncTextureSet2 = textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ false, // asynchronous loading.
+ asyncTextureId2,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ asyncLoadingStatus2,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &asyncObserver2,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply
+ );
+
+ DALI_TEST_EQUALS(asyncLoadingStatus2, false, TEST_LOCATION); // texture is loaded by previous sync request
+ DALI_TEST_CHECK(asyncTextureSet2); // texture is loaded
+ DALI_TEST_CHECK(asyncTextureSet2 == syncTextureSet); // check loaded two texture is same.
+
+ // observer is called synchronously because the texture is cached.
+ DALI_TEST_EQUALS(asyncObserver2.mLoaded, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(asyncObserver2.mObserverCalled, true, TEST_LOCATION);
+
+ asyncObserver2.mLoaded = false;
+ asyncObserver2.mObserverCalled = false;
+
+ application.SendNotification();
+ application.Render();
+
+ // Requested asynchronous loading at first is finished now and async observer is called now.
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS(asyncObserver1.mLoaded, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(asyncObserver1.mObserverCalled, true, TEST_LOCATION);
+ DALI_TEST_CHECK(asyncObserver1.mTextureSet == asyncTextureSet2); // check loaded two texture is same.
+
+ // asyncObserver2 was already called so it isn't called here.
+ DALI_TEST_EQUALS(asyncObserver2.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(asyncObserver2.mObserverCalled, false, TEST_LOCATION);
+
+ END_TEST;
+}
}
TextureManager::TextureManager()
-: mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); }),
- mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); }),
+: mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]()
+ { return AsyncLoadingHelper(*this); }),
+ mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]()
+ { return AsyncLoadingHelper(*this); }),
mExternalTextures(),
mLifecycleObservers(),
mLoadQueue(),
else
{
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- textureId = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex);
+ textureId = RequestLoadInternal(animatedImageLoading.GetUrl(), INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS, false, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiply, animatedImageLoading, frameIndex, false);
TextureManager::LoadState loadState = GetTextureStateInternal(textureId);
if(loadState == TextureManager::LoadState::UPLOADED)
{
}
else
{
- RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u);
+ RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
}
return pixelBuffer;
}
}
}
- else if(synchronousLoading)
+ else
{
- PixelData data;
- if(url.IsValid())
+ // For Atlas
+ if(synchronousLoading && atlasingStatus && imageAtlasManager->CheckAtlasAvailable(url, desiredSize))
{
- Devel::PixelBuffer pixelBuffer;
- if(url.IsBufferResource())
- {
- const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl());
- if(encodedImageBuffer)
- {
- pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
- }
- }
- else
- {
- pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
- }
+ Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);
+
if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
{
- Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
+ Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
if(maskPixelBuffer)
{
pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
}
}
+
+ PixelData data;
if(pixelBuffer)
{
PreMultiply(pixelBuffer, preMultiplyOnLoad);
data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+
+ if(data)
+ {
+ textureSet = imageAtlasManager->Add(textureRect, data);
+ if(textureSet)
+ {
+ textureRectSize.SetWidth(data.GetWidth());
+ textureRectSize.SetHeight(data.GetHeight());
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n");
+ }
}
- }
- if(!data)
- {
- DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous loading is failed\n");
- }
- else
- {
- if(atlasingStatus) // attempt atlasing
- {
- textureSet = imageAtlasManager->Add(textureRect, data);
- }
- if(!textureSet) // big image, no atlasing or atlasing failed
- {
- atlasingStatus = false;
- Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), data.GetWidth(), data.GetHeight());
- texture.Upload(data);
- textureSet = TextureSet::New();
- textureSet.SetTexture(0u, texture);
- }
- else
+ if(!textureSet)
{
- textureRectSize.SetWidth(data.GetWidth());
- textureRectSize.SetHeight(data.GetHeight());
+ atlasingStatus = false;
}
}
- }
- else
- {
- loadingStatus = true;
- if(atlasingStatus)
- {
- textureSet = imageAtlasManager->Add(textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver);
- }
- if(!textureSet) // big image, no atlasing or atlasing failed
+
+ if(!textureSet)
{
- atlasingStatus = false;
- if(!maskInfo || !maskInfo->mAlphaMaskUrl.IsValid())
+ loadingStatus = true;
+ if(atlasingStatus)
{
- textureId = RequestLoad(url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad);
+ textureSet = imageAtlasManager->Add(textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver);
}
- else
+ if(!textureSet) // big image, no atlasing or atlasing failed
{
- maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl);
- textureId = RequestLoad(url,
- maskInfo->mAlphaMaskId,
- maskInfo->mContentScaleFactor,
- desiredSize,
- fittingMode,
- samplingMode,
- TextureManager::NO_ATLAS,
- maskInfo->mCropToMask,
- textureObserver,
- orientationCorrection,
- reloadPolicy,
- preMultiplyOnLoad);
- }
+ atlasingStatus = false;
+ if(!maskInfo || !maskInfo->mAlphaMaskUrl.IsValid())
+ {
+ textureId = RequestLoad(url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad, synchronousLoading);
+ }
+ else
+ {
+ maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, synchronousLoading);
+ textureId = RequestLoad(url,
+ maskInfo->mAlphaMaskId,
+ maskInfo->mContentScaleFactor,
+ desiredSize,
+ fittingMode,
+ samplingMode,
+ TextureManager::NO_ATLAS,
+ maskInfo->mCropToMask,
+ textureObserver,
+ orientationCorrection,
+ reloadPolicy,
+ preMultiplyOnLoad,
+ synchronousLoading);
+ }
+
+ TextureManager::LoadState loadState = GetTextureStateInternal(textureId);
+ if(loadState == TextureManager::LoadState::UPLOADED)
+ {
+ // UploadComplete has already been called - keep the same texture set
+ textureSet = GetTextureSet(textureId);
+ }
- TextureManager::LoadState loadState = GetTextureStateInternal(textureId);
- if(loadState == TextureManager::LoadState::UPLOADED)
+ // If we are loading the texture, or waiting for the ready signal handler to complete, inform
+ // caller that they need to wait.
+ loadingStatus = (loadState == TextureManager::LoadState::LOADING ||
+ loadState == TextureManager::LoadState::WAITING_FOR_MASK ||
+ loadState == TextureManager::LoadState::MASK_APPLYING ||
+ loadState == TextureManager::LoadState::MASK_APPLIED ||
+ loadState == TextureManager::LoadState::NOT_STARTED ||
+ mQueueLoadFlag);
+ }
+ else
{
- // UploadComplete has already been called - keep the same texture set
- textureSet = GetTextureSet(textureId);
+ textureRectSize = desiredSize;
}
-
- // If we are loading the texture, or waiting for the ready signal handler to complete, inform
- // caller that they need to wait.
- loadingStatus = (loadState == TextureManager::LoadState::LOADING ||
- loadState == TextureManager::LoadState::WAITING_FOR_MASK ||
- loadState == TextureManager::LoadState::MASK_APPLYING ||
- loadState == TextureManager::LoadState::MASK_APPLIED ||
- loadState == TextureManager::LoadState::NOT_STARTED ||
- mQueueLoadFlag);
- }
- else
- {
- textureRectSize = desiredSize;
}
}
textureSet.SetSampler(0u, sampler);
}
+ if(synchronousLoading)
+ {
+ loadingStatus = false;
+ }
+
return textureSet;
}
TextureUploadObserver* observer,
bool orientationCorrection,
TextureManager::ReloadPolicy reloadPolicy,
- TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
+ TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
+ bool synchronousLoading)
{
- return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u);
+ return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
}
TextureManager::TextureId TextureManager::RequestLoad(
TextureUploadObserver* observer,
bool orientationCorrection,
TextureManager::ReloadPolicy reloadPolicy,
- TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
+ TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
+ bool synchronousLoading)
{
- return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u);
+ return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
}
-TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl)
+TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl, bool synchronousLoading)
{
// Use the normal load procedure to get the alpha mask.
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u);
+ return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
}
TextureManager::TextureId TextureManager::RequestLoadInternal(
TextureManager::ReloadPolicy reloadPolicy,
TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
Dali::AnimatedImageLoading animatedImageLoading,
- uint32_t frameIndex)
+ uint32_t frameIndex,
+ bool synchronousLoading)
{
// First check if the requested Texture is cached.
bool isAnimatedImage = (animatedImageLoading) ? true : false;
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);
}
- // Check if the requested Texture exist in Encoded Buffer
- // This mean, that buffer is not cached, and need to be decoded.
- if(textureId == INVALID_TEXTURE_ID && VisualUrl::BUFFER == url.GetProtocolType())
+ if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
{
- std::string location = url.GetLocation();
- if(location.size() > 0u)
+ if(VisualUrl::BUFFER == url.GetProtocolType())
{
- TextureId targetId = std::stoi(location);
- const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(targetId);
- if(encodedImageBuffer)
+ std::string location = url.GetLocation();
+ if(location.size() > 0u)
{
- textureId = targetId;
-
- // Increase EncodedImageBuffer reference during it contains mTextureInfoContainer.
- UseExternalResource(url.GetUrl());
-
- // Insert this buffer at mTextureInfoContainer.
- // This buffer will decode at ImageLoaderThread.
- bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
- mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
- cacheIndex = mTextureInfoContainer.size() - 1u;
+ TextureId targetId = std::stoi(location);
+ const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(targetId);
+ if(encodedImageBuffer)
+ {
+ textureId = targetId;
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New buffered texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+ // Increase EncodedImageBuffer reference during it contains mTextureInfoContainer.
+ UseExternalResource(url.GetUrl());
+ }
}
}
- }
- if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
- {
- // We need a new Texture.
- textureId = GenerateUniqueTextureId();
+ if(textureId == INVALID_TEXTURE_ID)
+ {
+ textureId = GenerateUniqueTextureId();
+ }
+
bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
cacheIndex = mTextureInfoContainer.size() - 1u;
textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
}
- // Check if we should add the observer.
- // Only do this if we have not loaded yet and it will not have loaded by the end of this method.
- switch(textureInfo.loadState)
+ if(!synchronousLoading)
{
- case TextureManager::LoadState::LOAD_FAILED: // Failed notifies observer which then stops observing.
- case TextureManager::LoadState::NOT_STARTED:
- {
- LoadOrQueueTexture(textureInfo, observer); // If called inside NotifyObservers, queues until afterwards
- break;
- }
- case TextureManager::LoadState::LOADING:
- case TextureManager::LoadState::WAITING_FOR_MASK:
- case TextureManager::LoadState::MASK_APPLYING:
- case TextureManager::LoadState::MASK_APPLIED:
+ // Check if we should add the observer.
+ // Only do this if we have not loaded yet and it will not have loaded by the end of this method.
+ switch(textureInfo.loadState)
{
- ObserveTexture(textureInfo, observer);
- break;
- }
- case TextureManager::LoadState::UPLOADED:
- {
- if(observer)
+ case TextureManager::LoadState::LOAD_FAILED: // Failed notifies observer which then stops observing.
+ case TextureManager::LoadState::NOT_STARTED:
+ {
+ LoadOrQueueTexture(textureInfo, observer); // If called inside NotifyObservers, queues until afterwards
+ break;
+ }
+ case TextureManager::LoadState::LOADING:
+ case TextureManager::LoadState::WAITING_FOR_MASK:
+ case TextureManager::LoadState::MASK_APPLYING:
+ case TextureManager::LoadState::MASK_APPLIED:
{
- LoadOrQueueTexture(textureInfo, observer);
+ ObserveTexture(textureInfo, observer);
+ break;
+ }
+ case TextureManager::LoadState::UPLOADED:
+ {
+ if(observer)
+ {
+ LoadOrQueueTexture(textureInfo, observer);
+ }
+ break;
+ }
+ case TextureManager::LoadState::CANCELLED:
+ {
+ // A cancelled texture hasn't finished loading yet. Treat as a loading texture
+ // (it's ref count has already been incremented, above)
+ textureInfo.loadState = TextureManager::LoadState::LOADING;
+ ObserveTexture(textureInfo, observer);
+ break;
+ }
+ case TextureManager::LoadState::LOAD_FINISHED:
+ {
+ // Loading has already completed.
+ if(observer && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER)
+ {
+ LoadOrQueueTexture(textureInfo, observer);
+ }
+ break;
}
- break;
}
- case TextureManager::LoadState::CANCELLED:
+ }
+ else
+ {
+ // If the image is already finished to load, use cached texture.
+ // We don't need to consider Observer becaouse this is synchronous loading.
+ if(textureInfo.loadState == TextureManager::LoadState::UPLOADED ||
+ textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED)
{
- // A cancelled texture hasn't finished loading yet. Treat as a loading texture
- // (it's ref count has already been incremented, above)
- textureInfo.loadState = TextureManager::LoadState::LOADING;
- ObserveTexture(textureInfo, observer);
- break;
+ return textureId;
}
- case TextureManager::LoadState::LOAD_FINISHED:
+ else
{
- // Loading has already completed.
- if(observer && textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER)
+ Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);;
+
+ if(!pixelBuffer)
{
- LoadOrQueueTexture(textureInfo, observer);
+ // If pixelBuffer loading is failed in synchronously, call Remove() method.
+ Remove(textureId, nullptr);
+ return INVALID_TEXTURE_ID;
+ }
+
+ if(storageType == StorageType::KEEP_PIXEL_BUFFER) // For the mask image loading.
+ {
+ textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data
+ textureInfo.loadState = LoadState::LOAD_FINISHED;
+ }
+ else // For the image loading.
+ {
+ if(maskTextureId != INVALID_TEXTURE_ID)
+ {
+ int maskCacheIndex = GetCacheIndexFromId(maskTextureId);
+ if(maskCacheIndex != INVALID_CACHE_INDEX)
+ {
+ Devel::PixelBuffer maskPixelBuffer = mTextureInfoContainer[maskCacheIndex].pixelBuffer;
+ if(maskPixelBuffer)
+ {
+ pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask);
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR("Mask image is not stored in cache.\n");
+ }
+ }
+ PreMultiply(pixelBuffer, preMultiplyOnLoad);
+
+ // Upload texture
+ UploadTexture(pixelBuffer, textureInfo);
}
- break;
}
}
return loadState;
}
+Devel::PixelBuffer TextureManager::LoadImageSynchronously(const VisualUrl& url,
+ const ImageDimensions desiredSize,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ bool orientationCorrection)
+{
+ Devel::PixelBuffer pixelBuffer;
+ if(url.IsBufferResource())
+ {
+ const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl());
+ if(encodedImageBuffer)
+ {
+ pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
+ }
+ else
+ {
+ pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
+ return pixelBuffer;
+}
+
TextureSet TextureManager::GetTextureSet(TextureId textureId)
{
TextureSet textureSet; // empty handle
{
// If same buffer added, increase reference count and return.
elem.referenceCount++;
- return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));;
+ return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));
}
}
TextureManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer);
std::string location = VisualUrl::GetLocation(url);
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
+ TextureId id = std::stoi(location);
const auto end = mEncodedBufferTextures.end();
for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter)
{
// If there is a mask texture ID associated with this texture, then apply the mask
// if it's already loaded. If it hasn't, and the mask is still loading,
// wait for the mask to finish loading.
- if(textureInfo.maskTextureId != INVALID_TEXTURE_ID)
+ // note, If the texture is already uploaded synchronously during loading,
+ // we don't need to apply mask.
+ if(textureInfo.loadState != LoadState::UPLOADED &&
+ textureInfo.maskTextureId != INVALID_TEXTURE_ID)
{
if(textureInfo.loadState == LoadState::MASK_APPLYING)
{
void TextureManager::UploadTexture(Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo)
{
- if(textureInfo.useAtlas != USE_ATLAS)
+ if(textureInfo.loadState != LoadState::UPLOADED && textureInfo.useAtlas != USE_ATLAS)
{
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId);
*/
enum class StorageType : uint8_t
{
- KEEP_PIXEL_BUFFER,
- RETURN_PIXEL_BUFFER,
- UPLOAD_TO_TEXTURE
+ KEEP_PIXEL_BUFFER, ///< Keep loaded pixel buffer inside of texture manager without making texture. This could be used for inside pixel process like mask image.
+ RETURN_PIXEL_BUFFER, ///< Return loaded pixel buffer without making texture.
+ /// Because a pixel buffer cannot be used multiple texture, this pixel buffer only cached during loading, and is removed after loading is finished.
+ UPLOAD_TO_TEXTURE ///< Loaded image will be uploaded to texture and the texture will be returned.
};
/**
*
* @return The texture set containing the frame of animated image, or empty if still loading.
*/
-
TextureSet LoadAnimatedImageTexture(Dali::AnimatedImageLoading animatedImageLoading,
uint32_t frameIndex,
Dali::SamplingMode::Type samplingMode,
*
* @return The pixel buffer containing the image, or empty if still loading.
*/
-
Devel::PixelBuffer LoadPixelBuffer(const VisualUrl& url,
Dali::ImageDimensions desiredSize,
Dali::FittingMode::Type fittingMode,
*
* @return The texture set containing the image, or empty if still loading.
*/
-
TextureSet LoadTexture(const VisualUrl& url,
Dali::ImageDimensions desiredSize,
Dali::FittingMode::Type fittingMode,
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in] reloadPolicy Forces a reload of the texture even if already cached
* @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the image has no alpha channel
+ * @param[in] synchronousLoading true if the frame should be loaded synchronously
* @return A TextureId to use as a handle to reference this Texture
*/
TextureId RequestLoad(const VisualUrl& url,
TextureUploadObserver* observer,
bool orientationCorrection,
TextureManager::ReloadPolicy reloadPolicy,
- MultiplyOnLoad& preMultiplyOnLoad);
+ MultiplyOnLoad& preMultiplyOnLoad,
+ bool synchronousLoading = false);
/**
* @brief Requests an image load of the given URL, when the texture has
* @param[in] reloadPolicy Forces a reload of the texture even if already cached
* @param[in] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
* image has no alpha channel
+ * @param[in] synchronousLoading true if the frame should be loaded synchronously
* @return A TextureId to use as a handle to reference this Texture
*/
TextureId RequestLoad(const VisualUrl& url,
TextureUploadObserver* observer,
bool orientationCorrection,
TextureManager::ReloadPolicy reloadPolicy,
- MultiplyOnLoad& preMultiplyOnLoad);
+ MultiplyOnLoad& preMultiplyOnLoad,
+ bool synchronousLoading = false);
/**
* Requests a masking image to be loaded. This mask is not uploaded to GL,
* instead, it is stored in CPU memory, and can be used for CPU blending.
*/
- TextureId RequestMaskLoad(const VisualUrl& maskUrl);
+ TextureId RequestMaskLoad(const VisualUrl& maskUrl,
+ bool synchronousLoading = false);
/**
* @brief Remove a Texture from the TextureManager.
* there is no alpha
* @param[in] animatedImageLoading The AnimatedImageLoading to load animated image
* @param[in] frameIndex The frame index of a frame to be loaded frame
+ * @param[in] synchronousLoading true if the frame should be loaded synchronously
* @return A TextureId to use as a handle to reference this Texture
*/
TextureId RequestLoadInternal(
TextureManager::ReloadPolicy reloadPolicy,
MultiplyOnLoad& preMultiplyOnLoad,
Dali::AnimatedImageLoading animatedImageLoading,
- uint32_t frameIndex);
+ uint32_t frameIndex,
+ bool synchronousLoading);
/**
* @brief Get the current state of a texture
*/
LoadState GetTextureStateInternal(TextureId textureId);
+ /**
+ * @brief Load a new image synchronously.
+ * @param[in] url The URL of the image to load
+ * @param[in] desiredSize The size the image is likely to appear at.
+ * This can be set to 0,0 for automatic
+ * @param[in] fittingMode The FittingMode to use
+ * @param[in] samplingMode The SamplingMode to use
+ * @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image,
+ * e.g., from portrait to landscape
+ * @return PixelBuffer of loaded image.
+ */
+ Devel::PixelBuffer LoadImageSynchronously(const VisualUrl& url,
+ const ImageDimensions desiredSize,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ bool orientationCorrection);
+
typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
// Structs: