[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / image-loader / loading-task.cpp
1 /*
2  * Copyright (c) 2024 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
18 // CLASS HEADER
19 #include <dali-toolkit/internal/image-loader/loading-task.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/devel-api/adaptor-framework/thread-settings.h>
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/trace.h>
27 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
28
29 #ifdef TRACE_ENABLED
30 #include <chrono>
31 #include <iomanip>
32 #include <sstream>
33 #include <thread>
34 #endif
35
36 namespace Dali
37 {
38 namespace Toolkit
39 {
40 namespace Internal
41 {
42 namespace
43 {
44 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
45
46 #ifdef TRACE_ENABLED
47 uint64_t GetNanoseconds()
48 {
49   // Get the time of a monotonic clock since its epoch.
50   auto epoch    = std::chrono::steady_clock::now().time_since_epoch();
51   auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
52   return static_cast<uint64_t>(duration.count());
53 }
54 #endif
55 } // namespace
56
57 LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
58 : AsyncTask(callback),
59   url(),
60   encodedImageBuffer(),
61   id(id),
62   textureId(TextureManagerType::INVALID_TEXTURE_ID),
63   dimensions(),
64   fittingMode(FittingMode::SCALE_TO_FILL),
65   samplingMode(SamplingMode::BOX_THEN_LINEAR),
66   preMultiplyOnLoad(preMultiplyOnLoad),
67   maskPixelBuffer(),
68   contentScale(1.0f),
69   animatedImageLoading(animatedImageLoading),
70   frameIndex(frameIndex),
71   orientationCorrection(),
72   isMaskTask(false),
73   cropToMask(false),
74   loadPlanes(false),
75   isReady(true)
76 {
77 }
78
79 LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
80 : AsyncTask(callback),
81   url(),
82   encodedImageBuffer(),
83   id(id),
84   textureId(TextureManagerType::INVALID_TEXTURE_ID),
85   dimensions(dimensions),
86   fittingMode(fittingMode),
87   samplingMode(samplingMode),
88   preMultiplyOnLoad(preMultiplyOnLoad),
89   maskPixelBuffer(),
90   contentScale(1.0f),
91   animatedImageLoading(animatedImageLoading),
92   frameIndex(frameIndex),
93   orientationCorrection(),
94   isMaskTask(false),
95   cropToMask(false),
96   loadPlanes(false),
97   isReady(true)
98 {
99 }
100
101 LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadPlanes, CallbackBase* callback)
102 : AsyncTask(callback, url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH),
103   url(url),
104   encodedImageBuffer(),
105   id(id),
106   textureId(TextureManagerType::INVALID_TEXTURE_ID),
107   dimensions(dimensions),
108   fittingMode(fittingMode),
109   samplingMode(samplingMode),
110   preMultiplyOnLoad(preMultiplyOnLoad),
111   maskPixelBuffer(),
112   contentScale(1.0f),
113   animatedImageLoading(),
114   frameIndex(0u),
115   orientationCorrection(orientationCorrection),
116   isMaskTask(false),
117   cropToMask(false),
118   loadPlanes(loadPlanes),
119   isReady(true)
120 {
121 }
122
123 LoadingTask::LoadingTask(uint32_t id, const EncodedImageBuffer& encodedImageBuffer, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
124 : AsyncTask(callback),
125   url(),
126   encodedImageBuffer(encodedImageBuffer),
127   id(id),
128   textureId(TextureManagerType::INVALID_TEXTURE_ID),
129   dimensions(dimensions),
130   fittingMode(fittingMode),
131   samplingMode(samplingMode),
132   preMultiplyOnLoad(preMultiplyOnLoad),
133   maskPixelBuffer(),
134   contentScale(1.0f),
135   animatedImageLoading(),
136   frameIndex(0u),
137   orientationCorrection(orientationCorrection),
138   isMaskTask(false),
139   cropToMask(false),
140   loadPlanes(false),
141   isReady(true)
142 {
143 }
144
145 LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
146 : AsyncTask(callback),
147   url(""),
148   encodedImageBuffer(),
149   id(id),
150   textureId(TextureManagerType::INVALID_TEXTURE_ID),
151   dimensions(),
152   fittingMode(),
153   samplingMode(),
154   preMultiplyOnLoad(preMultiplyOnLoad),
155   maskPixelBuffer(maskPixelBuffer),
156   contentScale(contentScale),
157   animatedImageLoading(),
158   frameIndex(0u),
159   orientationCorrection(),
160   isMaskTask(true),
161   cropToMask(cropToMask),
162   loadPlanes(false),
163   isReady(true)
164 {
165   pixelBuffers.push_back(pixelBuffer);
166 }
167
168 LoadingTask::~LoadingTask()
169 {
170 }
171
172 void LoadingTask::Process()
173 {
174 #ifdef TRACE_ENABLED
175   uint64_t mStartTimeNanoSceonds = 0;
176   uint64_t mEndTimeNanoSceonds   = 0;
177   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
178   {
179     mStartTimeNanoSceonds = GetNanoseconds();
180     std::ostringstream oss;
181     oss << "[u:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetEllipsedUrl()) << "]";
182     // DALI_TRACE_BEGIN(gTraceFilter, "DALI_IMAGE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
183     DALI_LOG_RELEASE_INFO("BEGIN: DALI_IMAGE_LOADING_TASK %s", oss.str().c_str());
184   }
185 #endif
186
187   isReady = false;
188   if(!isMaskTask)
189   {
190     Load();
191   }
192   else
193   {
194     ApplyMask();
195   }
196   MultiplyAlpha();
197   isReady = true;
198
199 #ifdef TRACE_ENABLED
200   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
201   {
202     mEndTimeNanoSceonds = GetNanoseconds();
203     std::ostringstream oss;
204     oss << std::fixed << std::setprecision(3);
205     oss << "[";
206     oss << "d:" << static_cast<float>(mEndTimeNanoSceonds - mStartTimeNanoSceonds) / 1000000.0f << "ms ";
207     oss << "m:" << isMaskTask << " ";
208     oss << "i:" << frameIndex << " ";
209     oss << "b:" << pixelBuffers.size() << " ";
210     if(!pixelBuffers.empty())
211     {
212       oss << "s:" << pixelBuffers[0].GetWidth() << "x" << pixelBuffers[0].GetHeight() << " ";
213       oss << "p:" << pixelBuffers[0].IsAlphaPreMultiplied() << " ";
214     }
215     oss << "u:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetEllipsedUrl()) << "]";
216     // DALI_TRACE_END(gTraceFilter, "DALI_IMAGE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
217     DALI_LOG_RELEASE_INFO("END: DALI_IMAGE_LOADING_TASK %s", oss.str().c_str());
218   }
219 #endif
220 }
221
222 bool LoadingTask::IsReady()
223 {
224   return isReady;
225 }
226
227 void LoadingTask::Load()
228 {
229   Devel::PixelBuffer pixelBuffer;
230   if(animatedImageLoading)
231   {
232     pixelBuffer = animatedImageLoading.LoadFrame(frameIndex, dimensions, fittingMode, samplingMode);
233   }
234   else if(encodedImageBuffer)
235   {
236     pixelBuffer = Dali::LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), dimensions, fittingMode, samplingMode, orientationCorrection);
237
238     // We don't need to hold image buffer anymore.
239     encodedImageBuffer.Reset();
240   }
241   else if(url.IsValid() && url.IsLocalResource())
242   {
243     if(loadPlanes)
244     {
245       Dali::LoadImagePlanesFromFile(url.GetUrl(), pixelBuffers, dimensions, fittingMode, samplingMode, orientationCorrection);
246     }
247     else
248     {
249       pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
250     }
251   }
252   else if(url.IsValid())
253   {
254     pixelBuffer = Dali::DownloadImageSynchronously(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
255   }
256
257   if(pixelBuffer)
258   {
259     pixelBuffers.push_back(pixelBuffer);
260   }
261
262   if(pixelBuffers.empty())
263   {
264     DALI_LOG_ERROR("LoadingTask::Load: Loading is failed: %s\n", url.GetUrl().c_str());
265   }
266 }
267
268 void LoadingTask::ApplyMask()
269 {
270   if(!pixelBuffers.empty())
271   {
272     pixelBuffers[0].ApplyMask(maskPixelBuffer, contentScale, cropToMask);
273   }
274 }
275
276 void LoadingTask::MultiplyAlpha()
277 {
278   if(!pixelBuffers.empty() && Pixel::HasAlpha(pixelBuffers[0].GetPixelFormat()))
279   {
280     if(preMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON)
281     {
282       pixelBuffers[0].MultiplyColorByAlpha();
283     }
284   }
285 }
286
287 void LoadingTask::SetTextureId(TextureManagerType::TextureId id)
288 {
289   textureId = id;
290 }
291
292 } // namespace Internal
293
294 } // namespace Toolkit
295
296 } // namespace Dali