97835c5abcb60893a0a37ff78504a27a5a0b27db
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / canvas-view / canvas-view-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 "canvas-view-rasterize-thread.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/thread-settings.h>
23 #include <dali/integration-api/adaptor-framework/adaptor.h>
24
25 namespace Dali
26 {
27 namespace Toolkit
28 {
29 namespace Internal
30 {
31 CanvasRendererRasterizingTask::CanvasRendererRasterizingTask(CanvasView* canvasView, CanvasRenderer canvasRenderer)
32 : mCanvasView(canvasView),
33   mCanvasRenderer(canvasRenderer),
34   mPixelData(PixelData()),
35   mBufferSize(0, 0)
36 {
37 }
38
39 bool CanvasRendererRasterizingTask::Rasterize()
40 {
41   if(mCanvasRenderer && mCanvasRenderer.Rasterize())
42   {
43     Devel::PixelBuffer pixbuf = mCanvasRenderer.GetPixelBuffer();
44     auto               width  = pixbuf.GetWidth();
45     auto               height = pixbuf.GetHeight();
46     if(width > 0 && height > 0)
47     {
48       mBufferSize.width  = width;
49       mBufferSize.height = height;
50
51       mPixelData = Devel::PixelBuffer::Convert(pixbuf);
52       return true;
53     }
54   }
55   return false;
56 }
57
58 CanvasView* CanvasRendererRasterizingTask::GetCanvasView() const
59 {
60   return mCanvasView.Get();
61 }
62
63 PixelData CanvasRendererRasterizingTask::GetPixelData() const
64 {
65   return mPixelData;
66 }
67
68 Vector2 CanvasRendererRasterizingTask::GetBufferSize() const
69 {
70   return mBufferSize;
71 }
72
73 CanvasViewRasterizeThread::CanvasViewRasterizeThread()
74 : mTrigger(new EventThreadCallback(MakeCallback(this, &CanvasViewRasterizeThread::ApplyRasterized))),
75   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
76   mProcessorRegistered(false),
77   mRasterizationCompletedSignal()
78 {
79 }
80
81 CanvasViewRasterizeThread::~CanvasViewRasterizeThread()
82 {
83   if(mProcessorRegistered && Adaptor::IsAvailable())
84   {
85     Adaptor::Get().UnregisterProcessor(*this);
86   }
87 }
88
89 void CanvasViewRasterizeThread::TerminateThread(CanvasViewRasterizeThread*& thread)
90 {
91   if(thread)
92   {
93     // add an empty task would stop the thread from conditional wait.
94     thread->AddTask(CanvasRendererRasterizingTaskPtr());
95     // stop the thread
96     thread->Join();
97     // delete the thread
98     delete thread;
99     thread = NULL;
100   }
101 }
102
103 void CanvasViewRasterizeThread::AddTask(CanvasRendererRasterizingTaskPtr task)
104 {
105   bool wasEmpty = false;
106
107   {
108     // Lock while adding task to the queue
109     ConditionalWait::ScopedLock lock(mConditionalWait);
110     wasEmpty = mRasterizeTasks.empty();
111     if(!wasEmpty && task != NULL)
112     {
113       // Remove the tasks with the same renderer.
114       // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
115       for(std::vector<CanvasRendererRasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
116       {
117         if((*it) && (*it)->GetCanvasView() == task->GetCanvasView()) //Need
118         {
119           mRasterizeTasks.erase(it);
120           break;
121         }
122       }
123     }
124     mRasterizeTasks.push_back(task);
125
126     if(!mProcessorRegistered && Adaptor::IsAvailable())
127     {
128       Adaptor::Get().RegisterProcessor(*this);
129       mProcessorRegistered = true;
130     }
131   }
132
133   if(wasEmpty)
134   {
135     // wake up the image loading thread
136     mConditionalWait.Notify();
137   }
138 }
139
140 CanvasRendererRasterizingTaskPtr CanvasViewRasterizeThread::NextCompletedTask()
141 {
142   // Lock while popping task out from the queue
143   Mutex::ScopedLock lock(mMutex);
144
145   if(mCompletedTasks.empty())
146   {
147     return CanvasRendererRasterizingTaskPtr();
148   }
149
150   std::vector<CanvasRendererRasterizingTaskPtr>::iterator next     = mCompletedTasks.begin();
151   CanvasRendererRasterizingTaskPtr                        nextTask = *next;
152   mCompletedTasks.erase(next);
153
154   return nextTask;
155 }
156
157 void CanvasViewRasterizeThread::RemoveTask(CanvasView* canvasView)
158 {
159   // Lock while remove task from the queue
160   ConditionalWait::ScopedLock lock(mConditionalWait);
161   if(!mRasterizeTasks.empty())
162   {
163     for(std::vector<CanvasRendererRasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
164     {
165       if((*it) && (*it)->GetCanvasView() == canvasView)
166       {
167         mRasterizeTasks.erase(it);
168         break;
169       }
170     }
171   }
172
173   UnregisterProcessor();
174 }
175
176 CanvasRendererRasterizingTaskPtr CanvasViewRasterizeThread::NextTaskToProcess()
177 {
178   // Lock while popping task out from the queue
179   ConditionalWait::ScopedLock lock(mConditionalWait);
180
181   // conditional wait
182   while(mRasterizeTasks.empty())
183   {
184     mConditionalWait.Wait(lock);
185   }
186
187   // pop out the next task from the queue
188   std::vector<CanvasRendererRasterizingTaskPtr>::iterator next     = mRasterizeTasks.begin();
189   CanvasRendererRasterizingTaskPtr                        nextTask = *next;
190   mRasterizeTasks.erase(next);
191
192   return nextTask;
193 }
194
195 void CanvasViewRasterizeThread::AddCompletedTask(CanvasRendererRasterizingTaskPtr task)
196 {
197   // Lock while adding task to the queue
198   Mutex::ScopedLock lock(mMutex);
199   mCompletedTasks.push_back(task);
200
201   // wake up the main thread
202   mTrigger->Trigger();
203 }
204
205 void CanvasViewRasterizeThread::Run()
206 {
207   SetThreadName("CanvasViewThread");
208   mLogFactory.InstallLogFunction();
209
210   while(CanvasRendererRasterizingTaskPtr task = NextTaskToProcess())
211   {
212     if(task->Rasterize())
213     {
214       AddCompletedTask(task);
215     }
216   }
217 }
218
219 void CanvasViewRasterizeThread::ApplyRasterized()
220 {
221   while(CanvasRendererRasterizingTaskPtr task = NextCompletedTask())
222   {
223     RasterizationCompletedSignal().Emit(task->GetPixelData());
224   }
225
226   UnregisterProcessor();
227 }
228
229 void CanvasViewRasterizeThread::Process(bool postProcessor)
230 {
231   ApplyRasterized();
232 }
233
234 CanvasViewRasterizeThread::RasterizationCompletedSignalType& CanvasViewRasterizeThread::RasterizationCompletedSignal()
235 {
236   return mRasterizationCompletedSignal;
237 }
238
239 void CanvasViewRasterizeThread::UnregisterProcessor()
240 {
241   if(mProcessorRegistered)
242   {
243     if(mRasterizeTasks.empty() && mCompletedTasks.empty() && Adaptor::IsAvailable())
244     {
245       Adaptor::Get().UnregisterProcessor(*this);
246       mProcessorRegistered = false;
247     }
248   }
249 }
250
251 } // namespace Internal
252
253 } // namespace Toolkit
254
255 } // namespace Dali