2 * Copyright (c) 2023 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 <dali-toolkit/internal/texture-manager/texture-cache-manager.h>
22 #include <dali/devel-api/common/hash.h>
23 #include <dali/integration-api/debug.h>
24 #include <string_view>
25 #include <unordered_map>
37 const std::string_view& GetEncodedImageBufferExtensions(Dali::EncodedImageBuffer::ImageType imageType)
39 static const std::unordered_map<Dali::EncodedImageBuffer::ImageType, const std::string_view> gEncodedImageBufferExtensionMap =
41 {Dali::EncodedImageBuffer::ImageType::REGULAR_IMAGE, ""},
42 {Dali::EncodedImageBuffer::ImageType::VECTOR_IMAGE, ".svg"},
43 {Dali::EncodedImageBuffer::ImageType::ANIMATED_VECTOR_IMAGE, ".json"},
46 const auto iter = gEncodedImageBufferExtensionMap.find(imageType);
48 DALI_ASSERT_DEBUG(iter != gEncodedImageBufferExtensionMap.end());
54 extern Debug::Filter* gTextureManagerLogFilter; ///< Define at texture-manager-impl.cpp
57 #define GET_LOAD_STATE_STRING(loadState) \
58 loadState == TextureManagerType::LoadState::NOT_STARTED ? "NOT_STARTED" : \
59 loadState == TextureManagerType::LoadState::LOADING ? "LOADING" : \
60 loadState == TextureManagerType::LoadState::LOAD_FINISHED ? "LOAD_FINISHED" : \
61 loadState == TextureManagerType::LoadState::WAITING_FOR_MASK ? "WAITING_FOR_MASK" : \
62 loadState == TextureManagerType::LoadState::MASK_APPLYING ? "MASK_APPLYING" : \
63 loadState == TextureManagerType::LoadState::MASK_APPLIED ? "MASK_APPLIED" : \
64 loadState == TextureManagerType::LoadState::UPLOADED ? "UPLOADED" : \
65 loadState == TextureManagerType::LoadState::CANCELLED ? "CANCELLED" : \
66 loadState == TextureManagerType::LoadState::MASK_CANCELLED ? "MASK_CANCELLED" : \
67 loadState == TextureManagerType::LoadState::LOAD_FAILED ? "LOAD_FAILED" : \
72 // Due to the compile issue, this specialized template code must be defined top of this code.
74 void TextureCacheManager::RemoveTextureInfoByIndex<TextureCacheManager::EncodedImageBufferInfoContainerType>(TextureCacheManager::EncodedImageBufferInfoContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
76 // Swap last data of cacheContainer.
77 if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
79 // First, change the cache index infomations inside of converter
80 mTextureIdConverter[cacheContainer.back().bufferId] = static_cast<std::uint32_t>(removeContainerIndex);
82 // After change converter, swap the value between current data and last data.
83 std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
86 // Now we can assume that latest data should be removed. pop_back.
87 cacheContainer.pop_back();
90 template<class ContainerType>
91 void TextureCacheManager::RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
93 // Swap last data of cacheContainer.
94 if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
96 // First, change the cache index infomations inside of converter
97 mTextureIdConverter[cacheContainer.back().textureId] = static_cast<std::uint32_t>(removeContainerIndex);
99 // After change converter, swap the value between current data and last data.
100 std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
103 // Now we can assume that latest data should be removed. pop_back.
104 cacheContainer.pop_back();
107 TextureCacheManager::TextureCacheManager()
111 TextureCacheManager::~TextureCacheManager()
115 VisualUrl TextureCacheManager::GetVisualUrl(const TextureCacheManager::TextureId& textureId)
117 VisualUrl visualUrl("");
118 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
120 switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
122 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
124 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
126 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
127 visualUrl = cachedTextureInfo.url;
130 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
132 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached external texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
133 visualUrl = VisualUrl::CreateTextureUrl(std::to_string(textureId));
136 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER:
138 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached buffer index=%d, bufferId=%d\n", cacheIndex.GetIndex(), textureId);
140 EncodedImageBufferInfo& cachedEncodedImageBufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
141 const auto& encodedImageBuffer = cachedEncodedImageBufferInfo.encodedImageBuffer;
142 visualUrl = VisualUrl::CreateBufferUrl(std::to_string(textureId), GetEncodedImageBufferExtensions(encodedImageBuffer.GetImageType()));
154 TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const TextureCacheManager::TextureId& textureId)
156 LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
157 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
159 switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
161 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
163 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
164 loadState = cachedTextureInfo.loadState;
167 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
169 loadState = LoadState::UPLOADED;
181 TextureCacheManager::LoadState TextureCacheManager::GetTextureStateInternal(const TextureCacheManager::TextureId& textureId)
183 LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
184 TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
185 if(cacheIndex != INVALID_CACHE_INDEX)
187 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
188 loadState = cachedTextureInfo.loadState;
194 Texture TextureCacheManager::GetTexture(const TextureCacheManager::TextureId& textureId, uint32_t textureIndex)
196 Texture texture; // empty handle
197 TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
199 switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
201 case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
203 TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
204 if(textureIndex < static_cast<uint32_t>(cachedTextureInfo.textures.size()))
206 texture = cachedTextureInfo.textures[textureIndex];
219 TextureCacheManager::ExternalTextureInfo& TextureCacheManager::GetExternalTextureInfo(const TextureCacheManager::TextureId& textureId)
221 TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(textureId);
222 DALI_ASSERT_ALWAYS(cacheIndex != INVALID_CACHE_INDEX);
224 return mExternalTextures[cacheIndex.GetIndex()];
227 EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId)
229 EncodedImageBuffer encodedImageBuffer; // empty handle
230 TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
231 if(cacheIndex != INVALID_CACHE_INDEX)
233 encodedImageBuffer = mEncodedImageBuffers[cacheIndex.GetIndex()].encodedImageBuffer;
235 return encodedImageBuffer;
238 EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const VisualUrl& url)
240 EncodedImageBuffer encodedImageBuffer; // empty handle
241 if(url.IsValid() && VisualUrl::BUFFER == url.GetProtocolType())
243 std::string location = url.GetLocationWithoutExtension();
244 if(location.size() > 0u)
246 TextureId bufferId = std::stoi(location);
247 return GetEncodedImageBuffer(bufferId);
250 return encodedImageBuffer;
253 std::string TextureCacheManager::AddExternalTexture(const TextureSet& textureSet, bool preMultiplied)
255 TextureId textureId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE, mExternalTextures.size()));
257 TextureCacheManager::ExternalTextureInfo textureInfo(textureId, textureSet, preMultiplied);
258 mExternalTextures.emplace_back(textureInfo);
260 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalTexture() : New texture registered. textureId:%d, preMultiplied:%d\n", textureInfo.textureId, preMultiplied);
262 return VisualUrl::CreateTextureUrl(std::to_string(textureInfo.textureId));
265 std::string TextureCacheManager::AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
268 TextureHash bufferHash = static_cast<TextureHash>(encodedImageBuffer.GetHash());
269 TextureCacheIndex bufferCacheIndex = FindCachedEncodedImageBuffer(bufferHash, encodedImageBuffer);
270 if(bufferCacheIndex != INVALID_CACHE_INDEX)
272 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[bufferCacheIndex.GetIndex()]);
274 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));
276 // If same buffer added, increase reference count and return.
277 bufferInfo.referenceCount++;
278 return VisualUrl::CreateBufferUrl(std::to_string(bufferInfo.bufferId), GetEncodedImageBufferExtensions(encodedImageBuffer.GetImageType()));
281 TextureId bufferId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER, mEncodedImageBuffers.size()));
283 TextureCacheManager::EncodedImageBufferInfo info(bufferId, bufferHash, encodedImageBuffer);
284 mEncodedImageBuffers.emplace_back(info);
286 // Insert TextureHashContainer
287 // Find exist list -or- Create new list.
288 std::vector<TextureId>& idList = mTextureHashContainer[bufferHash];
289 // We already assume that list doesn't contain id. just emplace back
290 idList.emplace_back(bufferId);
292 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : New buffer regested. bufferId:%d\n", info.bufferId);
294 return VisualUrl::CreateBufferUrl(std::to_string(info.bufferId), GetEncodedImageBufferExtensions(encodedImageBuffer.GetImageType()));
297 TextureSet TextureCacheManager::RemoveExternalTexture(const VisualUrl& url)
299 TextureSet textureSet;
300 bool removeTextureInfo = false;
301 TextureCacheIndex removeTextureIndex = INVALID_CACHE_INDEX;
304 if(VisualUrl::TEXTURE == url.GetProtocolType())
306 // get the location from the Url
307 std::string location = url.GetLocation();
308 if(location.size() > 0u)
310 TextureId textureId = std::stoi(location);
311 removeTextureIndex = GetCacheIndexFromExternalTextureId(textureId);
312 if(removeTextureIndex != INVALID_CACHE_INDEX)
314 ExternalTextureInfo& textureInfo(mExternalTextures[removeTextureIndex.GetIndex()]);
315 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));
316 textureSet = textureInfo.textureSet;
317 if(--(textureInfo.referenceCount) <= 0)
319 removeTextureInfo = true;
320 // id life is finished. Remove it at converter
321 mTextureIdConverter.Remove(textureId);
328 // Post removal process to avoid mExternalTextures reference problems.
329 if(removeTextureInfo)
331 // Swap last data of mExternalTextures, and pop_back.
332 RemoveTextureInfoByIndex(mExternalTextures, removeTextureIndex);
337 EncodedImageBuffer TextureCacheManager::RemoveEncodedImageBuffer(const VisualUrl& url)
339 EncodedImageBuffer encodedImageBuffer;
340 bool removeBufferInfo = false;
341 TextureCacheIndex removeBufferIndex = INVALID_CACHE_INDEX;
344 if(VisualUrl::BUFFER == url.GetProtocolType())
346 // get the location from the Url
347 std::string location = url.GetLocationWithoutExtension();
348 if(location.size() > 0u)
350 TextureId bufferId = std::stoi(location);
351 removeBufferIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
353 if(removeBufferIndex != INVALID_CACHE_INDEX)
355 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[removeBufferIndex.GetIndex()]);
356 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));
358 encodedImageBuffer = bufferInfo.encodedImageBuffer;
359 if(--(bufferInfo.referenceCount) <= 0)
361 removeBufferInfo = true;
362 // Step 1. remove current textureId information in mTextureHashContainer.
363 RemoveHashId(bufferInfo.bufferHash, bufferId);
364 // Step 2. id life is finished. Remove it at converter
365 mTextureIdConverter.Remove(bufferId);
372 // Post removal process to avoid mEncodedImageBuffers reference problems.
375 // Step 3. swap last data of mEncodedImageBuffers, and pop_back.
376 RemoveTextureInfoByIndex(mEncodedImageBuffers, removeBufferIndex);
378 return encodedImageBuffer;
381 void TextureCacheManager::UseExternalResource(const VisualUrl& url)
383 if(VisualUrl::TEXTURE == url.GetProtocolType())
385 std::string location = url.GetLocation();
386 if(location.size() > 0u)
388 TextureId id = std::stoi(location);
389 TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(id);
390 if(cacheIndex != INVALID_CACHE_INDEX)
392 ExternalTextureInfo& textureInfo(mExternalTextures[cacheIndex.GetIndex()]);
393 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));
395 textureInfo.referenceCount++;
400 else if(VisualUrl::BUFFER == url.GetProtocolType())
402 std::string location = url.GetLocationWithoutExtension();
403 if(location.size() > 0u)
405 TextureId id = std::stoi(location);
406 TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
407 if(cacheIndex != INVALID_CACHE_INDEX)
409 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
410 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));
412 bufferInfo.referenceCount++;
419 TextureCacheManager::TextureId TextureCacheManager::GenerateTextureId(const TextureCacheIndex& textureCacheIndex)
421 return mTextureIdConverter.Add(static_cast<std::uint32_t>(textureCacheIndex.indexValue));
424 TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromId(const TextureCacheManager::TextureId& textureId)
426 if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
428 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
429 if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL))
431 return INVALID_CACHE_INDEX;
434 DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mTextureInfoContainer.size());
439 TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId)
441 if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
443 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
444 if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE))
446 return INVALID_CACHE_INDEX;
449 DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mExternalTextures.size());
454 TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId)
456 if(bufferId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
458 TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(bufferId)]);
459 if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER))
461 return INVALID_CACHE_INDEX;
464 DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mEncodedImageBuffers.size());
469 TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer)
471 // Iterate through our hashes to find a match.
472 const auto& hashIterator = mTextureHashContainer.find(hash);
473 if(hashIterator != mTextureHashContainer.cend())
475 for(const auto& id : hashIterator->second)
477 // We have a match, now we check all the original parameters in case of a hash collision.
478 TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
479 if(cacheIndex != INVALID_CACHE_INDEX)
481 EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
483 if(bufferInfo.encodedImageBuffer == encodedImageBuffer)
485 // The found encoded image buffer.
492 // Default to an invalid ID, in case we do not find a match.
493 return INVALID_CACHE_INDEX;
496 TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
497 const VisualUrl& url,
498 const Dali::ImageDimensions& size,
499 const Dali::FittingMode::Type& fittingMode,
500 const Dali::SamplingMode::Type& samplingMode,
501 const TextureCacheManager::UseAtlas& useAtlas,
502 const TextureCacheManager::TextureId& maskTextureId,
503 const bool& cropToMask,
504 const std::uint32_t& frameIndex)
506 std::vector<std::uint8_t> hashTarget;
507 const uint16_t width = size.GetWidth();
508 const uint16_t height = size.GetWidth();
510 // If either the width or height has been specified, include the resizing options in the hash
511 if(width != 0 || height != 0)
513 // We are appending 5 bytes to the URL to form the hash input.
514 hashTarget.resize(5u);
515 std::uint8_t* hashTargetPtr = &(hashTarget[0u]);
517 // Pack the width and height (4 bytes total).
518 *hashTargetPtr++ = size.GetWidth() & 0xff;
519 *hashTargetPtr++ = (size.GetWidth() >> 8u) & 0xff;
520 *hashTargetPtr++ = size.GetHeight() & 0xff;
521 *hashTargetPtr++ = (size.GetHeight() >> 8u) & 0xff;
523 // Bit-pack the FittingMode, SamplingMode and atlasing.
524 // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit
525 *hashTargetPtr = (fittingMode << 4u) | (samplingMode << 1) | (useAtlas == UseAtlas::USE_ATLAS ? 1 : 0);
529 // We are not including sizing information, but we still need an extra byte for atlasing.
530 hashTarget.resize(1u);
532 // Add the atlasing to the hash input.
535 case UseAtlas::NO_ATLAS:
537 hashTarget[0u] = 'f';
540 case UseAtlas::USE_ATLAS:
542 hashTarget[0u] = 't';
548 if(maskTextureId != INVALID_TEXTURE_ID)
550 auto textureIdIndex = hashTarget.size();
551 hashTarget.resize(hashTarget.size() + sizeof(TextureId) + 1u);
552 std::uint8_t* hashTargetPtr = reinterpret_cast<std::uint8_t*>(&(hashTarget[textureIdIndex]));
554 // Append the texture id to the end of the URL byte by byte:
555 // (to avoid SIGBUS / alignment issues)
556 TextureId saltedMaskTextureId = maskTextureId;
557 for(size_t byteIter = 0; byteIter < sizeof(TextureId); ++byteIter)
559 *hashTargetPtr++ = saltedMaskTextureId & 0xff;
560 saltedMaskTextureId >>= 8u;
562 *hashTargetPtr++ = (cropToMask ? 'C' : 'M');
565 // Append the frameIndex. We don't do additional job when frameIndex = 0u due to the non-animated image case.
568 auto textureIdIndex = hashTarget.size();
569 hashTarget.resize(hashTarget.size() + sizeof(std::uint32_t));
570 std::uint8_t* hashTargetPtr = reinterpret_cast<std::uint8_t*>(&(hashTarget[textureIdIndex]));
572 // Append the frame index to the end of the URL byte by byte:
573 std::uint32_t saltedFrameIndex = frameIndex;
574 for(size_t byteIter = 0; byteIter < sizeof(std::uint8_t); ++byteIter)
576 *hashTargetPtr++ = saltedFrameIndex & 0xff;
577 saltedFrameIndex >>= 8u;
581 return url.GetUrlHash() ^ Dali::CalculateHash(hashTarget);
584 TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture(
585 const TextureCacheManager::TextureHash& hash,
586 const VisualUrl& url,
587 const Dali::ImageDimensions& size,
588 const Dali::FittingMode::Type& fittingMode,
589 const Dali::SamplingMode::Type& samplingMode,
590 const TextureCacheManager::UseAtlas& useAtlas,
591 const StorageType& storageType,
592 const TextureCacheManager::TextureId& maskTextureId,
593 const bool& cropToMask,
594 const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
595 const bool& isAnimatedImage,
596 const std::uint32_t& frameIndex)
598 // Iterate through our hashes to find a match.
599 const auto& hashIterator = mTextureHashContainer.find(hash);
600 if(hashIterator != mTextureHashContainer.cend())
602 for(const auto& textureId : hashIterator->second)
604 // We have a match, now we check all the original parameters in case of a hash collision.
605 TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
606 if(cacheIndex != INVALID_CACHE_INDEX)
608 TextureInfo& textureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
610 if((url.GetUrl() == textureInfo.url.GetUrl()) &&
611 (useAtlas == textureInfo.useAtlas) &&
612 (maskTextureId == textureInfo.maskTextureId) &&
613 (cropToMask == textureInfo.cropToMask) &&
614 (size == textureInfo.desiredSize) &&
615 (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
616 (storageType == textureInfo.storageType) &&
617 (frameIndex == textureInfo.frameIndex) &&
618 ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
619 (fittingMode == textureInfo.fittingMode &&
620 samplingMode == textureInfo.samplingMode)))
622 // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
623 // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
624 if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
626 // The found Texture is a match.
634 // Default to an invalid ID, in case we do not find a match.
635 return INVALID_CACHE_INDEX;
638 TextureCacheManager::TextureCacheIndex TextureCacheManager::AppendCache(const TextureCacheManager::TextureInfo& textureInfo)
640 // If we use EncodedImageBuffer, increase reference during it contains mTextureInfoContainer.
641 // This reference will be decreased when we call RemoveCache
642 if(textureInfo.url.GetProtocolType() == VisualUrl::BUFFER)
644 UseExternalResource(textureInfo.url);
647 TextureHash hash = textureInfo.hash;
648 TextureId id = textureInfo.textureId;
650 // Insert TextureHash container first
651 // Find exist list -or- Create new list.
652 std::vector<TextureId>& idList = mTextureHashContainer[hash];
653 // We already assume that list doesn't contain id. just emplace back
654 idList.emplace_back(id);
656 // Insert TextureInfo back of mTextureInfoContainer.
657 TextureCacheIndex cacheIndex = TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, mTextureInfoContainer.size());
658 mTextureInfoContainer.emplace_back(textureInfo);
660 // Add converter id --> cacheIndex
661 // NOTE : We should assume that id already generated by GenerateTextureId function.
662 mTextureIdConverter[id] = cacheIndex;
667 void TextureCacheManager::RemoveCache(TextureCacheManager::TextureInfo& textureInfo)
669 TextureCacheIndex textureInfoIndex = GetCacheIndexFromId(textureInfo.textureId);
670 bool removeTextureInfo = false;
672 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);
674 // Decrement the reference count and check if this is the last user of this Texture.
675 if(--textureInfo.referenceCount <= 0)
677 // This is the last remove for this Texture.
678 textureInfo.referenceCount = 0;
680 // If loaded, we can remove the TextureInfo and the Atlas (if atlased).
681 if(textureInfo.loadState == LoadState::UPLOADED)
683 if(textureInfo.atlas)
685 textureInfo.atlas.Remove(textureInfo.atlasRect);
687 removeTextureInfo = true;
689 else if(textureInfo.loadState == LoadState::LOADING)
691 // We mark the textureInfo for removal.
692 // Once the load has completed, this method will be called again.
693 textureInfo.loadState = LoadState::CANCELLED;
695 else if(textureInfo.loadState == LoadState::MASK_APPLYING)
697 // We mark the textureInfo for removal.
698 // Once the load has completed, this method will be called again.
699 textureInfo.loadState = LoadState::MASK_CANCELLED;
703 // In other states, we are not waiting for a load so we are safe to remove the TextureInfo data.
704 removeTextureInfo = true;
707 // If the state allows us to remove the TextureInfo data, we do so.
708 if(removeTextureInfo)
710 // If url location is BUFFER, decrease reference count of EncodedImageBuffer.
711 if(textureInfo.url.IsBufferResource())
713 RemoveEncodedImageBuffer(textureInfo.url.GetUrl());
716 // Permanently remove the textureInfo struct.
718 // Step 1. remove current textureId information in mTextureHashContainer.
719 RemoveHashId(textureInfo.hash, textureInfo.textureId);
720 // Step 2. make textureId is not using anymore. After this job, we can reuse textureId.
721 mTextureIdConverter.Remove(textureInfo.textureId);
725 // Post removal process to avoid mTextureInfoContainer reference problems.
726 if(removeTextureInfo)
728 // Step 3. swap last data of TextureInfoContainer, and pop_back.
729 RemoveTextureInfoByIndex(mTextureInfoContainer, textureInfoIndex);
733 void TextureCacheManager::RemoveHashId(const TextureCacheManager::TextureHash& textureHash, const TextureCacheManager::TextureId& textureId)
735 auto hashIterator = mTextureHashContainer.find(textureHash);
736 if(hashIterator != mTextureHashContainer.end())
738 auto hashIdList = hashIterator->second;
739 const auto& hashIdIterator = std::find(hashIdList.cbegin(), hashIdList.cend(), textureId);
740 if(hashIdIterator != hashIdList.cend())
742 hashIdList.erase(hashIdIterator);
743 if(hashIdList.size() == 0)
745 // If id list in current hash is empty, remove it self in the container.
746 mTextureHashContainer.erase(hashIterator);
752 } // namespace Internal
754 } // namespace Toolkit