Apply WrapMode in animated visual
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-image / rolling-animated-image-cache.cpp
index eba9341..b8a6961 100644 (file)
@@ -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 <dali-toolkit/devel-api/image-loader/texture-manager.h>
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // 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,50 @@ 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,
+                                                                   mWrapModeU,
+                                                                   mWrapModeV,
+                                                                   synchronousLoading,
+                                                                   this,
+                                                                   preMultiplyOnLoading);
 
-  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<uint32_t>(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;
 }
 
@@ -262,71 +265,114 @@ TextureSet RollingAnimatedImageCache::GetFrontTextureSet() const
 
 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());
+    mTextureManager.Remove(mMaskingData->mAlphaMaskId, this);
+    if(mQueue.IsEmpty())
+    {
+      mMaskingData->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
+    }
   }
 }
 
-void RollingAnimatedImageCache::UploadComplete(
-  bool           loadSuccess,
-  int32_t        textureId,
-  TextureSet     textureSet,
-  bool           useAtlasing,
-  const Vector4& atlasRect,
-  bool           preMultiplied)
+void RollingAnimatedImageCache::ClearCache()
 {
-  DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId);
-  LOG_CACHE;
-
-  bool frontFrameReady = IsFrontReady();
-
-  if(!mRequestingLoad)
+  while(mTextureManagerAlive && !mQueue.IsEmpty())
   {
-    SetImageFrameReady(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
   {
-    // UploadComplete 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;
+
+  TextureSet textureSet = mTextureManager.GetTextureSet(textureInformation.textureId);
+  if(textureSet)
+  {
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+    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, 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;
 }
 
-void RollingAnimatedImageCache::LoadComplete(
-  bool               loadSuccess,
-  Devel::PixelBuffer pixelBuffer,
-  const VisualUrl&   url,
-  bool               preMultiplied)
-{
-  // LoadComplete is called if this TextureUploadObserver requested to load
-  // an image that will be returned as a type of PixelBuffer by using a method
-  // TextureManager::LoadPixelBuffer.
-}
-
 } //namespace Internal
 } //namespace Toolkit
 } //namespace Dali