Merge "Fix RemoteSVG UTC failed due to the proxy block (2)" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-rasterize-thread.cpp
1 /*
2  * Copyright (c) 2022 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 "svg-rasterize-thread.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/environment-variable.h>
23 #include <dali/devel-api/adaptor-framework/file-loader.h>
24 #include <dali/devel-api/adaptor-framework/thread-settings.h>
25 #include <dali/integration-api/adaptor-framework/adaptor.h>
26 #include <dali/integration-api/debug.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
30
31 namespace Dali
32 {
33 namespace Toolkit
34 {
35 namespace Internal
36 {
37 namespace
38 {
39 constexpr auto DEFAULT_NUMBER_OF_SVG_RASTERIZE_THREADS = size_t{4u};
40 constexpr auto NUMBER_OF_SVG_RASTERIZE_THREADS_ENV     = "DALI_SVG_RASTERIZE_THREADS";
41
42 size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
43 {
44   auto           numberString          = EnvironmentVariable::GetEnvironmentVariable(environmentVariable);
45   auto           numberOfThreads       = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
46   constexpr auto MAX_NUMBER_OF_THREADS = 10u;
47   DALI_ASSERT_DEBUG(numberOfThreads < MAX_NUMBER_OF_THREADS);
48   return (numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS) ? numberOfThreads : defaultValue;
49 }
50
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gVectorImageLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_IMAGE");
53 #endif
54
55 } // unnamed namespace
56
57 SvgTask::SvgTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer)
58 : mSvgVisual(svgVisual),
59   mVectorRenderer(vectorRenderer),
60   mHasSucceeded(false)
61 {
62 }
63
64 SvgVisual* SvgTask::GetSvgVisual() const
65 {
66   return mSvgVisual.Get();
67 }
68
69 PixelData SvgTask::GetPixelData() const
70 {
71   return PixelData();
72 }
73
74 bool SvgTask::HasSucceeded() const
75 {
76   return mHasSucceeded;
77 }
78
79 SvgLoadingTask::SvgLoadingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi)
80 : SvgTask(svgVisual, vectorRenderer),
81   mUrl(url),
82   mDpi(dpi)
83 {
84 }
85
86 SvgLoadingTask::~SvgLoadingTask()
87 {
88 }
89
90 void SvgLoadingTask::Process()
91 {
92   if(mVectorRenderer.IsLoaded())
93   {
94     // Already loaded
95     mHasSucceeded = true;
96     return;
97   }
98
99   Dali::Vector<uint8_t> buffer;
100
101   if(!mUrl.IsLocalResource())
102   {
103     if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), buffer))
104     {
105       DALI_LOG_ERROR("Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
106       return;
107     }
108   }
109   else
110   {
111     if(!Dali::FileLoader::ReadFile(mUrl.GetUrl(), buffer))
112     {
113       DALI_LOG_ERROR("Failed to read file! [%s]\n", mUrl.GetUrl().c_str());
114       return;
115     }
116   }
117
118   buffer.PushBack('\0');
119
120   if(!mVectorRenderer.Load(buffer, mDpi))
121   {
122     DALI_LOG_ERROR("Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
123     return;
124   }
125
126   mHasSucceeded = true;
127 }
128
129 SvgRasterizingTask::SvgRasterizingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, unsigned int width, unsigned int height)
130 : SvgTask(svgVisual, vectorRenderer),
131   mWidth(width),
132   mHeight(height)
133 {
134 }
135
136 SvgRasterizingTask::~SvgRasterizingTask()
137 {
138 }
139
140 void SvgRasterizingTask::Process()
141 {
142   if(!mVectorRenderer.IsLoaded())
143   {
144     DALI_LOG_ERROR("File is not loaded!\n");
145     return;
146   }
147
148   DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "Rasterize: (%d x %d) [%p]\n", mWidth, mHeight, this);
149
150   Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
151   if(!pixelBuffer)
152   {
153     DALI_LOG_ERROR("Rasterize is failed!\n");
154     return;
155   }
156
157   mPixelData    = Devel::PixelBuffer::Convert(pixelBuffer);
158   mHasSucceeded = true;
159 }
160
161 bool SvgRasterizingTask::IsReady()
162 {
163   return mVectorRenderer.IsLoaded();
164 }
165
166 PixelData SvgRasterizingTask::GetPixelData() const
167 {
168   return mPixelData;
169 }
170
171 SvgRasterizeThread::SvgRasterizeThread(SvgRasterizeManager& svgRasterizeManager)
172 : mConditionalWait(),
173   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
174   mSvgRasterizeManager(svgRasterizeManager),
175   mDestroyThread(false),
176   mIsThreadStarted(false),
177   mIsThreadIdle(true)
178 {
179 }
180
181 SvgRasterizeThread::~SvgRasterizeThread()
182 {
183   // Stop the thread
184   {
185     ConditionalWait::ScopedLock lock(mConditionalWait);
186     mDestroyThread = true;
187     mConditionalWait.Notify(lock);
188   }
189
190   Join();
191 }
192
193 bool SvgRasterizeThread::RequestRasterize()
194 {
195   if(!mIsThreadStarted)
196   {
197     Start();
198     mIsThreadStarted = true;
199   }
200
201   {
202     // Lock while adding task to the queue
203     ConditionalWait::ScopedLock lock(mConditionalWait);
204
205     if(mIsThreadIdle)
206     {
207       mIsThreadIdle = false;
208
209       // wake up the thread
210       mConditionalWait.Notify(lock);
211       return true;
212     }
213   }
214
215   return false;
216 }
217
218 void SvgRasterizeThread::Run()
219 {
220   SetThreadName("SvgRasterizeThread");
221   mLogFactory.InstallLogFunction();
222
223   while(!mDestroyThread)
224   {
225     SvgTaskPtr task = mSvgRasterizeManager.NextTaskToProcess();
226     if(!task)
227     {
228       ConditionalWait::ScopedLock lock(mConditionalWait);
229       mIsThreadIdle = true;
230       mConditionalWait.Wait(lock);
231     }
232     else
233     {
234       task->Process();
235
236       mSvgRasterizeManager.AddCompletedTask(task);
237     }
238   }
239 }
240
241 SvgRasterizeManager::SvgRasterizeManager()
242 : mRasterizers(GetNumberOfThreads(NUMBER_OF_SVG_RASTERIZE_THREADS_ENV, DEFAULT_NUMBER_OF_SVG_RASTERIZE_THREADS), [&]() { return RasterizeHelper(*this); }),
243   mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeManager::ApplyRasterizedSVGToSampler))),
244   mProcessorRegistered(false)
245 {
246 }
247
248 SvgRasterizeManager::~SvgRasterizeManager()
249 {
250   if(mProcessorRegistered)
251   {
252     Adaptor::Get().UnregisterProcessor(*this);
253   }
254
255   mRasterizers.Clear();
256 }
257
258 void SvgRasterizeManager::AddTask(SvgTaskPtr task)
259 {
260   {
261     // Lock while adding task to the queue
262     Mutex::ScopedLock lock(mMutex);
263
264     // There are other tasks waiting for the rasterization
265     if(!mRasterizeTasks.empty())
266     {
267       // Remove the tasks with the same renderer.
268       // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
269       // Rasterizing task only, loading task is not duplicated.
270       for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
271       {
272         if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual())
273         {
274           SvgRasterizingTask* oldTask = dynamic_cast<SvgRasterizingTask*>(it->Get());
275           SvgRasterizingTask* newTask = dynamic_cast<SvgRasterizingTask*>(task.Get());
276           if(oldTask && newTask)
277           {
278             mRasterizeTasks.erase(it);
279             break;
280           }
281         }
282       }
283     }
284
285     mRasterizeTasks.push_back(task);
286   }
287
288   size_t count = mRasterizers.GetElementCount();
289   size_t index = 0;
290   while(index++ < count)
291   {
292     auto rasterizerHelperIt = mRasterizers.GetNext();
293     DALI_ASSERT_ALWAYS(rasterizerHelperIt != mRasterizers.End());
294
295     if(rasterizerHelperIt->RequestRasterize())
296     {
297       break;
298     }
299     // If all threads are busy, then it's ok just to push the task because they will try to get the next job.
300   }
301
302   if(!mProcessorRegistered)
303   {
304     Adaptor::Get().RegisterProcessor(*this);
305     mProcessorRegistered = true;
306   }
307
308   return;
309 }
310
311 SvgTaskPtr SvgRasterizeManager::NextCompletedTask()
312 {
313   // Lock while popping task out from the queue
314   Mutex::ScopedLock lock(mMutex);
315
316   if(mCompletedTasks.empty())
317   {
318     return SvgTaskPtr();
319   }
320
321   std::vector<SvgTaskPtr>::iterator next     = mCompletedTasks.begin();
322   SvgTaskPtr                        nextTask = *next;
323   mCompletedTasks.erase(next);
324
325   return nextTask;
326 }
327
328 void SvgRasterizeManager::RemoveTask(SvgVisual* visual)
329 {
330   {
331     // Lock while remove task from the queue
332     Mutex::ScopedLock lock(mMutex);
333     if(!mRasterizeTasks.empty())
334     {
335       for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(); it != mRasterizeTasks.end();)
336       {
337         if((*it) && (*it)->GetSvgVisual() == visual)
338         {
339           it = mRasterizeTasks.erase(it);
340         }
341         else
342         {
343           it++;
344         }
345       }
346     }
347   }
348
349   UnregisterProcessor();
350 }
351
352 SvgTaskPtr SvgRasterizeManager::NextTaskToProcess()
353 {
354   // Lock while popping task out from the queue
355   Mutex::ScopedLock lock(mMutex);
356
357   // pop out the next task from the queue
358   SvgTaskPtr nextTask = nullptr;
359
360   for(auto iter = mRasterizeTasks.begin(), endIter = mRasterizeTasks.end(); iter != endIter; ++iter)
361   {
362     if((*iter)->IsReady())
363     {
364       nextTask = *iter;
365       mRasterizeTasks.erase(iter);
366       break;
367     }
368   }
369
370   return nextTask;
371 }
372
373 void SvgRasterizeManager::AddCompletedTask(SvgTaskPtr task)
374 {
375   // Lock while adding task to the queue
376   Mutex::ScopedLock lock(mMutex);
377   mCompletedTasks.push_back(task);
378
379   // wake up the main thread
380   mTrigger->Trigger();
381 }
382
383 void SvgRasterizeManager::ApplyRasterizedSVGToSampler()
384 {
385   while(SvgTaskPtr task = NextCompletedTask())
386   {
387     DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "task = %p\n", task.Get());
388
389     task->GetSvgVisual()->ApplyRasterizedImage(task->GetPixelData(), task->HasSucceeded());
390   }
391
392   UnregisterProcessor();
393 }
394
395 void SvgRasterizeManager::Process(bool postProcessor)
396 {
397   ApplyRasterizedSVGToSampler();
398 }
399
400 void SvgRasterizeManager::UnregisterProcessor()
401 {
402   Mutex::ScopedLock lock(mMutex);
403
404   if(mProcessorRegistered)
405   {
406     if(mRasterizeTasks.empty() && mCompletedTasks.empty())
407     {
408       Adaptor::Get().UnregisterProcessor(*this);
409       mProcessorRegistered = false;
410     }
411   }
412 }
413
414 SvgRasterizeManager::RasterizeHelper::RasterizeHelper(SvgRasterizeManager& svgRasterizeManager)
415 : RasterizeHelper(std::unique_ptr<SvgRasterizeThread>(new SvgRasterizeThread(svgRasterizeManager)), svgRasterizeManager)
416 {
417 }
418
419 SvgRasterizeManager::RasterizeHelper::RasterizeHelper(RasterizeHelper&& rhs)
420 : RasterizeHelper(std::move(rhs.mRasterizer), rhs.mSvgRasterizeManager)
421 {
422 }
423
424 SvgRasterizeManager::RasterizeHelper::RasterizeHelper(std::unique_ptr<SvgRasterizeThread> rasterizer, SvgRasterizeManager& svgRasterizeManager)
425 : mRasterizer(std::move(rasterizer)),
426   mSvgRasterizeManager(svgRasterizeManager)
427 {
428 }
429
430 bool SvgRasterizeManager::RasterizeHelper::RequestRasterize()
431 {
432   return mRasterizer->RequestRasterize();
433 }
434 } // namespace Internal
435
436 } // namespace Toolkit
437
438 } // namespace Dali