ebefb9466cd7bab00da56456cd8672ac7999e199
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / image-loader / fast-track-loading-task.cpp
1 /*
2  * Copyright (c) 2023 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/fast-track-loading-task.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/integration-api/texture-integ.h>
26 #include <dali/integration-api/trace.h>
27 #include <dali/public-api/common/vector-wrapper.h>
28
29 #ifdef TRACE_ENABLED
30 #include <sstream>
31 #endif
32
33 namespace Dali
34 {
35 namespace Toolkit
36 {
37 namespace Internal
38 {
39 namespace
40 {
41 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
42
43 constexpr uint32_t CHROMINANCE_U_INDEX = 1u;
44 constexpr uint32_t CHROMINANCE_V_INDEX = 2u;
45
46 Dali::PixelData GetDummyChrominanceUPixelData()
47 {
48   static Dali::PixelData pixelDataU = PixelData::New(new uint8_t[2]{0x00, 0x00}, 2, 1, 2, Pixel::L8, PixelData::DELETE_ARRAY);
49   return pixelDataU;
50 }
51
52 Dali::PixelData GetDummyChrominanceVPixelData()
53 {
54   static Dali::PixelData pixelDataV = PixelData::New(new uint8_t[2]{0x00, 0x00}, 2, 2, 1, Pixel::L8, PixelData::DELETE_ARRAY);
55   return pixelDataV;
56 }
57
58 } // namespace
59
60 FastTrackLoadingTask::FastTrackLoadingTask(const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadPlanes, CallbackBase* callback)
61 : AsyncTask(MakeCallback(this, &FastTrackLoadingTask::OnComplete), url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH),
62   mUrl(url),
63   mTextures(),
64   mDimensions(dimensions),
65   mFittingMode(fittingMode),
66   mSamplingMode(samplingMode),
67   mPreMultiplyOnLoad(preMultiplyOnLoad),
68   mCallback(),
69   mTextureUploadManager(Dali::Devel::TextureUploadManager::Get()),
70   mImageInformations(),
71   mPixelData(),
72   mOrientationCorrection(orientationCorrection),
73   mLoadSuccess(false),
74   mLoadPlanesAvaliable(loadPlanes),
75   mPremultiplied(false),
76   mPlanesLoaded(false)
77 {
78   mCallback = std::unique_ptr<CallbackBase>(callback);
79   PrepareTexture();
80 }
81
82 FastTrackLoadingTask::~FastTrackLoadingTask()
83 {
84 }
85
86 void FastTrackLoadingTask::PrepareTexture()
87 {
88   const uint32_t requiredTexturesCount = mLoadPlanesAvaliable ? 3u : 1u;
89
90   mTextures.resize(requiredTexturesCount);
91   mImageInformations.resize(requiredTexturesCount);
92   for(uint32_t index = 0u; index < requiredTexturesCount; ++index)
93   {
94     mTextures[index] = mTextureUploadManager.GenerateTexture2D();
95
96     mImageInformations[index].resourceId = Integration::GetTextureResourceId(mTextures[index]);
97   }
98
99   if(mLoadPlanesAvaliable)
100   {
101     // Create static dummy chrominance pixel data now, for thread safety.
102     [[maybe_unused]] auto pixelDataU = GetDummyChrominanceUPixelData();
103     [[maybe_unused]] auto pixelDataV = GetDummyChrominanceVPixelData();
104   }
105 }
106
107 void FastTrackLoadingTask::OnComplete(AsyncTaskPtr task)
108 {
109   if(mLoadSuccess)
110   {
111     for(uint32_t index = 0u; index < mImageInformations.size(); ++index)
112     {
113       Dali::Integration::SetTextureSize(mTextures[index], Dali::ImageDimensions(mImageInformations[index].width, mImageInformations[index].height));
114       Dali::Integration::SetTexturePixelFormat(mTextures[index], mImageInformations[index].format);
115     }
116     if(mLoadPlanesAvaliable && !mPlanesLoaded)
117     {
118       // We will not use ChrominanceU and ChrominanceV texture anymore.
119       mTextures.resize(1u);
120     }
121   }
122   else
123   {
124     mTextures.clear();
125   }
126
127   if(mCallback)
128   {
129     CallbackBase::Execute(*mCallback, FastTrackLoadingTaskPtr(reinterpret_cast<FastTrackLoadingTask*>(task.Get())));
130   }
131 }
132
133 // Called by worker thread
134
135 void FastTrackLoadingTask::Process()
136 {
137   Load();
138   UploadToTexture();
139 }
140
141 bool FastTrackLoadingTask::IsReady()
142 {
143   return true;
144 }
145
146 void FastTrackLoadingTask::Load()
147 {
148 #ifdef TRACE_ENABLED
149   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
150   {
151     std::ostringstream oss;
152     oss << "[url:" << mUrl.GetUrl() << "]";
153     // DALI_TRACE_BEGIN(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK"); ///< TODO : Open it if we can control trace log level
154     DALI_LOG_RELEASE_INFO("BEGIN: DALI_IMAGE_FAST_TRACK_UPLOADING_TASK %s", oss.str().c_str());
155   }
156 #endif
157
158   Devel::PixelBuffer              pixelBuffer;
159   std::vector<Devel::PixelBuffer> pixelBuffers;
160
161   if(mUrl.IsValid() && mUrl.IsLocalResource())
162   {
163     if(mLoadPlanesAvaliable)
164     {
165       Dali::LoadImagePlanesFromFile(mUrl.GetUrl(), pixelBuffers, mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
166     }
167     else
168     {
169       pixelBuffer = Dali::LoadImageFromFile(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
170     }
171   }
172   else if(mUrl.IsValid())
173   {
174     pixelBuffer = Dali::DownloadImageSynchronously(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
175   }
176
177   if(pixelBuffer)
178   {
179     pixelBuffers.emplace_back(std::move(pixelBuffer));
180   }
181
182   if(pixelBuffers.empty())
183   {
184     mLoadSuccess = false;
185     DALI_LOG_ERROR("FastTrackLoadingTask::Load: Loading is failed: ResourceId : %d url : [%s]\n", mImageInformations[0u].resourceId, mUrl.GetUrl().c_str());
186   }
187   else
188   {
189     mPixelData.resize(pixelBuffers.size());
190
191     mLoadSuccess = true;
192     MultiplyAlpha(pixelBuffers[0]);
193     uint32_t index = 0u;
194     for(auto&& pixelBuffer : pixelBuffers)
195     {
196       mPixelData[index++] = Dali::Devel::PixelBuffer::Convert(pixelBuffer);
197     }
198
199     if(pixelBuffers.size() > 1u)
200     {
201       mPlanesLoaded = true;
202     }
203     else if(mLoadPlanesAvaliable && pixelBuffers.size() == 1u && mTextures.size() == 3u) ///< Case when we prepare three textures to render YUV, but loaded image is not YUV.
204     {
205       // Dummy pixel data for fake shader that we don't use actual YUV format.
206       // To fake shader, let we use indivisual sizes of texture for U and V.
207       mPixelData.resize(3u);
208       mPixelData[CHROMINANCE_U_INDEX] = GetDummyChrominanceUPixelData();
209       mPixelData[CHROMINANCE_V_INDEX] = GetDummyChrominanceVPixelData();
210     }
211
212     if(DALI_UNLIKELY(mPixelData.size() != mImageInformations.size()))
213     {
214       DALI_LOG_ERROR("FastTrackLoadingTask::Load: Undefined case. pixelBuffers.size() : %zu, image size : %zu, ResourceId : %d, url : [%s]\n", pixelBuffers.size(), mImageInformations.size(), mImageInformations[0u].resourceId, mUrl.GetUrl().c_str());
215       mLoadSuccess = false;
216     }
217   }
218
219 #ifdef TRACE_ENABLED
220   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
221   {
222     std::ostringstream oss;
223     oss << "[";
224     oss << "pixelBuffers:" << pixelBuffers.size() << " ";
225     if(!pixelBuffers.empty())
226     {
227       oss << "size:" << pixelBuffers[0].GetWidth() << "x" << pixelBuffers[0].GetHeight() << " ";
228       oss << "premult:" << mPremultiplied << " ";
229     }
230     oss << "url:" << mUrl.GetUrl() << "]";
231     // DALI_TRACE_END(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK"); ///< TODO : Open it if we can control trace log level
232     DALI_LOG_RELEASE_INFO("END: DALI_IMAGE_FAST_TRACK_UPLOADING_TASK %s", oss.str().c_str());
233   }
234 #endif
235 }
236
237 void FastTrackLoadingTask::MultiplyAlpha(Dali::Devel::PixelBuffer pixelBuffer)
238 {
239   if(mPreMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON && Pixel::HasAlpha(pixelBuffer.GetPixelFormat()))
240   {
241     pixelBuffer.MultiplyColorByAlpha();
242     mPremultiplied = pixelBuffer.IsAlphaPreMultiplied();
243   }
244 }
245
246 void FastTrackLoadingTask::UploadToTexture()
247 {
248   if(mLoadSuccess)
249   {
250     DALI_ASSERT_DEBUG(mPixelData.size() == mImageInformations.size());
251
252     uint32_t index = 0u;
253     for(auto&& pixelData : mPixelData)
254     {
255       mImageInformations[index].width  = pixelData.GetWidth();
256       mImageInformations[index].height = pixelData.GetHeight();
257       mImageInformations[index].format = pixelData.GetPixelFormat();
258
259       mTextureUploadManager.RequestUpload(mImageInformations[index].resourceId, pixelData);
260
261       pixelData.Reset();
262
263       ++index;
264     }
265   }
266
267   mPixelData.clear();
268 }
269
270 } // namespace Internal
271
272 } // namespace Toolkit
273
274 } // namespace Dali