Merge "Dummy graphics controller for test suite" into devel/graphics
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-rasterize-thread.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
18 // CLASS HEADER
19 #include "svg-rasterize-thread.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/file-loader.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
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
29
30 namespace Dali
31 {
32 namespace Toolkit
33 {
34 namespace Internal
35 {
36 RasterizingTask::RasterizingTask(SvgVisual* svgRenderer, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, unsigned int width, unsigned int height)
37 : mSvgVisual(svgRenderer),
38   mVectorRenderer(vectorRenderer),
39   mUrl(url),
40   mDpi(dpi),
41   mWidth(width),
42   mHeight(height),
43   mLoadSuccess(false)
44 {
45 }
46
47 RasterizingTask::~RasterizingTask()
48 {
49 }
50
51 void RasterizingTask::Load()
52 {
53   if(!mUrl.IsLocalResource())
54   {
55     Dali::Vector<uint8_t> remoteBuffer;
56     if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), remoteBuffer))
57     {
58       DALI_LOG_ERROR("RasterizingTask::Load: Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
59       return;
60     }
61
62     remoteBuffer.PushBack('\0');
63
64     if(!mVectorRenderer.Load(remoteBuffer, mDpi))
65     {
66       DALI_LOG_ERROR("RasterizingTask::Load:Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
67       return;
68     }
69
70     mLoadSuccess = true;
71   }
72   else
73   {
74     mLoadSuccess = true;
75   }
76 }
77
78 void RasterizingTask::Rasterize()
79 {
80   if(mWidth <= 0u || mHeight <= 0u)
81   {
82     DALI_LOG_ERROR("RasterizingTask::Rasterize: Size is zero!\n");
83     return;
84   }
85
86   Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(mWidth, mHeight, Dali::Pixel::RGBA8888);
87
88   uint32_t defaultWidth, defaultHeight;
89   mVectorRenderer.GetDefaultSize(defaultWidth, defaultHeight);
90
91   float scaleX = static_cast<float>(mWidth) / static_cast<float>(defaultWidth);
92   float scaleY = static_cast<float>(mHeight) / static_cast<float>(defaultHeight);
93   float scale  = scaleX < scaleY ? scaleX : scaleY;
94
95   if(!mVectorRenderer.Rasterize(pixelBuffer, scale))
96   {
97     DALI_LOG_ERROR("RasterizingTask::Rasterize: Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
98     return;
99   }
100
101   mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
102 }
103
104 VectorImageRenderer RasterizingTask::GetVectorRenderer() const
105 {
106   return mVectorRenderer;
107 }
108
109 bool RasterizingTask::IsLoaded() const
110 {
111   return mLoadSuccess;
112 }
113
114 SvgVisual* RasterizingTask::GetSvgVisual() const
115 {
116   return mSvgVisual.Get();
117 }
118
119 PixelData RasterizingTask::GetPixelData() const
120 {
121   return mPixelData;
122 }
123
124 SvgRasterizeThread::SvgRasterizeThread()
125 : mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler))),
126   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
127   mIsThreadWaiting(false),
128   mProcessorRegistered(false)
129 {
130 }
131
132 SvgRasterizeThread::~SvgRasterizeThread()
133 {
134   if(mProcessorRegistered)
135   {
136     Adaptor::Get().UnregisterProcessor(*this);
137   }
138 }
139
140 void SvgRasterizeThread::TerminateThread(SvgRasterizeThread*& thread)
141 {
142   if(thread)
143   {
144     // add an empty task would stop the thread from conditional wait.
145     thread->AddTask(RasterizingTaskPtr());
146     // stop the thread
147     thread->Join();
148     // delete the thread
149     delete thread;
150     thread = NULL;
151   }
152 }
153
154 void SvgRasterizeThread::AddTask(RasterizingTaskPtr task)
155 {
156   bool wasEmpty = false;
157
158   {
159     // Lock while adding task to the queue
160     ConditionalWait::ScopedLock lock(mConditionalWait);
161     wasEmpty = mRasterizeTasks.empty();
162     if(!wasEmpty && task != NULL)
163     {
164       // Remove the tasks with the same renderer.
165       // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
166       for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
167       {
168         if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual())
169         {
170           mRasterizeTasks.erase(it);
171           break;
172         }
173       }
174     }
175     mRasterizeTasks.push_back(task);
176
177     if(!mProcessorRegistered)
178     {
179       Adaptor::Get().RegisterProcessor(*this);
180       mProcessorRegistered = true;
181     }
182   }
183
184   if(wasEmpty)
185   {
186     // wake up the image loading thread
187     mConditionalWait.Notify();
188   }
189 }
190
191 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
192 {
193   // Lock while popping task out from the queue
194   Mutex::ScopedLock lock(mMutex);
195
196   if(mCompletedTasks.empty())
197   {
198     return RasterizingTaskPtr();
199   }
200
201   std::vector<RasterizingTaskPtr>::iterator next     = mCompletedTasks.begin();
202   RasterizingTaskPtr                        nextTask = *next;
203   mCompletedTasks.erase(next);
204
205   return nextTask;
206 }
207
208 void SvgRasterizeThread::RemoveTask(SvgVisual* visual)
209 {
210   // Lock while remove task from the queue
211   ConditionalWait::ScopedLock lock(mConditionalWait);
212   if(!mRasterizeTasks.empty())
213   {
214     for(std::vector<RasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
215     {
216       if((*it) && (*it)->GetSvgVisual() == visual)
217       {
218         mRasterizeTasks.erase(it);
219         break;
220       }
221     }
222   }
223
224   UnregisterProcessor();
225 }
226
227 void SvgRasterizeThread::DeleteImage(VectorImageRenderer vectorRenderer)
228 {
229   // Lock while adding image to the delete queue
230   ConditionalWait::ScopedLock lock(mConditionalWait);
231
232   if(mIsThreadWaiting) // no rasterization is ongoing, save to delete
233   {
234     // TODO: what?
235   }
236   else // wait to delete until current rasterization completed.
237   {
238     mDeleteSvg.PushBack(&vectorRenderer);
239   }
240 }
241
242 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
243 {
244   // Lock while popping task out from the queue
245   ConditionalWait::ScopedLock lock(mConditionalWait);
246
247   // Delete the image here to make sure that it is not used in the nsvgRasterize()
248   if(!mDeleteSvg.Empty())
249   {
250     mDeleteSvg.Clear();
251   }
252
253   // conditional wait
254   while(mRasterizeTasks.empty())
255   {
256     mIsThreadWaiting = true;
257     mConditionalWait.Wait(lock);
258   }
259   mIsThreadWaiting = false;
260
261   // pop out the next task from the queue
262   std::vector<RasterizingTaskPtr>::iterator next     = mRasterizeTasks.begin();
263   RasterizingTaskPtr                        nextTask = *next;
264   mRasterizeTasks.erase(next);
265
266   return nextTask;
267 }
268
269 void SvgRasterizeThread::AddCompletedTask(RasterizingTaskPtr task)
270 {
271   // Lock while adding task to the queue
272   Mutex::ScopedLock lock(mMutex);
273   mCompletedTasks.push_back(task);
274
275   // wake up the main thread
276   mTrigger->Trigger();
277 }
278
279 void SvgRasterizeThread::Run()
280 {
281   SetThreadName("SVGThread");
282   mLogFactory.InstallLogFunction();
283
284   while(RasterizingTaskPtr task = NextTaskToProcess())
285   {
286     task->Load();
287     task->Rasterize();
288     AddCompletedTask(task);
289   }
290 }
291
292 void SvgRasterizeThread::ApplyRasterizedSVGToSampler()
293 {
294   while(RasterizingTaskPtr task = NextCompletedTask())
295   {
296     task->GetSvgVisual()->ApplyRasterizedImage(task->GetVectorRenderer(), task->GetPixelData(), task->IsLoaded());
297   }
298
299   UnregisterProcessor();
300 }
301
302 void SvgRasterizeThread::Process()
303 {
304   ApplyRasterizedSVGToSampler();
305 }
306
307 void SvgRasterizeThread::UnregisterProcessor()
308 {
309   if(mProcessorRegistered)
310   {
311     if(mRasterizeTasks.empty() && mCompletedTasks.empty())
312     {
313       Adaptor::Get().UnregisterProcessor(*this);
314       mProcessorRegistered = false;
315     }
316   }
317 }
318
319 } // namespace Internal
320
321 } // namespace Toolkit
322
323 } // namespace Dali