X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fanimated-image%2Frolling-animated-image-cache.cpp;h=bd6c5a70a807991b550dd1d409bcd71a308cf3d7;hp=490c3bebda0548d0648d60b7519be13d7b88e9c9;hb=2bba756a645043d8c1c4023a75966401d531827c;hpb=88ff99f30ef65a6a9b5f5d3ab03a6da247a976dc diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp index 490c3be..bd6c5a7 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,6 @@ // CLASS HEADER #include "rolling-animated-image-cache.h" -// EXTERNAL HEADERS - // INTERNAL HEADERS #include #include // For ImageAtlasManagerPtr @@ -29,23 +27,24 @@ namespace #if defined(DEBUG_ENABLED) Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE"); -#define LOG_CACHE \ - { \ - std::ostringstream oss; \ - oss << "Size:" << mQueue.Count() << " [ "; \ - for(std::size_t _i = 0; _i < mQueue.Count(); ++_i) \ - { \ - oss << _i << "={ frm#: " << mQueue[_i].mFrameNumber << " tex: " << mImageUrls[mQueue[_i].mFrameNumber].mTextureId << "}, "; \ - } \ - oss << " ]" << std::endl; \ - DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "%s", oss.str().c_str()); \ +#define LOG_CACHE \ + if(gAnimImgLogFilter->IsEnabledFor(Debug::Concise)) \ + { \ + std::ostringstream oss; \ + oss << "Size:" << mQueue.Count() << " [ "; \ + for(std::size_t _i = 0; _i < mQueue.Count(); ++_i) \ + { \ + oss << _i << "={ frm#: " << mQueue[_i].mFrameNumber << " tex: " << mTextureIds[mQueue[_i].mFrameNumber] << "}, "; \ + } \ + oss << " ]" << std::endl; \ + DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "%s", oss.str().c_str()); \ } #else #define LOG_CACHE #endif -const bool ENABLE_ORIENTATION_CORRECTION(true); +static constexpr bool ENABLE_ORIENTATION_CORRECTION(true); } // namespace @@ -55,32 +54,42 @@ namespace Toolkit { namespace Internal { -RollingAnimatedImageCache::RollingAnimatedImageCache( - TextureManager& textureManager, AnimatedImageLoading& animatedImageLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize, bool isSynchronousLoading) -: ImageCache(textureManager, observer, batchSize), +namespace +{ +static constexpr uint32_t SINGLE_IMAGE_COUNT = 1u; +static constexpr uint32_t FIRST_FRAME_INDEX = 0u; +} // namespace + +RollingAnimatedImageCache::RollingAnimatedImageCache(TextureManager& textureManager, + AnimatedImageLoading& animatedImageLoading, + TextureManager::MaskingDataPointer& maskingData, + ImageCache::FrameReadyObserver& observer, + uint16_t cacheSize, + uint16_t batchSize, + const Dali::WrapMode::Type& wrapModeU, + const Dali::WrapMode::Type& wrapModeV, + bool isSynchronousLoading, + bool preMultiplyOnLoad) +: ImageCache(textureManager, maskingData, observer, batchSize, 0u), + mImageUrl(animatedImageLoading.GetUrl()), mAnimatedImageLoading(animatedImageLoading), - mFrameCount(frameCount), - mFrameIndex(0), + mFrameCount(SINGLE_IMAGE_COUNT), + mFrameIndex(FIRST_FRAME_INDEX), mCacheSize(cacheSize), mQueue(cacheSize), + mWrapModeU(wrapModeU), + mWrapModeV(wrapModeV), mIsSynchronousLoading(isSynchronousLoading), - mOnLoading(false) + mPreMultiplyOnLoad(preMultiplyOnLoad) { - mImageUrls.resize(mFrameCount); + mTextureIds.resize(mFrameCount); mIntervals.assign(mFrameCount, 0); - LoadBatch(); } RollingAnimatedImageCache::~RollingAnimatedImageCache() { - if(mTextureManagerAlive) - { - while(!mQueue.IsEmpty()) - { - ImageFrame imageFrame = mQueue.PopFront(); - mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this); - } - } + ClearCache(); + mAnimatedImageLoading.Reset(); } TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex) @@ -88,60 +97,58 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex) bool popExist = false; while(!mQueue.IsEmpty() && mQueue.Front().mFrameNumber != frameIndex) { - ImageFrame imageFrame = mQueue.PopFront(); - mTextureManager.Remove(mImageUrls[imageFrame.mFrameNumber].mTextureId, this); - mImageUrls[imageFrame.mFrameNumber].mTextureId = TextureManager::INVALID_TEXTURE_ID; - popExist = true; + PopFrontCache(); + popExist = true; } TextureSet textureSet; + uint32_t batchFrameIndex = frameIndex; // If we need to load new frame that are not stored in queue. // Load the frame synchronously. + bool synchronouslyLoaded = false; if(mIsSynchronousLoading && mQueue.IsEmpty()) { - bool synchronousLoading = true; - textureSet = mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading, frameIndex, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, mImageUrls[frameIndex].mTextureId, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this); - mFrameIndex = (frameIndex + 1) % mFrameCount; + textureSet = RequestFrameLoading(frameIndex, true); + batchFrameIndex = (frameIndex + 1) % mFrameCount; + uint32_t interval = 0u; + if(textureSet) + { + synchronouslyLoaded = true; + interval = mAnimatedImageLoading.GetFrameInterval(mQueue.Back().mFrameNumber); + } + MakeFrameReady(synchronouslyLoaded, textureSet, interval); } - if(popExist || mQueue.IsEmpty()) + if(popExist || mQueue.IsEmpty() || synchronouslyLoaded) { // If the frame of frameIndex was already loaded, load batch from the last frame of queue if(!mQueue.IsEmpty()) { if(!mLoadWaitingQueue.empty()) { - mFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount; + batchFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount; } else { - mFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount; + batchFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount; } } else { - mOnLoading = false; // If the request is for the first frame or a jumped frame(JUMP_TO) remove current waiting queue. mLoadWaitingQueue.clear(); // If the queue is empty, and the frame of frameIndex is not loaded synchronously. load batch from the frame of frameIndex if(!textureSet) { - mFrameIndex = frameIndex; + batchFrameIndex = frameIndex; } } - LoadBatch(); + LoadBatch(batchFrameIndex); } - if(!textureSet) + if(!textureSet && mLoadState != TextureManager::LoadState::LOAD_FAILED && IsFrontReady() == true) { - if(IsFrontReady() == true) - { - textureSet = GetFrontTextureSet(); - } - else - { - mWaitingForReadyFrame = true; - } + textureSet = GetFrontTextureSet(); } return textureSet; @@ -149,32 +156,17 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex) TextureSet RollingAnimatedImageCache::FirstFrame() { - return Frame(0u); -} - -TextureSet RollingAnimatedImageCache::NextFrame() -{ - TextureSet textureSet; - if(!mQueue.IsEmpty()) - { - uint32_t frameIndex = mQueue.Front().mFrameNumber; - if(IsFrontReady()) - { - frameIndex = (frameIndex + 1) % mFrameCount; - } - textureSet = Frame(frameIndex); - } - else - { - DALI_LOG_ERROR("Cache is empty."); - } - + TextureSet textureSet = Frame(FIRST_FRAME_INDEX); return textureSet; } uint32_t RollingAnimatedImageCache::GetFrameInterval(uint32_t frameIndex) const { - return mAnimatedImageLoading.GetFrameInterval(frameIndex); + if(frameIndex >= mIntervals.size()) + { + return 0u; + } + return mIntervals[frameIndex]; } int32_t RollingAnimatedImageCache::GetCurrentFrameIndex() const @@ -196,7 +188,7 @@ bool RollingAnimatedImageCache::IsFrontReady() const return (!mQueue.IsEmpty() && mQueue.Front().mReady); } -void RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex) +TextureSet RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex, bool synchronousLoading) { ImageFrame imageFrame; imageFrame.mFrameNumber = frameIndex; @@ -204,39 +196,54 @@ void RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex) mQueue.PushBack(imageFrame); - mRequestingLoad = true; + mLoadState = TextureManager::LoadState::LOADING; + + auto preMultiplyOnLoading = mPreMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD + : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + + TextureManager::TextureId loadTextureId = TextureManager::INVALID_TEXTURE_ID; + TextureSet textureSet = mTextureManager.LoadAnimatedImageTexture(mImageUrl, + mAnimatedImageLoading, + frameIndex, + loadTextureId, + mMaskingData, + SamplingMode::BOX_THEN_LINEAR, + synchronousLoading, + this, + preMultiplyOnLoading); + if(textureSet) + { + Sampler sampler = Sampler::New(); + sampler.SetWrapMode(mWrapModeU, mWrapModeV); + textureSet.SetSampler(0u, sampler); + } - bool synchronousLoading = false; - mTextureManager.LoadAnimatedImageTexture(mAnimatedImageLoading, frameIndex, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, mImageUrls[frameIndex].mTextureId, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this); + mTextureIds[frameIndex] = loadTextureId; - mRequestingLoad = false; + return textureSet; } -void RollingAnimatedImageCache::LoadBatch() +void RollingAnimatedImageCache::LoadBatch(uint32_t frameIndex) { // Try and load up to mBatchSize images, until the cache is filled. // Once the cache is filled, as frames progress, the old frame is // removed, and another frame is loaded - - bool frontFrameReady = IsFrontReady(); - for(unsigned int i = 0; i < mBatchSize && mQueue.Count() + mLoadWaitingQueue.size() < static_cast(mCacheSize) && !mQueue.IsFull(); ++i) + uint32_t minimumSize = std::min(mCacheSize, mFrameCount); + for(uint32_t i = 0; i < mBatchSize && (mQueue.Count() + mLoadWaitingQueue.size()) < minimumSize; ++i) { - if(!mOnLoading) + if(mLoadState != TextureManager::LoadState::LOADING) { - mOnLoading = true; - RequestFrameLoading(mFrameIndex); + RequestFrameLoading(frameIndex, false); } else { - mLoadWaitingQueue.push_back(mFrameIndex); + mLoadWaitingQueue.push_back(frameIndex); } - mFrameIndex++; - mFrameIndex %= mFrameCount; + frameIndex++; + frameIndex %= mFrameCount; } - CheckFrontFrame(frontFrameReady); - LOG_CACHE; } @@ -257,54 +264,119 @@ TextureSet RollingAnimatedImageCache::GetFrontTextureSet() const DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "RollingAnimatedImageCache::GetFrontTextureSet() FrameNumber:%d\n", mQueue[0].mFrameNumber); TextureManager::TextureId textureId = GetCachedTextureId(0); - return mTextureManager.GetTextureSet(textureId); + TextureSet textureSet = mTextureManager.GetTextureSet(textureId); + if(textureSet) + { + Sampler sampler = Sampler::New(); + sampler.SetWrapMode(mWrapModeU, mWrapModeV); + textureSet.SetSampler(0u, sampler); + } + return textureSet; } TextureManager::TextureId RollingAnimatedImageCache::GetCachedTextureId(int index) const { - return mImageUrls[mQueue[index].mFrameNumber].mTextureId; + return mTextureIds[mQueue[index].mFrameNumber]; } -void RollingAnimatedImageCache::CheckFrontFrame(bool wasReady) +void RollingAnimatedImageCache::PopFrontCache() { - if(mWaitingForReadyFrame && wasReady == false && IsFrontReady()) + ImageFrame imageFrame = mQueue.PopFront(); + mTextureManager.Remove(mTextureIds[imageFrame.mFrameNumber], this); + mTextureIds[imageFrame.mFrameNumber] = TextureManager::INVALID_TEXTURE_ID; + + if(mMaskingData && mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID) { - mWaitingForReadyFrame = false; - mObserver.FrameReady(GetFrontTextureSet()); + if(mQueue.IsEmpty()) + { + mMaskingData->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID; + } } } -void RollingAnimatedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation) +void RollingAnimatedImageCache::ClearCache() { - DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId); - LOG_CACHE; - - bool frontFrameReady = IsFrontReady(); - - if(!mRequestingLoad) + while(mTextureManagerAlive && !mQueue.IsEmpty()) { - SetImageFrameReady(textureInformation.textureId); + PopFrontCache(); + } + mLoadWaitingQueue.clear(); + mLoadState = TextureManager::LoadState::NOT_STARTED; +} - CheckFrontFrame(frontFrameReady); +void RollingAnimatedImageCache::MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval) +{ + if(!loadSuccess) + { + mLoadState = TextureManager::LoadState::LOAD_FAILED; + mObserver.FrameReady(TextureSet(), 0); } else { - // LoadComplete has been called from within RequestLoad. TextureManager must - // therefore already have the texture cached, so make the texture ready. - // (Use the last texture, as the texture id hasn't been assigned yet) - mQueue.Back().mReady = true; + mLoadState = TextureManager::LoadState::LOAD_FINISHED; + + // Reset size of Queue according to the real frame count. + if(mFrameCount != mAnimatedImageLoading.GetImageCount()) + { + mFrameCount = mAnimatedImageLoading.GetImageCount(); + mTextureIds.resize(mFrameCount); + mIntervals.assign(mFrameCount, 0u); + } + + bool frontFrameReady = IsFrontReady(); + // Because only one frame is on loading and the others are in mLoadWaitingQueue, + // mQueue.Back() is always the frame currently loaded. + mQueue.Back().mReady = true; + mIntervals[mQueue.Back().mFrameNumber] = interval; + // Check whether currently loaded frame is front of queue or not. + // If it is, notify frame ready to observer. + if(frontFrameReady == false && IsFrontReady()) + { + mObserver.FrameReady(textureSet, interval); + } + } +} + +void RollingAnimatedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureInformation) +{ + DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId); + LOG_CACHE; + + if(textureInformation.textureSet) + { + Sampler sampler = Sampler::New(); + sampler.SetWrapMode(mWrapModeU, mWrapModeV); + textureInformation.textureSet.SetSampler(0u, sampler); } - mOnLoading = false; - // The frames of a single animated image can not be loaded parallelly. - // Therefore, a frame is now loading, other orders are waiting. - // And, after the frame is loaded, requests load of next order. - if(!mLoadWaitingQueue.empty()) + MakeFrameReady(loadSuccess, textureInformation.textureSet, textureInformation.interval); + + if(loadSuccess) { - uint32_t loadingIndex = mLoadWaitingQueue.front(); - mLoadWaitingQueue.erase(mLoadWaitingQueue.begin()); - mOnLoading = true; - RequestFrameLoading(loadingIndex); + // The frames of a single animated image can not be loaded parallelly. + // Therefore, a frame is now loading, other orders are waiting. + // And, after the frame is loaded, requests load of next order. + if(!mLoadWaitingQueue.empty()) + { + uint32_t loadingIndex = mLoadWaitingQueue.front(); + mLoadWaitingQueue.erase(mLoadWaitingQueue.begin()); + RequestFrameLoading(loadingIndex, false); + } + else if(mQueue.Count() == 1u && textureInformation.frameCount > SINGLE_IMAGE_COUNT) + { + // There is only an image in queue and no waiting queue. + // Request to load batch once again. + uint32_t batchFrameIndex = 0u; + if(!mLoadWaitingQueue.empty()) + { + batchFrameIndex = (mLoadWaitingQueue.back() + 1) % mFrameCount; + } + else + { + batchFrameIndex = (mQueue.Back().mFrameNumber + 1) % mFrameCount; + } + LoadBatch(batchFrameIndex); + } } LOG_CACHE;