2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "texture-cache-manager.h"
22 #include <dali/devel-api/common/hash.h>
23 #include <dali/integration-api/debug.h>
34 extern Debug::Filter* gTextureManagerLogFilter; ///< Define at texture-manager-impl.cpp
37 #define GET_LOAD_STATE_STRING(loadState) \
38 loadState == TextureManagerType::LoadState::NOT_STARTED ? "NOT_STARTED" : \
39 loadState == TextureManagerType::LoadState::LOADING ? "LOADING" : \
40 loadState == TextureManagerType::LoadState::LOAD_FINISHED ? "LOAD_FINISHED" : \
41 loadState == TextureManagerType::LoadState::WAITING_FOR_MASK ? "WAITING_FOR_MASK" : \
42 loadState == TextureManagerType::LoadState::MASK_APPLYING ? "MASK_APPLYING" : \
43 loadState == TextureManagerType::LoadState::MASK_APPLIED ? "MASK_APPLIED" : \
44 loadState == TextureManagerType::LoadState::UPLOADED ? "UPLOADED" : \
45 loadState == TextureManagerType::LoadState::CANCELLED ? "CANCELLED" : \
46 loadState == TextureManagerType::LoadState::MASK_CANCELLED ? "MASK_CANCELLED" : \
47 loadState == TextureManagerType::LoadState::LOAD_FAILED ? "LOAD_FAILED" : \
52 // Due to the compile issue, this specialized template code must be defined top of this code.
54 void TextureCacheManager::RemoveTextureInfoByIndex<TextureCacheManager::EncodedImageBufferInfoContainerType>(TextureCacheManager::EncodedImageBufferInfoContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
56 // Swap last data of cacheContainer.
57 if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
59 // First, change the cache index infomations inside of converter
60 mTextureIdConverter[cacheContainer.back().bufferId] = static_cast<std::uint32_t>(removeContainerIndex);
62 // After change converter, swap the value between current data and last data.
63 std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
66 // Now we can assume that latest data should be removed. pop_back.
67 cacheContainer.pop_back();
70 template<class ContainerType>
71 void TextureCacheManager::RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
73 // Swap last data of cacheContainer.
74 if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
76 // First, change the cache index infomations inside of converter
77 mTextureIdConverter[cacheContainer.back().textureId] = static_cast<std::uint32_t>(removeContainerIndex);
79 // After change converter, swap the value between current data and last data.
80 std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
83 // Now we can assume that latest data should be removed. pop_back.
84 cacheContainer.pop_back();
87 TextureCacheManager::TextureCacheManager()
91 TextureCacheManager::~TextureCacheManager()
95 VisualUrl TextureCacheManager::GetVisualUrl(const TextureCacheManager::TextureId& textureId)
97 VisualUrl visualUrl("");
98 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
100 switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
102 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
104 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
106 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
107 visualUrl = cachedTextureInfo.url;
110 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
112 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached external texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
113 visualUrl = VisualUrl::CreateTextureUrl(std::to_string(textureId));
116 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER:
118 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached buffer index=%d, bufferId=%d\n", cacheIndex.GetIndex(), textureId);
119 visualUrl = VisualUrl::CreateBufferUrl(std::to_string(textureId));
131 TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const TextureCacheManager::TextureId& textureId)
133 LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
134 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
136 switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
138 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
140 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
141 loadState = cachedTextureInfo.loadState;
144 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
146 loadState = LoadState::UPLOADED;
158 TextureCacheManager::LoadState TextureCacheManager::GetTextureStateInternal(const TextureCacheManager::TextureId& textureId)
160 LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
161 TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
162 if(cacheIndex != INVALID_CACHE_INDEX)
164 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
165 loadState = cachedTextureInfo.loadState;
171 Texture TextureCacheManager::GetTexture(const TextureCacheManager::TextureId& textureId, uint32_t textureIndex)
173 Texture texture; // empty handle
174 TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
176 switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
178 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
180 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
181 if(textureIndex < static_cast<uint32_t>(cachedTextureInfo.textures.size()))
183 texture = cachedTextureInfo.textures[textureIndex];
196 TextureSet TextureCacheManager::GetExternalTextureSet(const TextureCacheManager::TextureId& textureId)
198 TextureSet textureSet; // empty handle
199 TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(textureId);
200 if(cacheIndex != INVALID_CACHE_INDEX)
202 textureSet = mExternalTextures[cacheIndex.GetIndex()].textureSet;
207 EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId)
209 EncodedImageBuffer encodedImageBuffer; // empty handle
210 TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
211 if(cacheIndex != INVALID_CACHE_INDEX)
213 encodedImageBuffer = mEncodedImageBuffers[cacheIndex.GetIndex()].encodedImageBuffer;
215 return encodedImageBuffer;
218 EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const VisualUrl& url)
220 EncodedImageBuffer encodedImageBuffer; // empty handle
221 if(url.IsValid() && VisualUrl::BUFFER == url.GetProtocolType())
223 std::string location = url.GetLocation();
224 if(location.size() > 0u)
226 TextureId bufferId = std::stoi(location);
227 return GetEncodedImageBuffer(bufferId);
230 return encodedImageBuffer;
233 std::string TextureCacheManager::AddExternalTexture(const TextureSet& textureSet)
235 TextureId textureId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE, mExternalTextures.size()));
237 TextureCacheManager::ExternalTextureInfo textureInfo(textureId, textureSet);
238 mExternalTextures.emplace_back(textureInfo);
240 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalTexture() : New texture registered. textureId:%d\n", textureInfo.textureId);
242 return VisualUrl::CreateTextureUrl(std::to_string(textureInfo.textureId));
245 std::string TextureCacheManager::AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
248 TextureHash bufferHash = static_cast<TextureHash>(encodedImageBuffer.GetHash());
249 TextureCacheIndex bufferCacheIndex = FindCachedEncodedImageBuffer(bufferHash, encodedImageBuffer);
250 if(bufferCacheIndex != INVALID_CACHE_INDEX)
252 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[bufferCacheIndex.GetIndex()]);
254 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));
256 // If same buffer added, increase reference count and return.
257 bufferInfo.referenceCount++;
258 return VisualUrl::CreateBufferUrl(std::to_string(bufferInfo.bufferId));
261 TextureId bufferId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER, mEncodedImageBuffers.size()));
263 TextureCacheManager::EncodedImageBufferInfo info(bufferId, bufferHash, encodedImageBuffer);
264 mEncodedImageBuffers.emplace_back(info);
266 // Insert TextureHashContainer
267 // Find exist list -or- Create new list.
268 std::vector<TextureId>& idList = mTextureHashContainer[bufferHash];
269 // We already assume that list doesn't contain id. just emplace back
270 idList.emplace_back(bufferId);
272 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : New buffer regested. bufferId:%d\n", info.bufferId);
274 return VisualUrl::CreateBufferUrl(std::to_string(info.bufferId));
277 TextureSet TextureCacheManager::RemoveExternalTexture(const VisualUrl& url)
279 TextureSet textureSet;
280 bool removeTextureInfo = false;
281 TextureCacheIndex removeTextureIndex = INVALID_CACHE_INDEX;
284 if(VisualUrl::TEXTURE == url.GetProtocolType())
286 // get the location from the Url
287 std::string location = url.GetLocation();
288 if(location.size() > 0u)
290 TextureId textureId = std::stoi(location);
291 removeTextureIndex = GetCacheIndexFromExternalTextureId(textureId);
292 if(removeTextureIndex != INVALID_CACHE_INDEX)
294 ExternalTextureInfo& textureInfo(mExternalTextures[removeTextureIndex.GetIndex()]);
295 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));
296 textureSet = textureInfo.textureSet;
297 if(--(textureInfo.referenceCount) <= 0)
299 removeTextureInfo = true;
300 // id life is finished. Remove it at converter
301 mTextureIdConverter.Remove(textureId);
308 // Post removal process to avoid mExternalTextures reference problems.
309 if(removeTextureInfo)
311 // Swap last data of mExternalTextures, and pop_back.
312 RemoveTextureInfoByIndex(mExternalTextures, removeTextureIndex);
317 EncodedImageBuffer TextureCacheManager::RemoveEncodedImageBuffer(const VisualUrl& url)
319 EncodedImageBuffer encodedImageBuffer;
320 bool removeBufferInfo = false;
321 TextureCacheIndex removeBufferIndex = INVALID_CACHE_INDEX;
324 if(VisualUrl::BUFFER == url.GetProtocolType())
326 // get the location from the Url
327 std::string location = url.GetLocation();
328 if(location.size() > 0u)
330 TextureId bufferId = std::stoi(location);
331 removeBufferIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
333 if(removeBufferIndex != INVALID_CACHE_INDEX)
335 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[removeBufferIndex.GetIndex()]);
336 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));
338 encodedImageBuffer = bufferInfo.encodedImageBuffer;
339 if(--(bufferInfo.referenceCount) <= 0)
341 removeBufferInfo = true;
342 // Step 1. remove current textureId information in mTextureHashContainer.
343 RemoveHashId(bufferInfo.bufferHash, bufferId);
344 // Step 2. id life is finished. Remove it at converter
345 mTextureIdConverter.Remove(bufferId);
352 // Post removal process to avoid mEncodedImageBuffers reference problems.
355 // Step 3. swap last data of mEncodedImageBuffers, and pop_back.
356 RemoveTextureInfoByIndex(mEncodedImageBuffers, removeBufferIndex);
358 return encodedImageBuffer;
361 void TextureCacheManager::UseExternalResource(const VisualUrl& url)
363 if(VisualUrl::TEXTURE == url.GetProtocolType())
365 std::string location = url.GetLocation();
366 if(location.size() > 0u)
368 TextureId id = std::stoi(location);
369 TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(id);
370 if(cacheIndex != INVALID_CACHE_INDEX)
372 ExternalTextureInfo& textureInfo(mExternalTextures[cacheIndex.GetIndex()]);
373 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));
375 textureInfo.referenceCount++;
380 else if(VisualUrl::BUFFER == url.GetProtocolType())
382 std::string location = url.GetLocation();
383 if(location.size() > 0u)
385 TextureId id = std::stoi(location);
386 TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
387 if(cacheIndex != INVALID_CACHE_INDEX)
389 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
390 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));
392 bufferInfo.referenceCount++;
399 TextureCacheManager::TextureId TextureCacheManager::GenerateTextureId(const TextureCacheIndex& textureCacheIndex)
401 return mTextureIdConverter.Add(static_cast<std::uint32_t>(textureCacheIndex.indexValue));
404 TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromId(const TextureCacheManager::TextureId& textureId)
406 if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
408 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
409 if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL))
411 return INVALID_CACHE_INDEX;
414 DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mTextureInfoContainer.size());
419 TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId)
421 if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
423 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
424 if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE))
426 return INVALID_CACHE_INDEX;
429 DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mExternalTextures.size());
434 TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId)
436 if(bufferId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
438 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(bufferId)]);
439 if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER))
441 return INVALID_CACHE_INDEX;
444 DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mEncodedImageBuffers.size());
449 TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer)
451 // Iterate through our hashes to find a match.
452 const auto& hashIterator = mTextureHashContainer.find(hash);
453 if(hashIterator != mTextureHashContainer.cend())
455 for(const auto& id : hashIterator->second)
457 // We have a match, now we check all the original parameters in case of a hash collision.
458 TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
459 if(cacheIndex != INVALID_CACHE_INDEX)
461 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
463 if(bufferInfo.encodedImageBuffer == encodedImageBuffer)
465 // The found encoded image buffer.
472 // Default to an invalid ID, in case we do not find a match.
473 return INVALID_CACHE_INDEX;
476 TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
477 const VisualUrl& url,
478 const Dali::ImageDimensions& size,
479 const Dali::FittingMode::Type& fittingMode,
480 const Dali::SamplingMode::Type& samplingMode,
481 const TextureCacheManager::UseAtlas& useAtlas,
482 const TextureCacheManager::TextureId& maskTextureId,
483 const bool& cropToMask,
484 const std::uint32_t& frameIndex)
486 std::vector<std::uint8_t> hashTarget;
487 const uint16_t width = size.GetWidth();
488 const uint16_t height = size.GetWidth();
490 // If either the width or height has been specified, include the resizing options in the hash
491 if(width != 0 || height != 0)
493 // We are appending 5 bytes to the URL to form the hash input.
494 hashTarget.resize(5u);
495 std::uint8_t* hashTargetPtr = &(hashTarget[0u]);
497 // Pack the width and height (4 bytes total).
498 *hashTargetPtr++ = size.GetWidth() & 0xff;
499 *hashTargetPtr++ = (size.GetWidth() >> 8u) & 0xff;
500 *hashTargetPtr++ = size.GetHeight() & 0xff;
501 *hashTargetPtr++ = (size.GetHeight() >> 8u) & 0xff;
503 // Bit-pack the FittingMode, SamplingMode and atlasing.
504 // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit
505 *hashTargetPtr = (fittingMode << 4u) | (samplingMode << 1) | (useAtlas == UseAtlas::USE_ATLAS ? 1 : 0);
509 // We are not including sizing information, but we still need an extra byte for atlasing.
510 hashTarget.resize(1u);
512 // Add the atlasing to the hash input.
515 case UseAtlas::NO_ATLAS:
517 hashTarget[0u] = 'f';
520 case UseAtlas::USE_ATLAS:
522 hashTarget[0u] = 't';
528 if(maskTextureId != INVALID_TEXTURE_ID)
530 auto textureIdIndex = hashTarget.size();
531 hashTarget.resize(hashTarget.size() + sizeof(TextureId) + 1u);
532 std::uint8_t* hashTargetPtr = reinterpret_cast<std::uint8_t*>(&(hashTarget[textureIdIndex]));
534 // Append the texture id to the end of the URL byte by byte:
535 // (to avoid SIGBUS / alignment issues)
536 TextureId saltedMaskTextureId = maskTextureId;
537 for(size_t byteIter = 0; byteIter < sizeof(TextureId); ++byteIter)
539 *hashTargetPtr++ = saltedMaskTextureId & 0xff;
540 saltedMaskTextureId >>= 8u;
542 *hashTargetPtr++ = (cropToMask ? 'C' : 'M');
545 // Append the frameIndex. We don't do additional job when frameIndex = 0u due to the non-animated image case.
548 auto textureIdIndex = hashTarget.size();
549 hashTarget.resize(hashTarget.size() + sizeof(std::uint32_t));
550 std::uint8_t* hashTargetPtr = reinterpret_cast<std::uint8_t*>(&(hashTarget[textureIdIndex]));
552 // Append the frame index to the end of the URL byte by byte:
553 std::uint32_t saltedFrameIndex = frameIndex;
554 for(size_t byteIter = 0; byteIter < sizeof(std::uint8_t); ++byteIter)
556 *hashTargetPtr++ = saltedFrameIndex & 0xff;
557 saltedFrameIndex >>= 8u;
561 return url.GetUrlHash() ^ Dali::CalculateHash(hashTarget);
564 TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture(
565 const TextureCacheManager::TextureHash& hash,
566 const VisualUrl& url,
567 const Dali::ImageDimensions& size,
568 const Dali::FittingMode::Type& fittingMode,
569 const Dali::SamplingMode::Type& samplingMode,
570 const TextureCacheManager::UseAtlas& useAtlas,
571 const StorageType& storageType,
572 const TextureCacheManager::TextureId& maskTextureId,
573 const bool& cropToMask,
574 const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
575 const bool& isAnimatedImage,
576 const std::uint32_t& frameIndex)
578 // Iterate through our hashes to find a match.
579 const auto& hashIterator = mTextureHashContainer.find(hash);
580 if(hashIterator != mTextureHashContainer.cend())
582 for(const auto& textureId : hashIterator->second)
584 // We have a match, now we check all the original parameters in case of a hash collision.
585 TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
586 if(cacheIndex != INVALID_CACHE_INDEX)
588 TextureInfo& textureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
590 if((url.GetUrl() == textureInfo.url.GetUrl()) &&
591 (useAtlas == textureInfo.useAtlas) &&
592 (maskTextureId == textureInfo.maskTextureId) &&
593 (cropToMask == textureInfo.cropToMask) &&
594 (size == textureInfo.desiredSize) &&
595 (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
596 (storageType == textureInfo.storageType) &&
597 (frameIndex == textureInfo.frameIndex) &&
598 ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
599 (fittingMode == textureInfo.fittingMode &&
600 samplingMode == textureInfo.samplingMode)))
602 // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
603 // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
604 if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
606 // The found Texture is a match.
614 // Default to an invalid ID, in case we do not find a match.
615 return INVALID_CACHE_INDEX;
618 TextureCacheManager::TextureCacheIndex TextureCacheManager::AppendCache(const TextureCacheManager::TextureInfo& textureInfo)
620 // If we use EncodedImageBuffer, increase reference during it contains mTextureInfoContainer.
621 // This reference will be decreased when we call RemoveCache
622 if(textureInfo.url.GetProtocolType() == VisualUrl::BUFFER)
624 UseExternalResource(textureInfo.url);
627 TextureHash hash = textureInfo.hash;
628 TextureId id = textureInfo.textureId;
630 // Insert TextureHash container first
631 // Find exist list -or- Create new list.
632 std::vector<TextureId>& idList = mTextureHashContainer[hash];
633 // We already assume that list doesn't contain id. just emplace back
634 idList.emplace_back(id);
636 // Insert TextureInfo back of mTextureInfoContainer.
637 TextureCacheIndex cacheIndex = TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, mTextureInfoContainer.size());
638 mTextureInfoContainer.emplace_back(textureInfo);
640 // Add converter id --> cacheIndex
641 // NOTE : We should assume that id already generated by GenerateTextureId function.
642 mTextureIdConverter[id] = cacheIndex;
647 void TextureCacheManager::RemoveCache(TextureCacheManager::TextureInfo& textureInfo)
649 TextureCacheIndex textureInfoIndex = GetCacheIndexFromId(textureInfo.textureId);
650 bool removeTextureInfo = false;
652 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%d) url:%s\n cacheIdx:%d loadState:%s reference count = %d\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState), textureInfo.referenceCount);
654 // Decrement the reference count and check if this is the last user of this Texture.
655 if(--textureInfo.referenceCount <= 0)
657 // This is the last remove for this Texture.
658 textureInfo.referenceCount = 0;
660 // If loaded, we can remove the TextureInfo and the Atlas (if atlased).
661 if(textureInfo.loadState == LoadState::UPLOADED)
663 if(textureInfo.atlas)
665 textureInfo.atlas.Remove(textureInfo.atlasRect);
667 removeTextureInfo = true;
669 else if(textureInfo.loadState == LoadState::LOADING)
671 // We mark the textureInfo for removal.
672 // Once the load has completed, this method will be called again.
673 textureInfo.loadState = LoadState::CANCELLED;
675 else if(textureInfo.loadState == LoadState::MASK_APPLYING)
677 // We mark the textureInfo for removal.
678 // Once the load has completed, this method will be called again.
679 textureInfo.loadState = LoadState::MASK_CANCELLED;
683 // In other states, we are not waiting for a load so we are safe to remove the TextureInfo data.
684 removeTextureInfo = true;
687 // If the state allows us to remove the TextureInfo data, we do so.
688 if(removeTextureInfo)
690 // If url location is BUFFER, decrease reference count of EncodedImageBuffer.
691 if(textureInfo.url.IsBufferResource())
693 RemoveEncodedImageBuffer(textureInfo.url.GetUrl());
696 // Permanently remove the textureInfo struct.
698 // Step 1. remove current textureId information in mTextureHashContainer.
699 RemoveHashId(textureInfo.hash, textureInfo.textureId);
700 // Step 2. make textureId is not using anymore. After this job, we can reuse textureId.
701 mTextureIdConverter.Remove(textureInfo.textureId);
705 // Post removal process to avoid mTextureInfoContainer reference problems.
706 if(removeTextureInfo)
708 // Step 3. swap last data of TextureInfoContainer, and pop_back.
709 RemoveTextureInfoByIndex(mTextureInfoContainer, textureInfoIndex);
713 void TextureCacheManager::RemoveHashId(const TextureCacheManager::TextureHash& textureHash, const TextureCacheManager::TextureId& textureId)
715 auto hashIterator = mTextureHashContainer.find(textureHash);
716 if(hashIterator != mTextureHashContainer.end())
718 auto hashIdList = hashIterator->second;
719 const auto& hashIdIterator = std::find(hashIdList.cbegin(), hashIdList.cend(), textureId);
720 if(hashIdIterator != hashIdList.cend())
722 hashIdList.erase(hashIdIterator);
723 if(hashIdList.size() == 0)
725 // If id list in current hash is empty, remove it self in the container.
726 mTextureHashContainer.erase(hashIterator);
732 } // namespace Internal
734 } // namespace Toolkit