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-manager-impl.h>
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/rendering/geometry.h>
29 #include <dali-toolkit/internal/texture-manager/texture-async-loading-helper.h>
30 #include <dali-toolkit/internal/texture-manager/texture-cache-manager.h>
31 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
32 #include <dali-toolkit/internal/visuals/rendering-addon.h>
36 constexpr auto INITIAL_HASH_NUMBER = size_t{0u};
38 constexpr auto TEXTURE_INDEX = 0u; ///< The Index for texture
39 constexpr auto MASK_TEXTURE_INDEX = 1u; ///< The Index for mask texture
49 // Define logfilter Internal namespace level so other files (e.g. texture-cache-manager.cpp) can also use this filter.
50 Debug::Filter* gTextureManagerLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TEXTURE_MANAGER");
53 #define GET_LOAD_STATE_STRING(loadState) \
54 loadState == TextureManagerType::LoadState::NOT_STARTED ? "NOT_STARTED" : \
55 loadState == TextureManagerType::LoadState::LOADING ? "LOADING" : \
56 loadState == TextureManagerType::LoadState::LOAD_FINISHED ? "LOAD_FINISHED" : \
57 loadState == TextureManagerType::LoadState::WAITING_FOR_MASK ? "WAITING_FOR_MASK" : \
58 loadState == TextureManagerType::LoadState::MASK_APPLYING ? "MASK_APPLYING" : \
59 loadState == TextureManagerType::LoadState::MASK_APPLIED ? "MASK_APPLIED" : \
60 loadState == TextureManagerType::LoadState::UPLOADED ? "UPLOADED" : \
61 loadState == TextureManagerType::LoadState::CANCELLED ? "CANCELLED" : \
62 loadState == TextureManagerType::LoadState::MASK_CANCELLED ? "MASK_CANCELLED" : \
63 loadState == TextureManagerType::LoadState::LOAD_FAILED ? "LOAD_FAILED" : \
70 const Vector4 FULL_ATLAS_RECT(0.0f, 0.0f, 1.0f, 1.0f); ///< UV Rectangle that covers the full Texture
72 void PreMultiply(Devel::PixelBuffer pixelBuffer, TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
74 if(Pixel::HasAlpha(pixelBuffer.GetPixelFormat()))
76 if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
78 pixelBuffer.MultiplyColorByAlpha();
83 preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
87 } // Anonymous namespace
89 TextureManager::MaskingData::MaskingData()
91 mAlphaMaskId(INVALID_TEXTURE_ID),
92 mContentScaleFactor(1.0f),
94 mPreappliedMasking(true),
95 mMaskImageLoadingFailed(false)
99 TextureManager::TextureManager(bool loadYuvPlanes)
100 : mTextureCacheManager(),
101 mAsyncLoader(std::unique_ptr<TextureAsyncLoadingHelper>(new TextureAsyncLoadingHelper(*this))),
102 mLifecycleObservers(),
104 mLoadingQueueTextureId(INVALID_TEXTURE_ID),
106 mLoadYuvPlanes(loadYuvPlanes),
107 mRemoveProcessorRegistered(false)
109 // Initialize the AddOn
110 RenderingAddOn::Get();
113 TextureManager::~TextureManager()
115 if(mRemoveProcessorRegistered && Adaptor::IsAvailable())
117 Adaptor::Get().UnregisterProcessor(*this, true);
118 mRemoveProcessorRegistered = false;
121 for(auto iter = mLifecycleObservers.Begin(), endIter = mLifecycleObservers.End(); iter != endIter; ++iter)
123 (*iter)->TextureManagerDestroyed();
127 TextureSet TextureManager::LoadAnimatedImageTexture(
128 const VisualUrl& url,
129 Dali::AnimatedImageLoading animatedImageLoading,
130 const uint32_t frameIndex,
131 TextureManager::TextureId& textureId,
132 MaskingDataPointer& maskInfo,
133 const Dali::ImageDimensions& desiredSize,
134 const Dali::FittingMode::Type fittingMode,
135 const Dali::SamplingMode::Type samplingMode,
136 const bool synchronousLoading,
137 TextureUploadObserver* textureObserver,
138 TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
140 TextureSet textureSet;
142 if(synchronousLoading)
144 Devel::PixelBuffer pixelBuffer;
145 if(animatedImageLoading)
147 pixelBuffer = animatedImageLoading.LoadFrame(frameIndex, desiredSize, fittingMode, samplingMode);
151 DALI_LOG_ERROR("TextureManager::LoadAnimatedImageTexture: Synchronous loading is failed\n");
156 if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
158 Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), desiredSize, fittingMode, samplingMode, true);
161 if(!maskInfo->mPreappliedMasking)
163 PixelData maskPixelData = Devel::PixelBuffer::Convert(maskPixelBuffer); // takes ownership of buffer
164 maskTexture = Texture::New(Dali::TextureType::TEXTURE_2D, maskPixelData.GetPixelFormat(), maskPixelData.GetWidth(), maskPixelData.GetHeight());
165 maskTexture.Upload(maskPixelData);
169 pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
174 DALI_LOG_ERROR("TextureManager::LoadAnimatedImageTexture: Synchronous mask image loading is failed\n");
178 if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
180 PreMultiply(pixelBuffer, preMultiplyOnLoad);
183 PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
186 Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
187 texture.Upload(pixelData);
188 textureSet = TextureSet::New();
189 textureSet.SetTexture(TEXTURE_INDEX, texture);
192 textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTexture);
199 TextureId alphaMaskId = INVALID_TEXTURE_ID;
200 float contentScaleFactor = 1.0f;
201 bool cropToMask = false;
202 if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
204 maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? TextureManager::StorageType::KEEP_PIXEL_BUFFER : TextureManager::StorageType::KEEP_TEXTURE);
205 alphaMaskId = maskInfo->mAlphaMaskId;
206 if(maskInfo->mPreappliedMasking)
208 contentScaleFactor = maskInfo->mContentScaleFactor;
209 cropToMask = maskInfo->mCropToMask;
213 textureId = RequestLoadInternal(url, alphaMaskId, textureId, contentScaleFactor, desiredSize, fittingMode, samplingMode, cropToMask, TextureManager::StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false);
215 TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
216 if(loadState == TextureManager::LoadState::UPLOADED)
218 // LoadComplete has already been called - keep the same texture set
219 textureSet = GetTextureSet(textureId);
226 Devel::PixelBuffer TextureManager::LoadPixelBuffer(
227 const VisualUrl& url,
228 const Dali::ImageDimensions& desiredSize,
229 const Dali::FittingMode::Type fittingMode,
230 const Dali::SamplingMode::Type samplingMode,
231 const bool synchronousLoading,
232 TextureUploadObserver* textureObserver,
233 const bool orientationCorrection,
234 TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
236 Devel::PixelBuffer pixelBuffer;
237 if(synchronousLoading)
241 if(url.IsBufferResource())
243 const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
244 if(encodedImageBuffer)
246 pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
251 pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
253 if(pixelBuffer && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
255 PreMultiply(pixelBuffer, preMultiplyOnLoad);
261 RequestLoadInternal(url, INVALID_TEXTURE_ID, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, false, TextureManager::StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
267 TextureSet TextureManager::LoadTexture(
268 const VisualUrl& url,
269 const Dali::ImageDimensions& desiredSize,
270 const Dali::FittingMode::Type fittingMode,
271 const Dali::SamplingMode::Type samplingMode,
272 MaskingDataPointer& maskInfo,
273 const bool synchronousLoading,
274 TextureManager::TextureId& textureId,
275 Vector4& textureRect,
276 Dali::ImageDimensions& textureRectSize,
277 bool& atlasingStatus,
279 TextureUploadObserver* textureObserver,
280 AtlasUploadObserver* atlasObserver,
281 ImageAtlasManagerPtr imageAtlasManager,
282 const bool orientationCorrection,
283 const TextureManager::ReloadPolicy reloadPolicy,
284 TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
286 TextureSet textureSet;
288 loadingStatus = false;
289 textureRect = FULL_ATLAS_RECT;
291 if(VisualUrl::TEXTURE == url.GetProtocolType())
293 std::string location = url.GetLocation();
294 if(location.size() > 0u)
296 TextureId id = std::stoi(location);
297 auto externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(id);
298 if(externalTextureInfo.textureSet)
300 if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
302 // Change preMultiplyOnLoad value so make caller determine to preMultiplyAlpha or not.
303 // TODO : Should we seperate input and output value?
304 preMultiplyOnLoad = externalTextureInfo.preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
307 TextureId alphaMaskId = INVALID_TEXTURE_ID;
308 if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
310 maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, TextureManager::StorageType::KEEP_TEXTURE, synchronousLoading);
311 alphaMaskId = maskInfo->mAlphaMaskId;
313 // Create new textureId. this textureId is not same as location
314 textureId = RequestLoad(url, alphaMaskId, textureId, 1.0f, desiredSize, fittingMode, samplingMode, false, textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad, synchronousLoading);
316 TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
317 if(loadState == TextureManager::LoadState::UPLOADED)
319 textureSet = GetTextureSet(textureId);
324 // TextureId is same as location
327 textureSet = TextureSet::New();
328 textureSet.SetTexture(TEXTURE_INDEX, externalTextureInfo.textureSet.GetTexture(TEXTURE_INDEX));
336 if(synchronousLoading && atlasingStatus)
338 const bool synchronousAtlasAvaliable = (desiredSize != ImageDimensions() || url.IsLocalResource()) ? imageAtlasManager->CheckAtlasAvailable(url, desiredSize)
340 if(synchronousAtlasAvaliable)
342 std::vector<Devel::PixelBuffer> pixelBuffers;
343 LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, false, pixelBuffers);
345 if(!pixelBuffers.empty() && maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
347 std::vector<Devel::PixelBuffer> maskPixelBuffers;
348 LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true, false, maskPixelBuffers);
349 if(!maskPixelBuffers.empty())
351 pixelBuffers[0].ApplyMask(maskPixelBuffers[0], maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
356 if(!pixelBuffers.empty())
358 PreMultiply(pixelBuffers[0], preMultiplyOnLoad);
359 data = Devel::PixelBuffer::Convert(pixelBuffers[0]); // takes ownership of buffer
363 textureSet = imageAtlasManager->Add(textureRect, data);
366 textureRectSize.SetWidth(data.GetWidth());
367 textureRectSize.SetHeight(data.GetHeight());
372 DALI_LOG_ERROR("TextureManager::LoadTexture: Synchronous Texture loading with atlasing is failed.\n");
377 atlasingStatus = false;
384 loadingStatus = true;
385 // Atlas manager can chage desired size when it is set by 0,0.
386 // We should store into textureRectSize only if atlasing successed.
387 // So copy inputed desiredSize, and replace value into textureRectSize only if atlasing success.
388 Dali::ImageDimensions atlasDesiredSize = desiredSize;
391 if(url.IsBufferResource())
393 const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl());
394 if(encodedImageBuffer)
396 textureSet = imageAtlasManager->Add(textureRect, encodedImageBuffer, desiredSize, fittingMode, true, atlasObserver);
401 textureSet = imageAtlasManager->Add(textureRect, url, atlasDesiredSize, fittingMode, true, atlasObserver);
404 if(!textureSet) // big image, no atlasing or atlasing failed
406 atlasingStatus = false;
408 TextureId alphaMaskId = INVALID_TEXTURE_ID;
409 float contentScaleFactor = 1.0f;
410 bool cropToMask = false;
411 if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
413 maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? TextureManager::StorageType::KEEP_PIXEL_BUFFER : TextureManager::StorageType::KEEP_TEXTURE, synchronousLoading);
414 alphaMaskId = maskInfo->mAlphaMaskId;
415 if(maskInfo && maskInfo->mPreappliedMasking)
417 contentScaleFactor = maskInfo->mContentScaleFactor;
418 cropToMask = maskInfo->mCropToMask;
422 textureId = RequestLoad(
432 orientationCorrection,
437 TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
438 if(loadState == TextureManager::LoadState::UPLOADED)
440 // LoadComplete has already been called - keep the same texture set
441 textureSet = GetTextureSet(textureId);
444 // If we are loading the texture, or waiting for the ready signal handler to complete, inform
445 // caller that they need to wait.
446 loadingStatus = (loadState == TextureManager::LoadState::LOADING ||
447 loadState == TextureManager::LoadState::WAITING_FOR_MASK ||
448 loadState == TextureManager::LoadState::MASK_APPLYING ||
449 loadState == TextureManager::LoadState::MASK_APPLIED ||
450 loadState == TextureManager::LoadState::NOT_STARTED ||
451 mLoadingQueueTextureId != INVALID_TEXTURE_ID);
455 textureRectSize = atlasDesiredSize;
460 if(synchronousLoading)
462 loadingStatus = false;
468 TextureManager::TextureId TextureManager::RequestLoad(
469 const VisualUrl& url,
470 const ImageDimensions& desiredSize,
471 const Dali::FittingMode::Type fittingMode,
472 const Dali::SamplingMode::Type samplingMode,
473 TextureUploadObserver* observer,
474 const bool orientationCorrection,
475 const TextureManager::ReloadPolicy reloadPolicy,
476 TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
477 const bool synchronousLoading)
479 return RequestLoadInternal(url, INVALID_TEXTURE_ID, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, false, TextureManager::StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
482 TextureManager::TextureId TextureManager::RequestLoad(
483 const VisualUrl& url,
484 const TextureManager::TextureId maskTextureId,
485 const TextureManager::TextureId previousTextureId,
486 const float contentScale,
487 const Dali::ImageDimensions& desiredSize,
488 const Dali::FittingMode::Type fittingMode,
489 const Dali::SamplingMode::Type samplingMode,
490 const bool cropToMask,
491 TextureUploadObserver* observer,
492 const bool orientationCorrection,
493 const TextureManager::ReloadPolicy reloadPolicy,
494 TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
495 const bool synchronousLoading)
497 return RequestLoadInternal(url, maskTextureId, previousTextureId, contentScale, desiredSize, fittingMode, samplingMode, cropToMask, TextureManager::StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
500 TextureManager::TextureId TextureManager::RequestMaskLoad(
501 const VisualUrl& maskUrl,
502 const TextureManager::StorageType storageType,
503 const bool synchronousLoading)
505 // Use the normal load procedure to get the alpha mask.
506 auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
507 return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), Dali::FittingMode::SCALE_TO_FILL, Dali::SamplingMode::NO_FILTER, false, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading);
510 TextureManager::TextureId TextureManager::RequestLoadInternal(
511 const VisualUrl& url,
512 const TextureManager::TextureId maskTextureId,
513 const TextureManager::TextureId previousTextureId,
514 const float contentScale,
515 const Dali::ImageDimensions& desiredSize,
516 const Dali::FittingMode::Type fittingMode,
517 const Dali::SamplingMode::Type samplingMode,
518 const bool cropToMask,
519 const TextureManager::StorageType storageType,
520 TextureUploadObserver* observer,
521 const bool orientationCorrection,
522 const TextureManager::ReloadPolicy reloadPolicy,
523 TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
524 Dali::AnimatedImageLoading animatedImageLoading,
525 const uint32_t frameIndex,
526 const bool synchronousLoading)
528 TextureHash textureHash = INITIAL_HASH_NUMBER;
529 TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
530 bool loadYuvPlanes = (mLoadYuvPlanes && maskTextureId == INVALID_TEXTURE_ID && storageType == TextureManager::StorageType::UPLOAD_TO_TEXTURE);
532 if(storageType != TextureManager::StorageType::RETURN_PIXEL_BUFFER)
534 textureHash = mTextureCacheManager.GenerateHash(url, desiredSize, fittingMode, samplingMode, maskTextureId, cropToMask, frameIndex);
536 // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
537 cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, storageType, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false, frameIndex);
540 TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
541 // Check if the requested Texture exists in the cache.
542 if(cacheIndex != INVALID_CACHE_INDEX)
544 if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || TextureManager::INVALID_TEXTURE_ID == previousTextureId)
546 // Mark this texture being used by another client resource, or Reload forced without request load before.
547 // Forced reload which have current texture before, would replace the current texture.
548 // without the need for incrementing the reference count.
549 ++(mTextureCacheManager[cacheIndex].referenceCount);
551 textureId = mTextureCacheManager[cacheIndex].textureId;
553 // Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info.
554 preMultiplyOnLoad = mTextureCacheManager[cacheIndex].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
555 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d, maskTextureId=%d, prevTextureId=%d, frameindex=%d, premultiplied=%d, refCount=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, previousTextureId, frameIndex, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0, static_cast<int>(mTextureCacheManager[cacheIndex].referenceCount));
558 if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
560 textureId = mTextureCacheManager.GenerateTextureId();
562 bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
564 // Cache new texutre, and get cacheIndex.
565 cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex, loadYuvPlanes));
566 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d, maskTextureId=%d, frameindex=%d premultiply=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, frameIndex, preMultiply);
569 // The below code path is common whether we are using the cache or not.
570 // The textureInfoIndex now refers to either a pre-existing cached TextureInfo,
571 // or a new TextureInfo just created.
572 TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
573 textureInfo.maskTextureId = maskTextureId;
574 textureInfo.storageType = storageType;
575 textureInfo.orientationCorrection = orientationCorrection;
577 // the case using external texture has already been loaded texture, so change its status to WAITING_FOR_MASK.
578 if(url.GetProtocolType() == VisualUrl::TEXTURE)
580 if(textureInfo.loadState != TextureManager::LoadState::UPLOADED)
582 textureInfo.preMultiplied = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
583 textureInfo.loadState = TextureManager::LoadState::WAITING_FOR_MASK;
587 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureInfo loadState:%s\n", GET_LOAD_STATE_STRING(textureInfo.loadState));
589 // Force reloading of texture by setting loadState unless already loading or cancelled.
590 if(TextureManager::ReloadPolicy::FORCED == reloadPolicy &&
591 TextureManager::LoadState::LOADING != textureInfo.loadState &&
592 TextureManager::LoadState::WAITING_FOR_MASK != textureInfo.loadState &&
593 TextureManager::LoadState::MASK_APPLYING != textureInfo.loadState &&
594 TextureManager::LoadState::MASK_APPLIED != textureInfo.loadState &&
595 TextureManager::LoadState::CANCELLED != textureInfo.loadState &&
596 TextureManager::LoadState::MASK_CANCELLED != textureInfo.loadState)
598 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d, maskTextureId=%d, prevTextureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, previousTextureId);
599 textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
602 if(!synchronousLoading)
604 // Check if we should add the observer.
605 // Only do this if we have not loaded yet and it will not have loaded by the end of this method.
606 switch(textureInfo.loadState)
608 case TextureManager::LoadState::LOAD_FAILED: // Failed notifies observer which then stops observing.
609 case TextureManager::LoadState::NOT_STARTED:
611 LoadOrQueueTexture(textureInfo, observer); // If called inside NotifyObservers, queues until afterwards
614 case TextureManager::LoadState::LOADING:
615 case TextureManager::LoadState::WAITING_FOR_MASK:
616 case TextureManager::LoadState::MASK_APPLYING:
617 case TextureManager::LoadState::MASK_APPLIED:
619 // Do not observe even we reload forced when texture is already loading state.
620 if(TextureManager::ReloadPolicy::CACHED == reloadPolicy || TextureManager::INVALID_TEXTURE_ID == previousTextureId)
622 ObserveTexture(textureInfo, observer);
626 case TextureManager::LoadState::UPLOADED:
630 LoadOrQueueTexture(textureInfo, observer);
634 case TextureManager::LoadState::CANCELLED:
636 // A cancelled texture hasn't finished loading yet. Treat as a loading texture
637 // (it's ref count has already been incremented, above)
638 textureInfo.loadState = TextureManager::LoadState::LOADING;
639 ObserveTexture(textureInfo, observer);
642 case TextureManager::LoadState::MASK_CANCELLED:
644 // A cancelled texture hasn't finished mask applying yet. Treat as a mask applying texture
645 // (it's ref count has already been incremented, above)
646 textureInfo.loadState = TextureManager::LoadState::MASK_APPLYING;
647 ObserveTexture(textureInfo, observer);
650 case TextureManager::LoadState::LOAD_FINISHED:
652 // Loading has already completed.
653 if(observer && textureInfo.storageType == TextureManager::StorageType::RETURN_PIXEL_BUFFER)
655 LoadOrQueueTexture(textureInfo, observer);
663 // If the image is already finished to load, use cached texture.
664 // We don't need to consider Observer because this is synchronous loading.
665 if(!(textureInfo.loadState == TextureManager::LoadState::UPLOADED ||
666 textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED))
668 if(url.GetProtocolType() == VisualUrl::TEXTURE)
670 // Get external textureSet from cacheManager.
671 std::string location = textureInfo.url.GetLocation();
672 if(!location.empty())
674 TextureId id = std::stoi(location);
675 auto externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(id);
676 textureInfo.textures.push_back(externalTextureInfo.textureSet.GetTexture(0));
677 textureInfo.loadState = TextureManager::LoadState::UPLOADED;
682 std::vector<Devel::PixelBuffer> pixelBuffers;
683 LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, loadYuvPlanes, pixelBuffers);
685 if(pixelBuffers.empty())
687 // If pixelBuffer loading is failed in synchronously, call RequestRemove() method.
688 RequestRemove(textureId, nullptr);
689 return INVALID_TEXTURE_ID;
692 if(storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER) // For the mask image loading.
694 textureInfo.pixelBuffer = pixelBuffers[0]; // Store the pixel data
695 textureInfo.loadState = TextureManager::LoadState::LOAD_FINISHED;
697 else // For the image loading.
700 if(maskTextureId != INVALID_TEXTURE_ID)
702 TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(maskTextureId);
703 if(maskCacheIndex != INVALID_CACHE_INDEX)
705 if(mTextureCacheManager[maskCacheIndex].storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER)
707 Devel::PixelBuffer maskPixelBuffer = mTextureCacheManager[maskCacheIndex].pixelBuffer;
710 pixelBuffers[0].ApplyMask(maskPixelBuffer, contentScale, cropToMask);
714 DALI_LOG_ERROR("Mask image cached invalid pixel buffer!\n");
720 DALI_LOG_ERROR("Mask image is not stored in cache.\n");
723 PreMultiply(pixelBuffers[0], preMultiplyOnLoad);
726 UploadTextures(pixelBuffers, textureInfo);
735 void TextureManager::RequestRemove(const TextureManager::TextureId textureId, TextureUploadObserver* observer)
737 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestRemove( textureId=%d observer=%p )\n", textureId, observer);
740 if(textureId != INVALID_TEXTURE_ID)
742 TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
743 if(textureCacheIndex != INVALID_CACHE_INDEX)
747 // Remove observer from cached texture info
748 TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]);
749 RemoveTextureObserver(textureInfo, observer);
752 mRemoveQueue.PushBack(textureId);
754 if(!mRemoveProcessorRegistered && Adaptor::IsAvailable())
756 mRemoveProcessorRegistered = true;
757 Adaptor::Get().RegisterProcessor(*this, true);
763 void TextureManager::Remove(const TextureManager::TextureId textureId)
765 if(textureId != INVALID_TEXTURE_ID)
767 TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
768 if(textureCacheIndex != INVALID_CACHE_INDEX)
770 TextureManager::TextureId maskTextureId = INVALID_TEXTURE_ID;
771 TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]);
772 // We only need to consider maskTextureId when texture's loadState is not cancelled. Because it is already deleted.
773 if(textureInfo.loadState != TextureManager::LoadState::CANCELLED && textureInfo.loadState != TextureManager::LoadState::MASK_CANCELLED)
775 if(textureInfo.maskTextureId != INVALID_TEXTURE_ID)
777 maskTextureId = textureInfo.maskTextureId;
781 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove( textureId=%d ) cacheIndex:%d removal maskTextureId=%d, loadState=%s\n", textureId, textureCacheIndex.GetIndex(), maskTextureId, GET_LOAD_STATE_STRING(textureInfo.loadState));
783 // Remove textureId in CacheManager. Now, textureInfo is invalidate.
784 mTextureCacheManager.RemoveCache(textureInfo);
786 // Remove maskTextureId in CacheManager
787 if(maskTextureId != INVALID_TEXTURE_ID)
789 TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(maskTextureId);
790 if(maskCacheIndex != INVALID_CACHE_INDEX)
792 TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
794 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Remove mask texture( maskTextureId=%d ) cacheIndex:%d, loadState=%s\n", maskTextureId, maskCacheIndex.GetIndex(), GET_LOAD_STATE_STRING(maskTextureInfo.loadState));
796 mTextureCacheManager.RemoveCache(maskTextureInfo);
803 void TextureManager::ProcessRemoveQueue()
805 // Note that RemoveQueue is not be changed during Remove().
806 for(auto&& textureId : mRemoveQueue)
808 if(textureId != INVALID_TEXTURE_ID)
813 mRemoveQueue.Clear();
816 void TextureManager::Process(bool postProcessor)
818 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::Process()\n");
820 ProcessRemoveQueue();
822 if(Adaptor::IsAvailable())
824 Adaptor::Get().UnregisterProcessor(*this, true);
825 mRemoveProcessorRegistered = false;
829 void TextureManager::LoadImageSynchronously(
830 const VisualUrl& url,
831 const Dali::ImageDimensions& desiredSize,
832 const Dali::FittingMode::Type fittingMode,
833 const Dali::SamplingMode::Type samplingMode,
834 const bool orientationCorrection,
835 const bool loadYuvPlanes,
836 std::vector<Devel::PixelBuffer>& pixelBuffers)
838 Devel::PixelBuffer pixelBuffer;
839 if(url.IsBufferResource())
841 const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
842 if(encodedImageBuffer)
844 pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
851 Dali::LoadImagePlanesFromFile(url.GetUrl(), pixelBuffers, desiredSize, fittingMode, samplingMode, orientationCorrection);
855 pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
861 pixelBuffers.push_back(pixelBuffer);
865 void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer)
867 // make sure an observer doesn't observe the same object twice
868 // otherwise it will get multiple calls to ObjectDestroyed()
869 DALI_ASSERT_DEBUG(mLifecycleObservers.End() == std::find(mLifecycleObservers.Begin(), mLifecycleObservers.End(), &observer));
870 mLifecycleObservers.PushBack(&observer);
873 void TextureManager::RemoveObserver(TextureManager::LifecycleObserver& observer)
875 // Find the observer...
876 auto endIter = mLifecycleObservers.End();
877 for(auto iter = mLifecycleObservers.Begin(); iter != endIter; ++iter)
879 if((*iter) == &observer)
881 mLifecycleObservers.Erase(iter);
885 DALI_ASSERT_DEBUG(endIter != mLifecycleObservers.End());
888 void TextureManager::LoadOrQueueTexture(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
890 switch(textureInfo.loadState)
892 case TextureManager::LoadState::NOT_STARTED:
893 case TextureManager::LoadState::LOAD_FAILED:
895 if(mLoadingQueueTextureId != INVALID_TEXTURE_ID)
897 QueueLoadTexture(textureInfo, observer);
901 LoadTexture(textureInfo, observer);
905 case TextureManager::LoadState::UPLOADED:
907 if(mLoadingQueueTextureId != INVALID_TEXTURE_ID)
909 QueueLoadTexture(textureInfo, observer);
913 // The Texture has already loaded. The other observers have already been notified.
914 // We need to send a "late" loaded notification for this observer.
917 EmitLoadComplete(observer, textureInfo, true);
922 case TextureManager::LoadState::LOADING:
923 case TextureManager::LoadState::CANCELLED:
924 case TextureManager::LoadState::MASK_CANCELLED:
925 case TextureManager::LoadState::LOAD_FINISHED:
926 case TextureManager::LoadState::WAITING_FOR_MASK:
927 case TextureManager::LoadState::MASK_APPLYING:
928 case TextureManager::LoadState::MASK_APPLIED:
935 void TextureManager::QueueLoadTexture(const TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
937 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Add observer to observer queue (textureId:%d, observer:%p)\n", textureInfo.textureId, observer);
939 const auto& textureId = textureInfo.textureId;
940 mLoadQueue.PushBack(QueueElement(textureId, observer));
944 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Connect DestructionSignal to observer:%p\n", observer);
945 observer->DestructionSignal().Connect(this, &TextureManager::ObserverDestroyed);
949 void TextureManager::LoadTexture(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
951 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::LoadTexture(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F");
952 textureInfo.loadState = TextureManager::LoadState::LOADING;
953 if(!textureInfo.loadSynchronously)
955 auto premultiplyOnLoad = (textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID) ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
956 if(textureInfo.animatedImageLoading)
958 mAsyncLoader->LoadAnimatedImage(textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, premultiplyOnLoad);
962 mAsyncLoader->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, textureInfo.orientationCorrection, premultiplyOnLoad, textureInfo.loadYuvPlanes);
965 ObserveTexture(textureInfo, observer);
968 void TextureManager::ProcessLoadQueue()
970 for(auto&& element : mLoadQueue)
972 if(element.mTextureId == INVALID_TEXTURE_ID)
977 TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(element.mTextureId);
978 if(cacheIndex != INVALID_CACHE_INDEX)
980 TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
982 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::ProcessLoadQueue() textureId=%d, observer=%p, cacheIndex=@%d, loadState:%s\n", element.mTextureId, element.mObserver, cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState));
984 if((textureInfo.loadState == TextureManager::LoadState::UPLOADED) ||
985 (textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED &&
986 textureInfo.storageType == TextureManager::StorageType::RETURN_PIXEL_BUFFER))
988 if(element.mObserver)
990 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", element.mObserver);
991 element.mObserver->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
993 EmitLoadComplete(element.mObserver, textureInfo, true);
996 else if(textureInfo.loadState == TextureManager::LoadState::LOADING)
998 // Note : LOADING state texture cannot be queue.
999 // This case be occured when same texture id are queue in mLoadQueue.
1000 ObserveTexture(textureInfo, element.mObserver);
1004 LoadTexture(textureInfo, element.mObserver);
1011 void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo,
1012 TextureUploadObserver* observer)
1014 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::ObserveTexture(): url:%s observer:%p\n", textureInfo.url.GetUrl().c_str(), observer);
1018 textureInfo.observerList.PushBack(observer);
1020 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Connect DestructionSignal to observer:%p\n", observer);
1021 observer->DestructionSignal().Connect(this, &TextureManager::ObserverDestroyed);
1025 void TextureManager::AsyncLoadComplete(const TextureManager::TextureId textureId, std::vector<Devel::PixelBuffer>& pixelBuffers)
1027 TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
1028 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d CacheIndex:%d )\n", textureId, cacheIndex.GetIndex());
1029 if(cacheIndex != INVALID_CACHE_INDEX)
1031 TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
1033 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));
1034 if(textureInfo.loadState != TextureManager::LoadState::CANCELLED && textureInfo.loadState != TextureManager::LoadState::MASK_CANCELLED)
1036 // textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified)
1037 PostLoad(textureInfo, pixelBuffers);
1041 Remove(textureInfo.textureId);
1046 void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, std::vector<Devel::PixelBuffer>& pixelBuffers)
1048 if(!pixelBuffers.empty()) ///< Load success
1050 if(pixelBuffers.size() == 1)
1052 Devel::PixelBuffer pixelBuffer = pixelBuffers[0];
1053 if(pixelBuffer && (pixelBuffer.GetWidth() != 0) && (pixelBuffer.GetHeight() != 0))
1055 textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied();
1057 if(textureInfo.storageType == TextureManager::StorageType::UPLOAD_TO_TEXTURE)
1059 // If there is a mask texture ID associated with this texture, then apply the mask
1060 // if it's already loaded. If it hasn't, and the mask is still loading,
1061 // wait for the mask to finish loading.
1062 // note, If the texture is already uploaded synchronously during loading,
1063 // we don't need to apply mask.
1064 if(textureInfo.loadState != TextureManager::LoadState::UPLOADED &&
1065 textureInfo.maskTextureId != INVALID_TEXTURE_ID)
1067 if(textureInfo.loadState == TextureManager::LoadState::MASK_APPLYING)
1069 textureInfo.loadState = TextureManager::LoadState::MASK_APPLIED;
1070 UploadTextures(pixelBuffers, textureInfo);
1071 NotifyObservers(textureInfo, true);
1075 LoadState maskLoadState = mTextureCacheManager.GetTextureStateInternal(textureInfo.maskTextureId);
1076 textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
1077 if(maskLoadState == TextureManager::LoadState::LOADING)
1079 textureInfo.loadState = TextureManager::LoadState::WAITING_FOR_MASK;
1081 else if(maskLoadState == TextureManager::LoadState::LOAD_FINISHED || maskLoadState == TextureManager::LoadState::UPLOADED)
1083 TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId);
1084 if(maskCacheIndex != INVALID_CACHE_INDEX)
1086 TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
1087 if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER)
1089 ApplyMask(textureInfo, textureInfo.maskTextureId);
1091 else if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
1093 // Upload image texture. textureInfo.loadState will be UPLOADED.
1094 UploadTextures(pixelBuffers, textureInfo);
1096 // notify mask texture set.
1097 NotifyObservers(textureInfo, true);
1101 else // maskLoadState == TextureManager::LoadState::LOAD_FAILED
1103 // Url texture load success, But alpha mask texture load failed. Run as normal image upload.
1104 DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n");
1105 UploadTextures(pixelBuffers, textureInfo);
1106 NotifyObservers(textureInfo, true);
1112 UploadTextures(pixelBuffers, textureInfo);
1113 NotifyObservers(textureInfo, true);
1118 textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data
1119 textureInfo.loadState = TextureManager::LoadState::LOAD_FINISHED;
1121 if(textureInfo.storageType == TextureManager::StorageType::RETURN_PIXEL_BUFFER)
1123 NotifyObservers(textureInfo, true);
1125 else // for the TextureManager::StorageType::KEEP_PIXEL_BUFFER and TextureManager::StorageType::KEEP_TEXTURE
1127 // Check if there was another texture waiting for this load to complete
1128 // (e.g. if this was an image mask, and its load is on a different thread)
1129 CheckForWaitingTexture(textureInfo);
1137 textureInfo.preMultiplied = false;
1139 UploadTextures(pixelBuffers, textureInfo);
1140 NotifyObservers(textureInfo, true);
1145 textureInfo.loadState = TextureManager::LoadState::LOAD_FAILED;
1146 if(textureInfo.storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER || textureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
1148 // Check if there was another texture waiting for this load to complete
1149 // (e.g. if this was an image mask, and its load is on a different thread)
1150 CheckForWaitingTexture(textureInfo);
1154 NotifyObservers(textureInfo, false);
1159 void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTextureInfo)
1161 if(maskTextureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED &&
1162 maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
1164 // Upload mask texture. textureInfo.loadState will be UPLOADED.
1165 std::vector<Devel::PixelBuffer> pixelBuffers;
1166 pixelBuffers.push_back(maskTextureInfo.pixelBuffer);
1167 UploadTextures(pixelBuffers, maskTextureInfo);
1170 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::CheckForWaitingTexture(): maskTextureId=%d, maskTextureUrl=%s\n", maskTextureInfo.textureId, maskTextureInfo.url.GetUrl().c_str());
1172 // Search the cache, checking if any texture has this texture id as a maskTextureId
1173 const size_t size = mTextureCacheManager.size();
1175 // Keep notify observer required textureIds.
1176 // Note : NotifyObservers can change mTextureCacheManager cache struct. We should check id's validation before notify.
1177 std::vector<TextureId> notifyRequiredTextureIds;
1179 // TODO : Refactorize here to not iterate whole cached image.
1180 for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
1182 if(mTextureCacheManager[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
1183 mTextureCacheManager[cacheIndex].loadState == TextureManager::LoadState::WAITING_FOR_MASK)
1185 TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
1187 if(maskTextureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED)
1189 if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_PIXEL_BUFFER)
1191 ApplyMask(textureInfo, maskTextureInfo.textureId);
1194 else if(maskTextureInfo.loadState == TextureManager::LoadState::UPLOADED)
1196 if(maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
1198 if(textureInfo.url.GetProtocolType() == VisualUrl::TEXTURE)
1200 // Get external textureSet from cacheManager.
1201 std::string location = textureInfo.url.GetLocation();
1202 if(!location.empty())
1204 TextureId id = std::stoi(location);
1205 auto externalTextureInfo = mTextureCacheManager.GetExternalTextureInfo(id);
1206 textureInfo.textures.push_back(externalTextureInfo.textureSet.GetTexture(0));
1207 textureInfo.loadState = TextureManager::LoadState::UPLOADED;
1212 // Upload image texture. textureInfo.loadState will be UPLOADED.
1213 std::vector<Devel::PixelBuffer> pixelBuffers;
1214 pixelBuffers.push_back(textureInfo.pixelBuffer);
1215 UploadTextures(pixelBuffers, textureInfo);
1218 // Increase reference counts for notify required textureId.
1219 // Now we can assume that we don't remove & re-assign this textureId
1220 // during NotifyObserver signal emit.
1221 maskTextureInfo.referenceCount++;
1222 textureInfo.referenceCount++;
1224 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::CheckForWaitingTexture(): Ready to notify textureId=%d\n", textureInfo.textureId);
1226 notifyRequiredTextureIds.push_back(textureInfo.textureId);
1229 else // maskTextureInfo.loadState == TextureManager::LoadState::LOAD_FAILED
1231 // Url texture load success, But alpha mask texture load failed. Run as normal image upload.
1232 DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n");
1233 std::vector<Devel::PixelBuffer> pixelBuffers;
1234 pixelBuffers.push_back(textureInfo.pixelBuffer);
1235 UploadTextures(pixelBuffers, textureInfo);
1237 // Increase reference counts for notify required textureId.
1238 // Now we can assume that we don't remove & re-assign this textureId
1239 // during NotifyObserver signal emit.
1240 maskTextureInfo.referenceCount++;
1241 textureInfo.referenceCount++;
1243 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::CheckForWaitingTexture(): Ready to notify textureId=%d\n", textureInfo.textureId);
1245 notifyRequiredTextureIds.push_back(textureInfo.textureId);
1250 // Notify textures are masked
1251 for(const auto textureId : notifyRequiredTextureIds)
1253 TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
1254 if(textureCacheIndex != INVALID_CACHE_INDEX)
1256 TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]);
1257 NotifyObservers(textureInfo, true);
1261 // Decrease reference count
1262 for(const auto textureId : notifyRequiredTextureIds)
1264 RequestRemove(textureId, nullptr);
1268 void TextureManager::ApplyMask(TextureManager::TextureInfo& textureInfo, const TextureManager::TextureId maskTextureId)
1270 TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(maskTextureId);
1271 if(maskCacheIndex != INVALID_CACHE_INDEX)
1273 Devel::PixelBuffer maskPixelBuffer = mTextureCacheManager[maskCacheIndex].pixelBuffer;
1274 Devel::PixelBuffer pixelBuffer = textureInfo.pixelBuffer;
1275 textureInfo.pixelBuffer.Reset();
1277 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F");
1279 textureInfo.loadState = TextureManager::LoadState::MASK_APPLYING;
1280 auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
1281 mAsyncLoader->ApplyMask(textureInfo.textureId, pixelBuffer, maskPixelBuffer, textureInfo.scaleFactor, textureInfo.cropToMask, premultiplyOnLoad);
1285 void TextureManager::UploadTextures(std::vector<Devel::PixelBuffer>& pixelBuffers, TextureManager::TextureInfo& textureInfo)
1287 if(!pixelBuffers.empty() && textureInfo.loadState != TextureManager::LoadState::UPLOADED)
1289 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTextures() New Texture for textureId:%d\n", textureInfo.textureId);
1291 // Check if this pixelBuffer is premultiplied
1292 textureInfo.preMultiplied = pixelBuffers[0].IsAlphaPreMultiplied();
1294 auto& renderingAddOn = RenderingAddOn::Get();
1295 if(renderingAddOn.IsValid())
1297 renderingAddOn.CreateGeometry(textureInfo.textureId, pixelBuffers[0]);
1300 // Remove previous textures and insert new textures
1301 textureInfo.textures.clear();
1303 for(auto&& pixelBuffer : pixelBuffers)
1305 Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
1306 PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
1307 texture.Upload(pixelData);
1308 textureInfo.textures.push_back(texture);
1312 // Update the load state.
1313 // Note: This is regardless of success as we care about whether a
1314 // load attempt is in progress or not. If unsuccessful, a broken
1315 // image is still loaded.
1316 textureInfo.loadState = TextureManager::LoadState::UPLOADED;
1319 void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, const bool success)
1321 TextureId textureId = textureInfo.textureId;
1323 // If there is an observer: Notify the load is complete, whether successful or not,
1324 // and erase it from the list
1325 TextureInfo* info = &textureInfo;
1327 if(info->animatedImageLoading)
1329 // If loading failed, we don't need to get frameCount and frameInterval.
1332 info->frameCount = info->animatedImageLoading.GetImageCount();
1333 info->frameInterval = info->animatedImageLoading.GetFrameInterval(info->frameIndex);
1335 info->animatedImageLoading.Reset();
1338 mLoadingQueueTextureId = textureId;
1340 // Reverse observer list that we can pop_back the observer.
1341 std::reverse(info->observerList.Begin(), info->observerList.End());
1343 while(info->observerList.Count())
1345 TextureUploadObserver* observer = *(info->observerList.End() - 1u);
1347 // During LoadComplete() a Control ResourceReady() signal is emitted.
1348 // During that signal the app may add remove /add Textures (e.g. via
1350 // It is possible for observers to be removed from the observer list,
1351 // and it is also possible for the mTextureInfoContainer to be modified,
1352 // invalidating the reference to the textureInfo struct.
1353 // Texture load requests for the same URL are deferred until the end of this
1355 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() observer:%p textureId:%d url:%s loadState:%s\n", observer, textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState));
1356 // It is possible for the observer to be deleted.
1357 // Disconnect and remove the observer first.
1358 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer);
1359 observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
1361 info->observerList.Erase(info->observerList.End() - 1u);
1363 EmitLoadComplete(observer, *info, success);
1365 // Get the textureInfo from the container again as it may have been invalidated.
1366 TextureCacheIndex textureInfoIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
1367 if(textureInfoIndex == INVALID_CACHE_INDEX)
1369 break; // texture has been removed - can stop.
1371 info = &mTextureCacheManager[textureInfoIndex];
1374 mLoadingQueueTextureId = INVALID_TEXTURE_ID;
1377 if(info->storageType == TextureManager::StorageType::RETURN_PIXEL_BUFFER && info->observerList.Count() == 0)
1379 RequestRemove(info->textureId, nullptr);
1383 void TextureManager::ObserverDestroyed(TextureUploadObserver* observer)
1385 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::ObserverDestroyed() observer:%p\n", observer);
1387 const std::size_t size = mTextureCacheManager.size();
1388 for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
1390 TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
1391 for(TextureInfo::ObserverListType::Iterator j = textureInfo.observerList.Begin();
1392 j != textureInfo.observerList.End();)
1396 j = textureInfo.observerList.Erase(j);
1405 // Remove element from the LoadQueue
1406 for(auto&& element : mLoadQueue)
1408 if(element.mObserver == observer)
1410 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Remove observer from observer queue (textureId:%d, observer:%p)\n", element.mTextureId, element.mObserver);
1411 element.mTextureId = INVALID_TEXTURE_ID;
1412 element.mObserver = nullptr;
1417 Dali::Geometry TextureManager::GetRenderGeometry(const TextureManager::TextureId textureId, uint32_t& frontElements, uint32_t& backElements)
1419 return RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().GetGeometry(textureId, frontElements, backElements) : Geometry();
1422 void TextureManager::EmitLoadComplete(TextureUploadObserver* observer, TextureManager::TextureInfo& textureInfo, const bool success)
1424 if(textureInfo.storageType == TextureManager::StorageType::RETURN_PIXEL_BUFFER)
1426 observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::PIXEL_BUFFER, textureInfo.pixelBuffer, textureInfo.url.GetUrl(), textureInfo.preMultiplied));
1430 TextureSet textureSet = GetTextureSet(textureInfo);
1431 if(textureInfo.isAnimatedImageFormat)
1433 observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::ANIMATED_IMAGE_TEXTURE, textureInfo.textureId, textureSet, textureInfo.frameCount, textureInfo.frameInterval));
1437 observer->LoadComplete(success, TextureUploadObserver::TextureInformation(TextureUploadObserver::ReturnType::TEXTURE, textureInfo.textureId, textureSet, textureInfo.preMultiplied));
1442 TextureSet TextureManager::GetTextureSet(const TextureManager::TextureId textureId)
1444 TextureSet textureSet;
1445 TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
1446 if(loadState == TextureManager::LoadState::UPLOADED)
1448 TextureCacheIndex textureCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
1449 if(textureCacheIndex != INVALID_CACHE_INDEX)
1451 TextureInfo& textureInfo(mTextureCacheManager[textureCacheIndex]);
1452 textureSet = GetTextureSet(textureInfo);
1457 DALI_LOG_ERROR("GetTextureSet is failed. texture is not uploaded \n");
1462 TextureSet TextureManager::GetTextureSet(const TextureManager::TextureInfo& textureInfo)
1464 TextureSet textureSet;
1466 // Always create new TextureSet here, so we don't share same TextureSets for multiple visuals.
1467 textureSet = TextureSet::New();
1469 if(!textureInfo.textures.empty())
1471 if(textureInfo.textures.size() > 1) // For YUV case
1473 uint32_t index = 0u;
1474 for(auto&& texture : textureInfo.textures)
1476 textureSet.SetTexture(index++, texture);
1481 textureSet.SetTexture(TEXTURE_INDEX, textureInfo.textures[0]);
1482 TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId);
1483 if(maskCacheIndex != INVALID_CACHE_INDEX)
1485 TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
1486 if(maskTextureInfo.storageType == TextureManager::StorageType::UPLOAD_TO_TEXTURE || maskTextureInfo.storageType == TextureManager::StorageType::KEEP_TEXTURE)
1488 if(!maskTextureInfo.textures.empty())
1490 textureSet.SetTexture(MASK_TEXTURE_INDEX, maskTextureInfo.textures[0]);
1499 void TextureManager::RemoveTextureObserver(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
1503 const auto iterEnd = textureInfo.observerList.End();
1504 const auto iter = std::find(textureInfo.observerList.Begin(), iterEnd, observer);
1507 // Disconnect and remove the observer.
1508 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer);
1509 observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
1510 textureInfo.observerList.Erase(iter);
1514 // Given textureId might exist at load queue.
1515 // Remove observer from the LoadQueue
1516 for(auto&& element : mLoadQueue)
1518 if(element.mTextureId == textureInfo.textureId && element.mObserver == observer)
1520 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "Remove observer from observer queue (textureId:%d, observer:%p)\n", element.mTextureId, element.mObserver);
1521 DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, " Disconnect DestructionSignal to observer:%p\n", observer);
1522 observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
1523 element.mObserver = nullptr;
1531 } // namespace Internal
1533 } // namespace Toolkit