[dali_2.2.50] Merge branch 'devel/master'
[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_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK", oss.str().c_str());
154   }
155 #endif
156
157   Devel::PixelBuffer              pixelBuffer;
158   std::vector<Devel::PixelBuffer> pixelBuffers;
159
160   if(mUrl.IsValid() && mUrl.IsLocalResource())
161   {
162     if(mLoadPlanesAvaliable)
163     {
164       Dali::LoadImagePlanesFromFile(mUrl.GetUrl(), pixelBuffers, mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
165     }
166     else
167     {
168       pixelBuffer = Dali::LoadImageFromFile(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
169     }
170   }
171   else if(mUrl.IsValid())
172   {
173     pixelBuffer = Dali::DownloadImageSynchronously(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
174   }
175
176   if(pixelBuffer)
177   {
178     pixelBuffers.emplace_back(std::move(pixelBuffer));
179   }
180
181   if(pixelBuffers.empty())
182   {
183     mLoadSuccess = false;
184     DALI_LOG_ERROR("FastTrackLoadingTask::Load: Loading is failed: ResourceId : %d url : [%s]\n", mImageInformations[0u].resourceId, mUrl.GetUrl().c_str());
185   }
186   else
187   {
188     mPixelData.resize(pixelBuffers.size());
189
190     mLoadSuccess = true;
191     MultiplyAlpha(pixelBuffers[0]);
192     uint32_t index = 0u;
193     for(auto&& pixelBuffer : pixelBuffers)
194     {
195       mPixelData[index++] = Dali::Devel::PixelBuffer::Convert(pixelBuffer);
196     }
197
198     if(pixelBuffers.size() > 1u)
199     {
200       mPlanesLoaded = true;
201     }
202     else if(mLoadPlanesAvaliable && pixelBuffers.size() == 1u && mTextures.size() == 3u) ///< Case when we prepare three textures to render YUV, but loaded image is not YUV.
203     {
204       // Dummy pixel data for fake shader that we don't use actual YUV format.
205       // To fake shader, let we use indivisual sizes of texture for U and V.
206       mPixelData.resize(3u);
207       mPixelData[CHROMINANCE_U_INDEX] = GetDummyChrominanceUPixelData();
208       mPixelData[CHROMINANCE_V_INDEX] = GetDummyChrominanceVPixelData();
209     }
210
211     if(DALI_UNLIKELY(mPixelData.size() != mImageInformations.size()))
212     {
213       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());
214       mLoadSuccess = false;
215     }
216   }
217
218 #ifdef TRACE_ENABLED
219   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
220   {
221     std::ostringstream oss;
222     oss << "[";
223     oss << "pixelBuffers: " << pixelBuffers.size() << " ";
224     if(!pixelBuffers.empty())
225     {
226       oss << "premult:" << mPremultiplied << " ";
227     }
228     oss << "url:" << mUrl.GetUrl() << "]";
229     DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK", oss.str().c_str());
230   }
231 #endif
232 }
233
234 void FastTrackLoadingTask::MultiplyAlpha(Dali::Devel::PixelBuffer pixelBuffer)
235 {
236   if(mPreMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON && Pixel::HasAlpha(pixelBuffer.GetPixelFormat()))
237   {
238     pixelBuffer.MultiplyColorByAlpha();
239     mPremultiplied = pixelBuffer.IsAlphaPreMultiplied();
240   }
241 }
242
243 void FastTrackLoadingTask::UploadToTexture()
244 {
245   if(mLoadSuccess)
246   {
247     DALI_ASSERT_DEBUG(mPixelData.size() == mImageInformations.size());
248
249     uint32_t index = 0u;
250     for(auto&& pixelData : mPixelData)
251     {
252       mImageInformations[index].width  = pixelData.GetWidth();
253       mImageInformations[index].height = pixelData.GetHeight();
254       mImageInformations[index].format = pixelData.GetPixelFormat();
255
256       mTextureUploadManager.RequestUpload(mImageInformations[index].resourceId, pixelData);
257
258       pixelData.Reset();
259
260       ++index;
261     }
262   }
263
264   mPixelData.clear();
265 }
266
267 } // namespace Internal
268
269 } // namespace Toolkit
270
271 } // namespace Dali