Updated all cpp files to new format
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-image / rolling-image-cache.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 // CLASS HEADER
18 #include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
19
20 // INTERNAL HEADERS
21 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
22 #include <dali/integration-api/debug.h>
23
24 // EXTERNAL HEADERS
25
26 namespace
27 {
28 #if defined(DEBUG_ENABLED)
29 Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
30
31 #define LOG_CACHE                                                                                                                                                        \
32   {                                                                                                                                                                      \
33     std::ostringstream oss;                                                                                                                                              \
34     oss << "Size:" << mQueue.Count() << " [ ";                                                                                                                           \
35     for(std::size_t _i = 0; _i < mQueue.Count(); ++_i)                                                                                                                   \
36     {                                                                                                                                                                    \
37       oss << _i << "={ tex:" << mImageUrls[mQueue[_i].mUrlIndex].mTextureId << " urlId:" << mQueue[_i].mUrlIndex << " rdy:" << (mQueue[_i].mReady ? "T" : "F") << "}, "; \
38     }                                                                                                                                                                    \
39     oss << " ]" << std::endl;                                                                                                                                            \
40     DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "%s", oss.str().c_str());                                                                                           \
41   }
42
43 #else
44 #define LOG_CACHE
45 #endif
46
47 const bool ENABLE_ORIENTATION_CORRECTION(true);
48
49 } // namespace
50
51 namespace Dali
52 {
53 namespace Toolkit
54 {
55 namespace Internal
56 {
57 RollingImageCache::RollingImageCache(
58   TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer, uint16_t cacheSize, uint16_t batchSize)
59 : ImageCache(textureManager, observer, batchSize),
60   mImageUrls(urlList),
61   mQueue(cacheSize)
62 {
63   LoadBatch();
64 }
65
66 RollingImageCache::~RollingImageCache()
67 {
68   if(mTextureManagerAlive)
69   {
70     while(!mQueue.IsEmpty())
71     {
72       ImageFrame imageFrame = mQueue.PopFront();
73       mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
74     }
75   }
76 }
77
78 TextureSet RollingImageCache::Frame(uint32_t frameIndex)
79 {
80   // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures.
81   if(mImageUrls[frameIndex].mTextureId == TextureManager::INVALID_TEXTURE_ID)
82   {
83     mUrlIndex = frameIndex;
84     while(!mQueue.IsEmpty())
85     {
86       ImageFrame imageFrame = mQueue.PopFront();
87       mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
88       mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
89     }
90     LoadBatch();
91   }
92   // If the frame is already loaded, remove previous frames of the frame in the queue
93   // and load new frames amount of removed frames.
94   else
95   {
96     bool popExist = false;
97     while(!mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex)
98     {
99       ImageFrame imageFrame = mQueue.PopFront();
100       mTextureManager.Remove(mImageUrls[imageFrame.mUrlIndex].mTextureId, this);
101       mImageUrls[imageFrame.mUrlIndex].mTextureId = TextureManager::INVALID_TEXTURE_ID;
102       popExist                                    = true;
103     }
104     if(popExist)
105     {
106       mUrlIndex = (mQueue.Back().mUrlIndex + 1) % mImageUrls.size();
107       LoadBatch();
108     }
109   }
110
111   TextureSet textureSet;
112   if(IsFrontReady() == true)
113   {
114     textureSet = GetFrontTextureSet();
115   }
116   else
117   {
118     mWaitingForReadyFrame = true;
119   }
120
121   return textureSet;
122 }
123
124 TextureSet RollingImageCache::FirstFrame()
125 {
126   return Frame(0u);
127 }
128
129 TextureSet RollingImageCache::NextFrame()
130 {
131   TextureSet textureSet;
132   if(!mQueue.IsEmpty())
133   {
134     uint32_t frameIndex = mQueue.Front().mUrlIndex;
135     if(IsFrontReady())
136     {
137       frameIndex = (frameIndex + 1) % mImageUrls.size();
138     }
139     textureSet = Frame(frameIndex);
140   }
141   else
142   {
143     DALI_LOG_ERROR("Cache is empty.");
144   }
145
146   return textureSet;
147 }
148
149 uint32_t RollingImageCache::GetFrameInterval(uint32_t frameIndex) const
150 {
151   return 0u;
152 }
153
154 int32_t RollingImageCache::GetCurrentFrameIndex() const
155 {
156   if(mQueue.IsEmpty())
157   {
158     return -1;
159   }
160   return mQueue.Front().mUrlIndex;
161 }
162
163 int32_t RollingImageCache::GetTotalFrameCount() const
164 {
165   return mImageUrls.size();
166 }
167
168 bool RollingImageCache::IsFrontReady() const
169 {
170   return (!mQueue.IsEmpty() && mQueue.Front().mReady);
171 }
172
173 void RollingImageCache::LoadBatch()
174 {
175   // Try and load up to mBatchSize images, until the cache is filled.
176   // Once the cache is filled, as frames progress, the old frame is
177   // cleared, but not erased, and another image is loaded
178   bool frontFrameReady = IsFrontReady();
179
180   for(unsigned int i = 0; i < mBatchSize && !mQueue.IsFull(); ++i)
181   {
182     ImageFrame imageFrame;
183
184     std::string& url     = mImageUrls[mUrlIndex].mUrl;
185     imageFrame.mUrlIndex = mUrlIndex;
186     imageFrame.mReady    = false;
187
188     ++mUrlIndex;
189     mUrlIndex %= mImageUrls.size();
190
191     mQueue.PushBack(imageFrame);
192
193     // Note, if the image is already loaded, then UploadComplete will get called
194     // from within this method. This means it won't yet have a texture id, so we
195     // need to account for this inside the UploadComplete method using mRequestingLoad.
196     mRequestingLoad = true;
197
198     bool                               synchronousLoading = false;
199     bool                               atlasingStatus     = false;
200     bool                               loadingStatus      = false;
201     TextureManager::MaskingDataPointer maskInfo           = nullptr;
202     AtlasUploadObserver*               atlasObserver      = nullptr;
203     ImageAtlasManagerPtr               imageAtlasManager  = nullptr;
204     Vector4                            textureRect;
205     Dali::ImageDimensions              textureRectSize;
206     auto                               preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
207
208     mTextureManager.LoadTexture(
209       url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, maskInfo, synchronousLoading, mImageUrls[imageFrame.mUrlIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
210
211     mRequestingLoad = false;
212   }
213
214   CheckFrontFrame(frontFrameReady);
215 }
216
217 void RollingImageCache::SetImageFrameReady(TextureManager::TextureId textureId)
218 {
219   for(std::size_t i = 0; i < mQueue.Count(); ++i)
220   {
221     if(GetCachedTextureId(i) == textureId)
222     {
223       mQueue[i].mReady = true;
224       break;
225     }
226   }
227 }
228
229 TextureSet RollingImageCache::GetFrontTextureSet() const
230 {
231   TextureManager::TextureId textureId = GetCachedTextureId(0);
232   return mTextureManager.GetTextureSet(textureId);
233 }
234
235 TextureManager::TextureId RollingImageCache::GetCachedTextureId(int index) const
236 {
237   return mImageUrls[mQueue[index].mUrlIndex].mTextureId;
238 }
239
240 void RollingImageCache::CheckFrontFrame(bool wasReady)
241 {
242   if(mWaitingForReadyFrame && wasReady == false && IsFrontReady())
243   {
244     mWaitingForReadyFrame = false;
245     mObserver.FrameReady(GetFrontTextureSet());
246   }
247 }
248
249 void RollingImageCache::UploadComplete(
250   bool           loadSuccess,
251   int32_t        textureId,
252   TextureSet     textureSet,
253   bool           useAtlasing,
254   const Vector4& atlasRect,
255   bool           preMultiplied)
256 {
257   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId);
258   LOG_CACHE;
259
260   bool frontFrameReady = IsFrontReady();
261
262   if(!mRequestingLoad)
263   {
264     SetImageFrameReady(textureId);
265
266     CheckFrontFrame(frontFrameReady);
267   }
268   else
269   {
270     // UploadComplete has been called from within RequestLoad. TextureManager must
271     // therefore already have the texture cached, so make the texture ready.
272     // (Use the last texture, as the texture id hasn't been assigned yet)
273     mQueue.Back().mReady = true;
274   }
275
276   LOG_CACHE;
277 }
278
279 void RollingImageCache::LoadComplete(
280   bool               loadSuccess,
281   Devel::PixelBuffer pixelBuffer,
282   const VisualUrl&   url,
283   bool               preMultiplied)
284 {
285   // LoadComplete is called if this TextureUploadObserver requested to load
286   // an image that will be returned as a type of PixelBuffer by using a method
287   // TextureManager::LoadPixelBuffer.
288 }
289
290 } //namespace Internal
291 } //namespace Toolkit
292 } //namespace Dali