namespace
{
const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
-
-}
+const char* TEST_MASK_FILE_NAME = TEST_RESOURCE_DIR "/mask.png";
class TestObserver : public Dali::Toolkit::TextureUploadObserver
{
TextureSet mTextureSet;
};
+class TestObserverRemoveAndGenerateUrl : public TestObserver
+{
+public:
+ TestObserverRemoveAndGenerateUrl(TextureManager* textureManagerPtr)
+ : TestObserver(),
+ mTextureManagerPtr(textureManagerPtr)
+ {
+ }
+
+ virtual void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override
+ {
+ if(textureInformation.returnType == TextureUploadObserver::ReturnType::TEXTURE)
+ {
+ mCompleteType = CompleteType::UPLOAD_COMPLETE;
+ }
+ else
+ {
+ mCompleteType = CompleteType::LOAD_COMPLETE;
+ }
+ mLoaded = loadSuccess;
+ mObserverCalled = true;
+ mTextureSet = textureInformation.textureSet;
+
+ // Remove during LoadComplete
+ mTextureManagerPtr->Remove(textureInformation.textureId, nullptr);
+
+ // ...And generate string which using texture id.
+ mGeneratedExternalUrl = mTextureManagerPtr->AddExternalTexture(mTextureSet);
+ }
+
+public:
+ std::string mGeneratedExternalUrl;
+
+protected:
+ TextureManager* mTextureManagerPtr; // Keep the pointer of texture manager.
+};
+
+} // namespace
+
int UtcTextureManagerRequestLoad(void)
{
ToolkitTestApplication application;
EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
- std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
- std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1);
+ std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
+ std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
std::string url3 = VisualUrl::CreateBufferUrl(""); ///< Impossible Buffer URL. for coverage
// Check if same EncodedImageBuffer get same url
DALI_TEST_CHECK(url1 == url2);
// Reduce reference count
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
// Check whethere url1 still valid
DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
- url2 = textureManager.AddExternalEncodedImageBuffer(buffer2);
+ url2 = textureManager.AddEncodedImageBuffer(buffer2);
// Check if difference EncodedImageBuffer get difference url
DALI_TEST_CHECK(url1 != url2);
DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION);
- textureManager.RemoveExternalEncodedImageBuffer(url1);
- textureManager.RemoveExternalEncodedImageBuffer(url2);
+ textureManager.RemoveEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url2);
// Now url1 and url2 is invalid type. mLoaded will return false
EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
- std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
- std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1);
+ std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
+ std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
// Check if same EncodedImageBuffer get same url
DALI_TEST_CHECK(url1 == url2);
// Reduce reference count
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
// Check whethere url1 still valid
DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
// Reduce reference count
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
// Check whethere url1 is not valid anymore
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
textureManager.UseExternalResource(url1);
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
- url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
- // Check if difference EncodedImageBuffer get difference url
- // Previous EncodedImageBuffer was deleted, so we get new url even same buffer.
- DALI_TEST_CHECK(url1 != url2);
+ url1 = textureManager.AddEncodedImageBuffer(buffer1);
- url2 = textureManager.AddExternalEncodedImageBuffer(buffer2);
+ url2 = textureManager.AddEncodedImageBuffer(buffer2);
// Check if difference EncodedImageBuffer get difference url
DALI_TEST_CHECK(url1 != url2);
DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION);
// Decrease each url's reference count.
- textureManager.RemoveExternalEncodedImageBuffer(url1);
- textureManager.RemoveExternalEncodedImageBuffer(url2);
+ textureManager.RemoveEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url2);
// url1 buffer is still have 1 reference count because it is cached.
// But url2 not valid because it is not cached.
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url2));
// Check url1 buffer have 1 reference count because it is cached.
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
END_TEST;
END_TEST;
}
+
+int UtcTextureManagerQueueRemoveDuringObserve(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcTextureManagerQueueRemoveDuringObserve");
+
+ TextureManager textureManager; // Create new texture manager
+
+ TestObserverRemoveAndGenerateUrl observer(&textureManager); // special observer for this UTC.
+
+ std::string filename(TEST_IMAGE_FILE_NAME);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ TextureManager::TextureId textureId = textureManager.RequestLoad(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::UseAtlas::NO_ATLAS,
+ &observer,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer.mLoaded, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+ tet_printf("loaded textureId is %d, generated url is %s\n", static_cast<int>(textureId), observer.mGeneratedExternalUrl.c_str());
+
+ DALI_TEST_CHECK(static_cast<int>(textureId) != std::stoi(VisualUrl::GetLocation(observer.mGeneratedExternalUrl))); // Check we don't reuse textureId during observe
+
+ // Decrease external texture reference count who observer created
+ textureManager.RemoveExternalTexture(observer.mGeneratedExternalUrl);
+
+ application.SendNotification();
+ application.Render();
+
+ END_TEST;
+}
+
+int UtcTextureManagerRemoveDuringApplyMasking(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcTextureManagerRemoveDuringApplyMasking");
+
+ TextureManager textureManager; // Create new texture manager
+
+ TestObserver observer1;
+ TestObserver observer2;
+
+ std::string filename(TEST_IMAGE_FILE_NAME);
+ std::string maskname(TEST_MASK_FILE_NAME);
+ 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;
+
+ auto textureId1(TextureManager::INVALID_TEXTURE_ID);
+ Vector4 atlasRect(0.f, 0.f, 1.f, 1.f);
+ Dali::ImageDimensions atlasRectSize(0, 0);
+ bool synchronousLoading(false);
+ bool atlasingStatus(false);
+ bool loadingStatus(false);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ ImageAtlasManagerPtr atlasManager = nullptr;
+ Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+ textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ synchronousLoading,
+ textureId1,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ loadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &observer1,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ // Load image and mask image.
+ // Now, LoadState become MASK_APPLYING
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ tet_printf("Current textureId1:%d's state become MASK_APPLYING\n", static_cast<int>(textureId1));
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+
+ // Remove current textureId1. and request new texture again.
+ textureManager.Remove(textureId1, &observer1);
+ auto textureId2 = textureManager.RequestLoad(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::UseAtlas::NO_ATLAS,
+ &observer2,
+ true, ///< orientationCorrection
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply,
+ synchronousLoading);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mObserverCalled, false, TEST_LOCATION);
+
+ tet_printf("textureId1:%d removed and textureId2:%d requested\n", static_cast<int>(textureId1), static_cast<int>(textureId2));
+
+ // ApplyMask event come back, and do nothing.
+ // CAPTION : HARD-CODING.
+ {
+ textureManager.AsyncLoadComplete(textureId1, Dali::Devel::PixelBuffer());
+ textureManager.Remove(maskInfo->mAlphaMaskId, nullptr);
+ }
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mObserverCalled, false, TEST_LOCATION);
+
+ // CAPTION : HARD-CODING.
+ {
+ textureManager.AsyncLoadComplete(textureId2, Dali::Devel::PixelBuffer());
+ textureManager.Remove(textureId2, &observer2);
+ }
+
+ DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION); ///< Note that we call AsyncLoadComplete hardly with empty pixelbuffer.
+ DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+ END_TEST;
+}
\ No newline at end of file
const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
const char* TEST_IMAGE_FILE_NAME2 = "gallery_image_02.jpg";
+// resolution: 1024*1024
const char* TEST_IMAGE_1 = TEST_RESOURCE_DIR "/TB-gloss.png";
const char* TEST_IMAGE_2 = TEST_RESOURCE_DIR "/tb-norm.png";
ImageView gImageView1;
ImageView gImageView2;
ImageView gImageView3;
+ImageView gImageView4;
void OnResourceReadySignal03(Control control)
{
gResourceReadySignalCounter++;
}
+int gResourceReadySignal04ComesOrder = 0;
+
+void OnResourceReadySignal04(Control control)
+{
+ gResourceReadySignalCounter++;
+ tet_printf("rc %d\n", gResourceReadySignalCounter);
+ if(gResourceReadySignalCounter == 1)
+ {
+ auto scene = gImageView1.GetParent();
+
+ // Request load something
+ // We hope this request result is return later than gImageView2.
+ gImageView3 = ImageView::New(TEST_IMAGE_1);
+ gImageView3.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ scene.Add(gImageView3);
+ gImageView4 = ImageView::New(TEST_IMAGE_2);
+ gImageView4.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ scene.Add(gImageView4);
+
+ if(control == gImageView1)
+ {
+ gResourceReadySignal04ComesOrder = 1;
+ }
+ else
+ {
+ gResourceReadySignal04ComesOrder = 2;
+ }
+ }
+ if(gResourceReadySignalCounter == 2)
+ {
+ if(gResourceReadySignal04ComesOrder == 1 && control == gImageView2)
+ {
+ // Scene off first one.
+ gImageView1.Unparent();
+
+ // Scene off second one.
+ gImageView2.Unparent();
+ }
+ else if(gResourceReadySignal04ComesOrder == 2 && control == gImageView1)
+ {
+ // Scene off first one.
+ gImageView2.Unparent();
+
+ // Scene off second one.
+ gImageView1.Unparent();
+ }
+ else
+ {
+ // We can't check that this utc fail case. just pass always when we come here.
+ gResourceReadySignal04ComesOrder = -1;
+ }
+
+ // If we don't seperate index of FreeList area
+ // and if we don't queue remove during obversing,
+ // cache index become something invalid data.
+ // In this case, some strange observer can be called.
+ // For example, gImageView4.LoadComplete will be called.
+ }
+}
+
} // namespace
int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
END_TEST;
}
+
+int UtcDaliImageViewSetImageOnResourceReadySignal04(void)
+{
+ tet_infoline("Test texturemanager's remove queue works well within signal handler.");
+
+ ToolkitTestApplication application;
+
+ gResourceReadySignalCounter = 0;
+ gResourceReadySignal04ComesOrder = 0;
+
+ gImageView1 = ImageView::New("invalid.jpg"); // request invalid image, to make loading failed fast.
+ gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ application.GetScene().Add(gImageView1);
+
+ gImageView2 = ImageView::New("invalid.png"); // request invalid image, to make loading failed fast.
+ gImageView2.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ application.GetScene().Add(gImageView2);
+
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Try to load 2 invalid image");
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 2, TEST_LOCATION);
+
+ tet_infoline("load done");
+
+ // We can test this UTC only if gImageView1 and gImageView2 loaded done.
+ if(gResourceReadySignal04ComesOrder == -1)
+ {
+ tet_infoline("Bad news.. gImageView3 or gImageView4 loaded faster than others. just skip this UTC");
+ }
+ else
+ {
+ // gImageView3 and gImageView4 load must not be successed yet.
+ DALI_TEST_EQUALS(gImageView3.GetRendererCount(), 0u, TEST_LOCATION);
+ DALI_TEST_EQUALS(gImageView4.GetRendererCount(), 0u, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Try to load 2 valid image");
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 4, TEST_LOCATION);
+
+ tet_infoline("load done");
+
+ // gImageView3 and gImageView4 load must be successed now.
+ DALI_TEST_EQUALS(gImageView3.GetRendererAt(0).GetTextures().GetTextureCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(gImageView4.GetRendererAt(0).GetTextures().GetTextureCount(), 1u, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
if(visualFactory)
{
auto& textureManager = GetImplementation(visualFactory).GetTextureManager();
- mUrl = textureManager.AddExternalEncodedImageBuffer(encodedImageBuffer);
+ mUrl = textureManager.AddEncodedImageBuffer(encodedImageBuffer);
}
}
}
else if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(mUrl))
{
- textureManager.RemoveExternalEncodedImageBuffer(mUrl);
+ textureManager.RemoveEncodedImageBuffer(mUrl);
}
}
}
"Unknown"
// clang-format on
#endif
-namespace
+
+// Due to the compile issue, this specialized template code must be defined top of this code.
+template<>
+void TextureCacheManager::RemoveTextureInfoByIndex<TextureCacheManager::EncodedImageBufferInfoContainerType>(TextureCacheManager::EncodedImageBufferInfoContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
{
-} // Anonymous namespace
+ // Swap last data of cacheContainer.
+ if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
+ {
+ // First, change the cache index infomations inside of converter
+ mTextureIdConverter[cacheContainer.back().bufferId] = static_cast<std::uint32_t>(removeContainerIndex);
+
+ // After change converter, swap the value between current data and last data.
+ std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
+ }
+
+ // Now we can assume that latest data should be removed. pop_back.
+ cacheContainer.pop_back();
+}
+
+template<class ContainerType>
+void TextureCacheManager::RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
+{
+ // Swap last data of cacheContainer.
+ if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
+ {
+ // First, change the cache index infomations inside of converter
+ mTextureIdConverter[cacheContainer.back().textureId] = static_cast<std::uint32_t>(removeContainerIndex);
+
+ // After change converter, swap the value between current data and last data.
+ std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
+ }
+
+ // Now we can assume that latest data should be removed. pop_back.
+ cacheContainer.pop_back();
+}
TextureCacheManager::TextureCacheManager()
-: mCurrentTextureId(0)
{
}
VisualUrl TextureCacheManager::GetVisualUrl(const TextureCacheManager::TextureId& textureId)
{
VisualUrl visualUrl("");
- TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
- if(cacheIndex != INVALID_CACHE_INDEX)
+ switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
{
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture id=%d, textureId=%d\n", cacheIndex, textureId);
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
- visualUrl = cachedTextureInfo.url;
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+ visualUrl = cachedTextureInfo.url;
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached external texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
+ visualUrl = VisualUrl::CreateTextureUrl(std::to_string(textureId));
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER:
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached buffer index=%d, bufferId=%d\n", cacheIndex.GetIndex(), textureId);
+ visualUrl = VisualUrl::CreateBufferUrl(std::to_string(textureId));
+ break;
+ }
+ default:
+ {
+ break;
+ }
}
+
return visualUrl;
}
TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const TextureCacheManager::TextureId& textureId)
{
- LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
+ LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
- TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
- if(cacheIndex != INVALID_CACHE_INDEX)
- {
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
- loadState = cachedTextureInfo.loadState;
- }
- else
+ switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
{
- for(auto&& elem : mExternalTextures)
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
{
- if(elem.textureId == textureId)
- {
- loadState = LoadState::UPLOADED;
- break;
- }
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+ loadState = cachedTextureInfo.loadState;
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+ {
+ loadState = LoadState::UPLOADED;
+ break;
+ }
+ default:
+ {
+ break;
}
}
+
return loadState;
}
TextureCacheManager::LoadState TextureCacheManager::GetTextureStateInternal(const TextureCacheManager::TextureId& textureId)
{
- LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
-
+ LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
if(cacheIndex != INVALID_CACHE_INDEX)
{
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
loadState = cachedTextureInfo.loadState;
}
TextureSet TextureCacheManager::GetTextureSet(const TextureCacheManager::TextureId& textureId)
{
- TextureSet textureSet; // empty handle
+ TextureSet textureSet; // empty handle
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
- TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
- if(cacheIndex != INVALID_CACHE_INDEX)
+ switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
{
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
- textureSet = cachedTextureInfo.textureSet;
- }
- else
- {
- for(auto&& elem : mExternalTextures)
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
{
- if(elem.textureId == textureId)
- {
- textureSet = elem.textureSet;
- break;
- }
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+ textureSet = cachedTextureInfo.textureSet;
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+ {
+ textureSet = mExternalTextures[cacheIndex.GetIndex()].textureSet;
+ break;
+ }
+ default:
+ {
+ break;
}
}
+
return textureSet;
}
TextureSet TextureCacheManager::GetExternalTextureSet(const TextureCacheManager::TextureId& textureId)
{
- TextureSet textureSet; // empty handle
- for(auto&& elem : mExternalTextures)
+ TextureSet textureSet; // empty handle
+ TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(textureId);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == textureId)
- {
- textureSet = elem.textureSet;
- break;
- }
+ textureSet = mExternalTextures[cacheIndex.GetIndex()].textureSet;
}
return textureSet;
}
-EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& textureId)
+EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId)
{
EncodedImageBuffer encodedImageBuffer; // empty handle
- for(auto&& elem : mEncodedBufferTextures)
+ TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == textureId)
- {
- encodedImageBuffer = elem.encodedImageBuffer;
- break;
- }
+ encodedImageBuffer = mEncodedImageBuffers[cacheIndex.GetIndex()].encodedImageBuffer;
}
return encodedImageBuffer;
}
-EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const std::string& url)
+EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const VisualUrl& url)
{
EncodedImageBuffer encodedImageBuffer; // empty handle
- if(url.size() > 0 && VisualUrl::BUFFER == VisualUrl::GetProtocolType(url))
+ if(url.IsValid() && VisualUrl::BUFFER == url.GetProtocolType())
{
- std::string location = VisualUrl::GetLocation(url);
+ std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId targetId = std::stoi(location);
- return GetEncodedImageBuffer(targetId);
+ TextureId bufferId = std::stoi(location);
+ return GetEncodedImageBuffer(bufferId);
}
}
return encodedImageBuffer;
std::string TextureCacheManager::AddExternalTexture(const TextureSet& textureSet)
{
- TextureCacheManager::ExternalTextureInfo info(GenerateUniqueTextureId(), textureSet);
- mExternalTextures.emplace_back(info);
- return VisualUrl::CreateTextureUrl(std::to_string(info.textureId));
+ TextureId textureId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE, mExternalTextures.size()));
+
+ TextureCacheManager::ExternalTextureInfo textureInfo(textureId, textureSet);
+ mExternalTextures.emplace_back(textureInfo);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalTexture() : New texture registered. textureId:%d\n", textureInfo.textureId);
+
+ return VisualUrl::CreateTextureUrl(std::to_string(textureInfo.textureId));
}
-std::string TextureCacheManager::AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
+std::string TextureCacheManager::AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
{
// Duplication check
- for(auto&& elem : mEncodedBufferTextures)
+ TextureHash bufferHash = static_cast<TextureHash>(encodedImageBuffer.GetHash());
+ TextureCacheIndex bufferCacheIndex = FindCachedEncodedImageBuffer(bufferHash, encodedImageBuffer);
+ if(bufferCacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.encodedImageBuffer == encodedImageBuffer)
- {
- // If same buffer added, increase reference count and return.
- elem.referenceCount++;
- return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));
- }
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[bufferCacheIndex.GetIndex()]);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : Increase reference. bufferId:%d, cache index:%d, reference:%d\n", bufferInfo.bufferId, bufferCacheIndex.GetIndex(), static_cast<int>(bufferInfo.referenceCount));
+
+ // If same buffer added, increase reference count and return.
+ bufferInfo.referenceCount++;
+ return VisualUrl::CreateBufferUrl(std::to_string(bufferInfo.bufferId));
}
- TextureCacheManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer);
- mEncodedBufferTextures.emplace_back(info);
- return VisualUrl::CreateBufferUrl(std::to_string(info.textureId));
+
+ TextureId bufferId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER, mEncodedImageBuffers.size()));
+
+ TextureCacheManager::EncodedImageBufferInfo info(bufferId, bufferHash, encodedImageBuffer);
+ mEncodedImageBuffers.emplace_back(info);
+
+ // Insert TextureHashContainer
+ // Find exist list -or- Create new list.
+ std::vector<TextureId>& idList = mTextureHashContainer[bufferHash];
+ // We already assume that list doesn't contain id. just emplace back
+ idList.emplace_back(bufferId);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : New buffer regested. bufferId:%d\n", info.bufferId);
+
+ return VisualUrl::CreateBufferUrl(std::to_string(info.bufferId));
}
-TextureSet TextureCacheManager::RemoveExternalTexture(const std::string& url)
+TextureSet TextureCacheManager::RemoveExternalTexture(const VisualUrl& url)
{
- if(url.size() > 0u)
+ TextureSet textureSet;
+ bool removeTextureInfo = false;
+ TextureCacheIndex removeTextureIndex = INVALID_CACHE_INDEX;
+ if(url.IsValid())
{
- if(VisualUrl::TEXTURE == VisualUrl::GetProtocolType(url))
+ if(VisualUrl::TEXTURE == url.GetProtocolType())
{
// get the location from the Url
- std::string location = VisualUrl::GetLocation(url);
+ std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- const auto end = mExternalTextures.end();
- for(auto iter = mExternalTextures.begin(); iter != end; ++iter)
+ TextureId textureId = std::stoi(location);
+ removeTextureIndex = GetCacheIndexFromExternalTextureId(textureId);
+ if(removeTextureIndex != INVALID_CACHE_INDEX)
{
- if(iter->textureId == id)
+ ExternalTextureInfo& textureInfo(mExternalTextures[removeTextureIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::RemoveExternalTexture(url:%s) textureId:%d reference:%d\n", url.GetUrl().c_str(), textureId, static_cast<int>(textureInfo.referenceCount));
+ textureSet = textureInfo.textureSet;
+ if(--(textureInfo.referenceCount) <= 0)
{
- auto textureSet = iter->textureSet;
- if(--(iter->referenceCount) <= 0)
- {
- mExternalTextures.erase(iter);
- }
- return textureSet;
+ removeTextureInfo = true;
+ // id life is finished. Remove it at converter
+ mTextureIdConverter.Remove(textureId);
}
}
}
}
}
- return TextureSet();
+
+ // Post removal process to avoid mExternalTextures reference problems.
+ if(removeTextureInfo)
+ {
+ // Swap last data of mExternalTextures, and pop_back.
+ RemoveTextureInfoByIndex(mExternalTextures, removeTextureIndex);
+ }
+ return textureSet;
}
-EncodedImageBuffer TextureCacheManager::RemoveExternalEncodedImageBuffer(const std::string& url)
+EncodedImageBuffer TextureCacheManager::RemoveEncodedImageBuffer(const VisualUrl& url)
{
- if(url.size() > 0u)
+ EncodedImageBuffer encodedImageBuffer;
+ bool removeBufferInfo = false;
+ TextureCacheIndex removeBufferIndex = INVALID_CACHE_INDEX;
+ if(url.IsValid())
{
- if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(url))
+ if(VisualUrl::BUFFER == url.GetProtocolType())
{
// get the location from the Url
- std::string location = VisualUrl::GetLocation(url);
+ std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- const auto end = mEncodedBufferTextures.end();
- for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter)
+ TextureId bufferId = std::stoi(location);
+ removeBufferIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
+
+ if(removeBufferIndex != INVALID_CACHE_INDEX)
{
- if(iter->textureId == id)
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[removeBufferIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::RemoveEncodedImageBuffer(url:%s) bufferId:%d reference:%d\n", url.GetUrl().c_str(), bufferId, static_cast<int>(bufferInfo.referenceCount));
+
+ encodedImageBuffer = bufferInfo.encodedImageBuffer;
+ if(--(bufferInfo.referenceCount) <= 0)
{
- auto encodedImageBuffer = iter->encodedImageBuffer;
- if(--(iter->referenceCount) <= 0)
- {
- mEncodedBufferTextures.erase(iter);
- }
- return encodedImageBuffer;
+ removeBufferInfo = true;
+ // Step 1. remove current textureId information in mTextureHashContainer.
+ RemoveHashId(bufferInfo.bufferHash, bufferId);
+ // Step 2. id life is finished. Remove it at converter
+ mTextureIdConverter.Remove(bufferId);
}
}
}
}
}
- return EncodedImageBuffer();
+
+ // Post removal process to avoid mEncodedImageBuffers reference problems.
+ if(removeBufferInfo)
+ {
+ // Step 3. swap last data of mEncodedImageBuffers, and pop_back.
+ RemoveTextureInfoByIndex(mEncodedImageBuffers, removeBufferIndex);
+ }
+ return encodedImageBuffer;
}
void TextureCacheManager::UseExternalResource(const VisualUrl& url)
std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- for(auto&& elem : mExternalTextures)
+ TextureId id = std::stoi(location);
+ TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == id)
- {
- elem.referenceCount++;
- return;
- }
+ ExternalTextureInfo& textureInfo(mExternalTextures[cacheIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::UseExternalResource(url:%s) type:TEXTURE, location:%s, reference:%d\n", url.GetUrl().c_str(), url.GetLocation().c_str(), static_cast<int>(textureInfo.referenceCount));
+
+ textureInfo.referenceCount++;
+ return;
}
}
}
std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- for(auto&& elem : mEncodedBufferTextures)
+ TextureId id = std::stoi(location);
+ TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == id)
- {
- elem.referenceCount++;
- return;
- }
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::UseExternalResource(url:%s) type:BUFFER, location:%s, reference:%d\n", url.GetUrl().c_str(), url.GetLocation().c_str(), static_cast<int>(bufferInfo.referenceCount));
+
+ bufferInfo.referenceCount++;
+ return;
}
}
}
}
-TextureCacheManager::TextureId TextureCacheManager::GenerateUniqueTextureId()
+TextureCacheManager::TextureId TextureCacheManager::GenerateTextureId(const TextureCacheIndex& textureCacheIndex)
{
- return mCurrentTextureId++;
+ return mTextureIdConverter.Add(static_cast<std::uint32_t>(textureCacheIndex.indexValue));
}
TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromId(const TextureCacheManager::TextureId& textureId)
{
- const TextureCacheIndex size = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
+ if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
- for(TextureCacheIndex i = 0; i < size; ++i)
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
+ if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL))
{
- if(mTextureInfoContainer[i].textureId == textureId)
+ return INVALID_CACHE_INDEX;
+ }
+
+ DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mTextureInfoContainer.size());
+
+ return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId)
+{
+ if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
+
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
+ if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE))
+ {
+ return INVALID_CACHE_INDEX;
+ }
+
+ DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mExternalTextures.size());
+
+ return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId)
+{
+ if(bufferId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
+
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(bufferId)]);
+ if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER))
+ {
+ return INVALID_CACHE_INDEX;
+ }
+
+ DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mEncodedImageBuffers.size());
+
+ return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer)
+{
+ // Iterate through our hashes to find a match.
+ const auto& hashIterator = mTextureHashContainer.find(hash);
+ if(hashIterator != mTextureHashContainer.cend())
+ {
+ for(const auto& id : hashIterator->second)
{
- return i;
+ // We have a match, now we check all the original parameters in case of a hash collision.
+ TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
+ {
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
+
+ if(bufferInfo.encodedImageBuffer == encodedImageBuffer)
+ {
+ // The found encoded image buffer.
+ return cacheIndex;
+ }
+ }
}
}
+ // Default to an invalid ID, in case we do not find a match.
return INVALID_CACHE_INDEX;
}
TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::TextureId& maskTextureId,
const bool& cropToMask)
{
- std::vector<std::uint8_t> hashTarget(url.begin(), url.end());
- const size_t urlLength = url.length();
+ std::vector<std::uint8_t> hashTarget(url.GetUrl().begin(), url.GetUrl().end());
+ const size_t urlLength = hashTarget.size();
const uint16_t width = size.GetWidth();
const uint16_t height = size.GetWidth();
TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture(
const TextureCacheManager::TextureHash& hash,
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
const TextureCacheManager::TextureId& maskTextureId,
+ const bool& cropToMask,
const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
- bool isAnimatedImage,
- const bool& cropToMask)
+ const bool& isAnimatedImage)
{
- // Default to an invalid ID, in case we do not find a match.
- TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
-
// Iterate through our hashes to find a match.
- const TextureCacheIndex count = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
- for(TextureCacheIndex i = 0u; i < count; ++i)
+ const auto& hashIterator = mTextureHashContainer.find(hash);
+ if(hashIterator != mTextureHashContainer.cend())
{
- if(mTextureInfoContainer[i].hash == hash)
+ for(const auto& textureId : hashIterator->second)
{
// We have a match, now we check all the original parameters in case of a hash collision.
- TextureInfo& textureInfo(mTextureInfoContainer[i]);
-
- if((url == textureInfo.url.GetUrl()) &&
- (useAtlas == textureInfo.useAtlas) &&
- (maskTextureId == textureInfo.maskTextureId) &&
- (cropToMask == textureInfo.cropToMask) &&
- (size == textureInfo.desiredSize) &&
- (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
- ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
- (fittingMode == textureInfo.fittingMode &&
- samplingMode == textureInfo.samplingMode)))
+ TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- // 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 == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
+ TextureInfo& textureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+
+ if((url.GetUrl() == textureInfo.url.GetUrl()) &&
+ (useAtlas == textureInfo.useAtlas) &&
+ (maskTextureId == textureInfo.maskTextureId) &&
+ (cropToMask == textureInfo.cropToMask) &&
+ (size == textureInfo.desiredSize) &&
+ (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
+ ((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 == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
+ {
+ // The found Texture is a match.
+ return cacheIndex;
+ }
}
}
}
}
- return cacheIndex;
+ // Default to an invalid ID, in case we do not find a match.
+ return INVALID_CACHE_INDEX;
}
TextureCacheManager::TextureCacheIndex TextureCacheManager::AppendCache(const TextureCacheManager::TextureInfo& textureInfo)
{
- TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
+ // If we use EncodedImageBuffer, increase reference during it contains mTextureInfoContainer.
+ // This reference will be decreased when we call RemoveCache
+ if(textureInfo.url.GetProtocolType() == VisualUrl::BUFFER)
+ {
+ UseExternalResource(textureInfo.url);
+ }
+
+ TextureHash hash = textureInfo.hash;
+ TextureId id = textureInfo.textureId;
+
+ // Insert TextureHash container first
+ // Find exist list -or- Create new list.
+ std::vector<TextureId>& idList = mTextureHashContainer[hash];
+ // We already assume that list doesn't contain id. just emplace back
+ idList.emplace_back(id);
+
+ // Insert TextureInfo back of mTextureInfoContainer.
+ TextureCacheIndex cacheIndex = TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, mTextureInfoContainer.size());
mTextureInfoContainer.emplace_back(textureInfo);
+
+ // Add converter id --> cacheIndex
+ // NOTE : We should assume that id already generated by GenerateTextureId function.
+ mTextureIdConverter[id] = cacheIndex;
+
return cacheIndex;
}
{
TextureCacheIndex textureInfoIndex = GetCacheIndexFromId(textureId);
+ bool removeTextureInfo = false;
+
if(textureInfoIndex != INVALID_CACHE_INDEX)
{
- TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex]);
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%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);
+ TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex.GetIndex()]);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%d) url:%s\n cacheIdx:%d loadState:%s reference count = %d\n", textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex.GetIndex(), 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)
{
// This is the last remove for this Texture.
textureInfo.referenceCount = 0;
- bool removeTextureInfo = false;
// If loaded, we can remove the TextureInfo and the Atlas (if atlased).
if(textureInfo.loadState == LoadState::UPLOADED)
}
removeTextureInfo = true;
}
- else if(textureInfo.loadState == LoadState::LOADING)
+ else if(textureInfo.loadState == LoadState::LOADING || textureInfo.loadState == LoadState::MASK_APPLYING)
{
// We mark the textureInfo for removal.
// Once the load has completed, this method will be called again.
// If url location is BUFFER, decrease reference count of EncodedImageBuffer.
if(textureInfo.url.IsBufferResource())
{
- RemoveExternalEncodedImageBuffer(textureInfo.url.GetUrl());
+ RemoveEncodedImageBuffer(textureInfo.url.GetUrl());
}
+
// Permanently remove the textureInfo struct.
- mTextureInfoContainer.erase(mTextureInfoContainer.begin() + textureInfoIndex);
+
+ // Step 1. remove current textureId information in mTextureHashContainer.
+ RemoveHashId(textureInfo.hash, textureId);
+ // Step 2. make textureId is not using anymore. After this job, we can reuse textureId.
+ mTextureIdConverter.Remove(textureId);
+ }
+ }
+ }
+
+ // Post removal process to avoid mTextureInfoContainer reference problems.
+ if(removeTextureInfo)
+ {
+ // Step 3. swap last data of TextureInfoContainer, and pop_back.
+ RemoveTextureInfoByIndex(mTextureInfoContainer, textureInfoIndex);
+ }
+}
+
+void TextureCacheManager::RemoveHashId(const TextureCacheManager::TextureHash& textureHash, const TextureCacheManager::TextureId& textureId)
+{
+ auto hashIterator = mTextureHashContainer.find(textureHash);
+ if(hashIterator != mTextureHashContainer.end())
+ {
+ auto hashIdList = hashIterator->second;
+ const auto& hashIdIterator = std::find(hashIdList.cbegin(), hashIdList.cend(), textureId);
+ if(hashIdIterator != hashIdList.cend())
+ {
+ hashIdList.erase(hashIdIterator);
+ if(hashIdList.size() == 0)
+ {
+ // If id list in current hash is empty, remove it self in the container.
+ mTextureHashContainer.erase(hashIterator);
}
}
}
*/
// EXTERNAL INCLUDES
+#include <dali/devel-api/common/free-list.h>
#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+#include <unordered_map>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
* You can Convert TextureId into TextureCacheIndex by this class.
*
* Also, You can store external TextureSet or EncodedImageBuffer here.
+ *
+ * There are 3 type of CachedContainer in this manager
+ * - mTextureInfoContainer : Cache all kind of textures that need some load/upload jobs.
+ * All kind of images that visual using (not vector image) will be stored here.
+ * This container will use TEXTURE_CACHE_INDEX_TYPE_LOCAL
+ *
+ * - mExternalTextures : External appended TextureSet cache container.
+ * External TextureSet can be Something like NativeImageSource, FrameBuffer and PixelData.
+ * This container will use TEXTURE_CACHE_INDEX_TYPE_TEXTURE
+ * The textureId will be used for VisualUrl. ex) dali://1
+ *
+ * - mEncodedImageBuffers : External appended EncodedImageBuffer cache container.
+ * This container will use TEXTURE_CACHE_INDEX_TYPE_BUFFER
+ * The bufferId will be used for VisualUrl. ex) enbuf://1
+ * Note that this bufferId is not equal with textureId in mTextureInfoContainer.
*/
class TextureCacheManager
{
public:
// Copy enum and types and const values that TextureCacheManager will use.
+ using TextureCacheIndexType = TextureManagerType::TextureCacheIndexType;
+ using TextureCacheIndexData = TextureManagerType::TextureCacheIndexData;
+
using TextureId = TextureManagerType::TextureId;
using TextureCacheIndex = TextureManagerType::TextureCacheIndex;
using TextureHash = TextureManagerType::TextureHash;
/**
* @brief Get the current state of a texture
+ * @note This API doesn't consider encodedimagebuffer.
* @param[in] textureId The texture id to query
* @return The loading state if the texture is valid, or NOT_STARTED if the textureId
* is not valid.
/**
* @brief Get the current state of a texture
+ * @note This API doesn't consider external & encodedimagebuffer.
* @param[in] textureId The texture id to query
* @return The loading state if the texture is valid, or NOT_STARTED if the textureId
* is not valid.
/**
* @brief Get the encoded image buffer
- * @param[in] textureId The textureId to look up
- * @return the encoded image buffer, or an empty handle if textureId is not valid
+ * @param[in] bufferId The bufferId to look up
+ * @return the encoded image buffer, or an empty handle if bufferId is not valid
*/
- EncodedImageBuffer GetEncodedImageBuffer(const TextureCacheManager::TextureId& textureId);
+ EncodedImageBuffer GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId);
/**
* @brief Get the encoded image buffer by VisualUrl
* @param[in] url The url to look up
* @return the encoded image buffer, or an empty handle if url is not buffer resource or buffer is not valid
*/
- EncodedImageBuffer GetEncodedImageBuffer(const std::string& url);
+ EncodedImageBuffer GetEncodedImageBuffer(const VisualUrl& url);
/**
* Adds an external texture to the texture manager
std::string AddExternalTexture(const TextureSet& texture);
/**
- * Adds an external encoded image buffer to the texture manager
+ * Adds an encoded image buffer to the texture manager
* @param[in] encodedImageBuffer The image buffer to add
* @return string containing the URL for the texture
*/
- std::string AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer);
+ std::string AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer);
/**
* Removes an external texture from texture manager
* @param[in] url The string containing the texture to remove
* @return handle to the texture
*/
- TextureSet RemoveExternalTexture(const std::string& url);
+ TextureSet RemoveExternalTexture(const VisualUrl& url);
/**
* Removes an external encoded image buffer from texture manager
* @param[in] url The string containing the encoded image buffer to remove
* @return handle to the encoded image buffer
*/
- EncodedImageBuffer RemoveExternalEncodedImageBuffer(const std::string& url);
+ EncodedImageBuffer RemoveEncodedImageBuffer(const VisualUrl& url);
/**
- * @brief Notify that external textures or external encoded image buffers are used.
+ * @brief Notify that external textures or encoded image buffers are used.
* @param[in] url The URL of the texture to use.
*/
void UseExternalResource(const VisualUrl& url);
// To Generate / Get / Remove TextureId.
/**
- * @brief Generates a new, unique TextureId
- * @return A unique TextureId
+ * @brief Generates a new valid TextureId.
+ * @param[in] textureCacheIndex the index of the cache container. If we don't setup this value, default is INVALID_CACHE_INDEX
+ * @return A TextureId
*/
- TextureCacheManager::TextureId GenerateUniqueTextureId();
+ TextureCacheManager::TextureId GenerateTextureId(const TextureCacheIndex& textureCacheIndex = INVALID_CACHE_INDEX);
/**
* @brief Used to lookup an index into the TextureInfoContainer from a TextureId
* @return A hash of the provided data for caching.
*/
TextureCacheManager::TextureHash GenerateHash(
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlas True if atlased
* @param[in] maskTextureId Optional texture ID to use to mask this image
- * @param[in] preMultiplyOnLoad If the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+ * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
* @param[in] isAnimatedImage True if the texture is from animated image.
* @param[in] cropToMask True if crop to mask
- * @return A TextureCacheId of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
+ * @return A TextureCacheIndex of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
*/
TextureCacheManager::TextureCacheIndex FindCachedTexture(
const TextureCacheManager::TextureHash& hash,
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
const TextureCacheManager::TextureId& maskTextureId,
+ const bool& cropToMask,
const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
- bool isAnimatedImage,
- const bool& cropToMask);
+ const bool& isAnimatedImage);
/**
* @brief Append a Texture to the TextureCacheManager.
* @note This API doesn't check duplication of TextureId.
+ * @note This API doesn't consider external & encodedimagebuffer.
*
* @param[in] textureInfo TextureInfo that want to cache in container.
* @return Index of newly appended texture info.
/**
* @brief Remove a Texture from the TextureCacheManager.
+ * @note This API doesn't consider external & encodedimagebuffer.
*
* Textures are cached and therefore only the removal of the last
* occurrence of a Texture will cause its removal internally.
*/
inline TextureCacheManager::TextureInfo& operator[](const TextureCacheManager::TextureCacheIndex& textureCacheIndex) noexcept
{
- return mTextureInfoContainer[textureCacheIndex];
+ return mTextureInfoContainer[textureCacheIndex.GetIndex()];
}
/**
private:
// Private defined structs.
+ /**
+ * @brief This struct is used to manage the life-cycle of ExternalTexture url.
+ */
struct ExternalTextureInfo
{
ExternalTextureInfo(const TextureCacheManager::TextureId& textureId,
std::int16_t referenceCount;
};
- struct EncodedBufferTextureInfo
+ /**
+ * @brief This struct is used to manage the life-cycle of EncodedImageBuffer url.
+ */
+ struct EncodedImageBufferInfo
{
- EncodedBufferTextureInfo(const TextureCacheManager::TextureId& textureId,
- const EncodedImageBuffer& encodedImageBuffer)
- : textureId(textureId),
+ EncodedImageBufferInfo(const TextureCacheManager::TextureId& bufferId,
+ const TextureCacheManager::TextureHash& bufferHash,
+ const EncodedImageBuffer& encodedImageBuffer)
+ : bufferId(bufferId),
+ bufferHash(bufferHash),
encodedImageBuffer(encodedImageBuffer),
referenceCount(1u)
{
}
- TextureCacheManager::TextureId textureId;
- EncodedImageBuffer encodedImageBuffer;
- std::int16_t referenceCount;
+ TextureCacheManager::TextureId bufferId;
+ TextureCacheManager::TextureHash bufferHash;
+ EncodedImageBuffer encodedImageBuffer;
+ std::int16_t referenceCount;
};
- typedef std::vector<TextureCacheManager::TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
- typedef std::vector<TextureCacheManager::ExternalTextureInfo> ExternalTextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
- typedef std::vector<TextureCacheManager::EncodedBufferTextureInfo> EncodedBufferTextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
+ typedef Dali::FreeList TextureIdConverterType; ///< The converter type from TextureId to index of TextureInfoContainer.
+
+ typedef std::unordered_map<TextureCacheManager::TextureHash, std::vector<TextureCacheManager::TextureId>> TextureHashContainerType; ///< The container type used to fast-find the TextureId by TextureHash.
+ typedef std::vector<TextureCacheManager::TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
+ typedef std::vector<TextureCacheManager::ExternalTextureInfo> ExternalTextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of ExternalTexture url
+ typedef std::vector<TextureCacheManager::EncodedImageBufferInfo> EncodedImageBufferInfoContainerType; ///< The container type used to manage the life-cycle and caching of EncodedImageBuffer url
+
+private:
+ // Private API: only used internally
+
+ /**
+ * @brief Used to lookup an index into the ExternalTextureInfoContainer from a textureId
+ * @param[in] textureId The TextureId to look up
+ * @return The cache index
+ */
+ TextureCacheManager::TextureCacheIndex GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId);
+
+ /**
+ * @brief Used to lookup an index into the EncodedImageBufferInfoContainer from a bufferId
+ * @param[in] bufferId The bufferId to look up
+ * @return The cache index
+ */
+ TextureCacheManager::TextureCacheIndex GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId);
+
+ /**
+ * @brief Looks up a cached encoded image buffer cached by its hash.
+ * If found, the given parameters are used to check there is no hash-collision.
+ * @param[in] hash The hash to look up
+ * @param[in] encodedImageBuffer The image buffer to load
+ * @return A TextureCacheIndex of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
+ */
+ TextureCacheManager::TextureCacheIndex FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer);
+
+ /**
+ * @brief Remove id in HashContainer.
+ * @param[in] hash The hash of the texture/buffer to be delete
+ * @param[in] id The texture/buffer id to be deleted.
+ */
+ void RemoveHashId(const TextureCacheManager::TextureHash& hash, const TextureCacheManager::TextureId& id);
+
+ /**
+ * @brief Remove data from container by the TextureCacheIndex.
+ * It also valiate the TextureIdConverter internally.
+ * We will assume that only valid TextureCacheIndex will come.
+ *
+ * @tparam ContainerType The type of container. It will automatically defined
+ * @param[in] cacheContainer The container that will remove texture info.
+ * @param[in] removeContainerIndex The index of texture info that will remove.
+ */
+ template<class ContainerType>
+ void RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex);
private:
/**
*/
TextureCacheManager& operator=(const TextureCacheManager& rhs) = delete;
-private: // Member Variables:
- TextureInfoContainerType mTextureInfoContainer{}; ///< Used to manage the life-cycle and caching of Textures
- ExternalTextureInfoContainerType mExternalTextures{}; ///< Externally provided textures
- EncodedBufferTextureInfoContainerType mEncodedBufferTextures{}; ///< Externally encoded buffer textures
- TextureCacheManager::TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
+private: // Member Variables:
+ TextureIdConverterType mTextureIdConverter{}; ///< Convert TextureId into various container's index.
+ TextureHashContainerType mTextureHashContainer{}; ///< Used to manage the life-cycle and caching of Textures + EncodedImageBuffer by TextureHash
+
+ TextureInfoContainerType mTextureInfoContainer{}; ///< Used to manage the life-cycle and caching of Textures
+ ExternalTextureInfoContainerType mExternalTextures{}; ///< Externally provided textures
+ EncodedImageBufferInfoContainerType mEncodedImageBuffers{}; ///< Externally encoded image buffer
};
} // namespace Internal
mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }),
mLifecycleObservers(),
mLoadQueue(),
+ mRemoveQueue(),
mQueueLoadFlag(false)
{
// Initialize the AddOn
{
if(url.IsBufferResource())
{
- const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl());
+ const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
if(encodedImageBuffer)
{
pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
if(storageType != StorageType::RETURN_PIXEL_BUFFER && useCache)
{
- textureHash = mTextureCacheManager.GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask);
+ textureHash = mTextureCacheManager.GenerateHash(url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask);
// Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
- cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false, cropToMask);
+ cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
}
TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
// 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\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d premultiplied=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0);
}
if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
{
- if(VisualUrl::BUFFER == url.GetProtocolType())
- {
- std::string location = url.GetLocation();
- if(location.size() > 0u)
- {
- TextureId targetId = std::stoi(location);
- const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(targetId);
- if(encodedImageBuffer)
- {
- textureId = targetId;
-
- // Increase EncodedImageBuffer reference during it contains mTextureInfoContainer.
- // TODO! We should change action when reload policy is FORCE.
- // Eunki Hong will fix it after refactoring patch merged.
- mTextureCacheManager.UseExternalResource(url.GetUrl());
- }
- }
- }
-
- if(textureId == INVALID_TEXTURE_ID)
- {
- textureId = mTextureCacheManager.GenerateUniqueTextureId();
- }
+ textureId = mTextureCacheManager.GenerateTextureId();
bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
// Cache new texutre, and get cacheIndex.
cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
- 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);
+ 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.GetIndex(), textureId);
}
// The below code path is common whether we are using the cache or not.
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);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId);
textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
}
void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureUploadObserver* observer)
{
- // Remove textureId in CacheManager.
- mTextureCacheManager.RemoveCache(textureId);
-
- if(observer)
+ if(textureId != INVALID_TEXTURE_ID)
{
- // Remove element from the LoadQueue
- for(auto&& element : mLoadQueue)
+ if(mQueueLoadFlag)
+ {
+ // Remove textureId after NotifyObserver finished
+ mRemoveQueue.PushBack(textureId);
+ }
+ else
{
- if(element.mObserver == observer)
+ // Remove textureId in CacheManager.
+ mTextureCacheManager.RemoveCache(textureId);
+ }
+
+ if(observer)
+ {
+ // Remove element from the LoadQueue
+ for(auto&& element : mLoadQueue)
{
- // Do not erase the item. We will clear it later in ProcessQueuedTextures().
- element.mObserver = nullptr;
- break;
+ if(element.mObserver == observer)
+ {
+ // Do not erase the item. We will clear it later in ProcessLoadQueue().
+ element.mObserver = nullptr;
+ break;
+ }
}
}
}
Devel::PixelBuffer pixelBuffer;
if(url.IsBufferResource())
{
- const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl());
+ const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
if(encodedImageBuffer)
{
pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
ObserveTexture(textureInfo, observer);
}
-void TextureManager::ProcessQueuedTextures()
+void TextureManager::ProcessLoadQueue()
{
for(auto&& element : mLoadQueue)
{
mLoadQueue.Clear();
}
+void TextureManager::ProcessRemoveQueue()
+{
+ for(const auto& textureId : mRemoveQueue)
+ {
+ mTextureCacheManager.RemoveCache(textureId);
+ }
+ mRemoveQueue.Clear();
+}
+
void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo,
TextureUploadObserver* observer)
{
void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, Devel::PixelBuffer pixelBuffer)
{
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d )\n", textureId);
TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d CacheIndex:%d )\n", textureId, cacheIndex.GetIndex());
if(cacheIndex != INVALID_CACHE_INDEX)
{
TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, " textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex, GET_LOAD_STATE_STRING(textureInfo.loadState));
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, " textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState));
if(textureInfo.loadState != LoadState::CANCELLED)
{
{
// Search the cache, checking if any texture has this texture id as a
// maskTextureId:
- const TextureCacheIndex size = static_cast<TextureCacheIndex>(mTextureCacheManager.size());
+ const std::size_t size = mTextureCacheManager.size();
const bool maskLoadSuccess = maskTextureInfo.loadState == LoadState::LOAD_FINISHED ? true : false;
- for(TextureCacheIndex cacheIndex = 0; cacheIndex < size; ++cacheIndex)
+ // TODO : Refactorize here to not iterate whole cached image.
+ for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
{
if(mTextureCacheManager[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
mTextureCacheManager[cacheIndex].loadState == LoadState::WAITING_FOR_MASK)
// 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, textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState));
+ 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));
// It is possible for the observer to be deleted.
// Disconnect and remove the observer first.
}
mQueueLoadFlag = false;
- ProcessQueuedTextures();
+ ProcessLoadQueue();
+ ProcessRemoveQueue();
if(info->storageType == StorageType::RETURN_PIXEL_BUFFER && info->observerList.Count() == 0)
{
void TextureManager::ObserverDestroyed(TextureUploadObserver* observer)
{
- const TextureCacheIndex count = static_cast<TextureCacheIndex>(mTextureCacheManager.size());
- for(TextureCacheIndex i = 0; i < count; ++i)
+ const std::size_t size = mTextureCacheManager.size();
+ for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
{
- TextureInfo& textureInfo(mTextureCacheManager[i]);
+ TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
for(TextureInfo::ObserverListType::Iterator j = textureInfo.observerList.Begin();
j != textureInfo.observerList.End();)
{
}
/**
- * @copydoc TextureCacheManager::RemoveExternalEncodedImageBuffer
+ * @copydoc TextureCacheManager::RemoveEncodedImageBuffer
*/
- inline EncodedImageBuffer RemoveExternalEncodedImageBuffer(const std::string& url)
+ inline EncodedImageBuffer RemoveEncodedImageBuffer(const std::string& url)
{
- return mTextureCacheManager.RemoveExternalEncodedImageBuffer(url);
+ return mTextureCacheManager.RemoveEncodedImageBuffer(url);
}
/**
}
/**
- * @copydoc TextureCacheManager::AddExternalEncodedImageBuffer
+ * @copydoc TextureCacheManager::AddEncodedImageBuffer
*/
- inline std::string AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
+ inline std::string AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
{
- return mTextureCacheManager.AddExternalEncodedImageBuffer(encodedImageBuffer);
+ return mTextureCacheManager.AddEncodedImageBuffer(encodedImageBuffer);
}
public: // Load Request API
/**
* @brief Initiate load of textures queued whilst NotifyObservers invoking callbacks.
*/
- void ProcessQueuedTextures();
+ void ProcessLoadQueue();
+
+ /**
+ * @brief Initiate remove of texture queued whilst NotifyObservers invoking callbacks.
+ */
+ void ProcessRemoveQueue();
/**
* Add the observer to the observer list
RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
- Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
- Dali::Vector<LoadQueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
- bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued.
+ Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
+ Dali::Vector<LoadQueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
+ Dali::Vector<TextureManager::TextureId> mRemoveQueue; ///< Queue of textures to remove after NotifyObservers
+ bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued.
};
} // namespace Internal
*/
namespace TextureManagerType
{
+// Enum!
+
+enum TextureCacheIndexType
+{
+ TEXTURE_CACHE_INDEX_FREE_LIST = 0, ///< Only for FreeList. We should not use this for TextureCacheIndex.
+ TEXTURE_CACHE_INDEX_TYPE_LOCAL = 1,
+ TEXTURE_CACHE_INDEX_TYPE_TEXTURE,
+ TEXTURE_CACHE_INDEX_TYPE_BUFFER,
+ TEXTURE_CACHE_INDEX_TYPE_MASKING, ///< Not implemented yet.
+ TEXTURE_CACHE_INDEX_TYPE_MAX = 7, ///< Maximum number of cache type we can use.
+};
+
+// Union!
+
+/**
+ * @brief standard union type of texture index.
+ * Due to the FreeList can only use for uint32_t and we need to seperate
+ * each index per container type, we can only hold maximum 2^28 textures
+ * at the same time.
+ * 0 ~ 2^28 - 1 : index of FreeList. TextureCacheManager will not use it.
+ * 2^28 ~ 2*2^28 - 1 : index of mTextureInfoContainer, the main texture container.
+ * 2*2^28 ~ 3*2^28 - 1 : index of mExternalTextures.
+ * 3*2^28 ~ 4*2^28 - 1 : index of mEncodedBufferTextures.
+ */
+union TextureCacheIndexData
+{
+ TextureCacheIndexData() = default;
+ constexpr TextureCacheIndexData(const std::uint32_t& index)
+ : indexValue(index)
+ {
+ }
+ constexpr explicit TextureCacheIndexData(const std::int32_t& index)
+ : indexValue(static_cast<std::uint32_t>(index))
+ {
+ }
+ constexpr TextureCacheIndexData(const TextureCacheIndexType& type, const std::uint32_t& index)
+ : detailValue{index, type}
+ {
+ }
+ constexpr TextureCacheIndexData(const TextureCacheIndexData& indexData)
+ : indexValue(indexData.indexValue)
+ {
+ }
+ constexpr TextureCacheIndexData(TextureCacheIndexData&& indexData)
+ : indexValue(indexData.indexValue)
+ {
+ }
+
+ TextureCacheIndexData& operator=(const std::uint32_t& index)
+ {
+ indexValue = index;
+ return *this;
+ }
+ TextureCacheIndexData& operator=(const TextureCacheIndexData& rhs)
+ {
+ indexValue = rhs.indexValue;
+ return *this;
+ }
+ TextureCacheIndexData& operator=(TextureCacheIndexData&& rhs)
+ {
+ indexValue = rhs.indexValue;
+ return *this;
+ }
+
+ constexpr operator std::uint32_t() const
+ {
+ return indexValue;
+ }
+ constexpr operator std::uint32_t()
+ {
+ return indexValue;
+ }
+ constexpr explicit operator std::int32_t() const
+ {
+ return static_cast<std::int32_t>(indexValue);
+ }
+ constexpr explicit operator std::int32_t()
+ {
+ return static_cast<std::int32_t>(indexValue);
+ }
+
+ // Return detailValue.index. - the real index of datailValue.type container
+ constexpr inline std::uint32_t GetIndex() const
+ {
+ return detailValue.index;
+ }
+
+ inline constexpr bool operator==(const TextureCacheIndexData& rhs)
+ {
+ return indexValue == rhs.indexValue;
+ }
+ inline constexpr bool operator<(const TextureCacheIndexData& rhs)
+ {
+ return indexValue < rhs.indexValue;
+ }
+
+ // Data area
+ std::uint32_t indexValue;
+ struct
+ {
+ unsigned int index : 28;
+ TextureCacheIndexType type : 4;
+ } detailValue;
+};
+
// Typedef:
-typedef std::int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
-typedef std::int32_t TextureCacheIndex; ///< The TextureCacheIndex type. This is used as a handles to refer to a particular Texture in TextureCacheManager.
- /// Note : For the same Texture, TextureId will not be changed. But TextureCacheIndex can be chaged when TextureCacheManager
- /// Internal container informations changed by Append or Remove.
-typedef std::size_t TextureHash; ///< The type used to store the hash used for Texture caching.
+typedef std::int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
+typedef TextureCacheIndexData TextureCacheIndex; ///< The TextureCacheIndex type. This is used as a handles to refer to a particular Texture in TextureCacheManager.
+ /// Note : For the same Texture, TextureId will not be changed. But TextureCacheIndex can be chaged when TextureCacheManager
+ /// Internal container informations changed by Append or Remove.
+typedef std::size_t TextureHash; ///< The type used to store the hash used for Texture caching.
// Constant values:
static constexpr TextureId INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
-static constexpr TextureCacheIndex INVALID_CACHE_INDEX = -1; ///< Used to represent a null TextureCacheIndex or error
+static constexpr TextureCacheIndex INVALID_CACHE_INDEX = 0; ///< Used to represent a null TextureCacheIndex or error
// Enum classes:
else if(mImageUrl.IsBufferResource())
{
TextureManager& textureManager = mFactoryCache.GetTextureManager();
- textureManager.RemoveExternalEncodedImageBuffer(mImageUrl.GetUrl());
+ textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
}
}