Set the thread name (image/svg)
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-rasterize-thread.cpp
1 /*
2  * Copyright (c) 2016 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 // INTERNAL INCLUDES
22 #include <dali-toolkit/third-party/nanosvg/nanosvgrast.h>
23 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
24 #include <dali/devel-api/adaptor-framework/thread-settings.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 RasterizingTask::RasterizingTask( SvgVisual* svgRenderer, NSVGimage* parsedSvg, unsigned int width, unsigned int height )
36 : mSvgVisual( svgRenderer ),
37   mParsedSvg( parsedSvg ),
38   mWidth( width ),
39   mHeight( height )
40 {
41 }
42
43 void RasterizingTask::Rasterize( NSVGrasterizer* rasterizer )
44 {
45   if( mWidth > 0u && mHeight > 0u )
46   {
47     float scaleX =  static_cast<float>( mWidth ) /  mParsedSvg->width;
48     float scaleY =  static_cast<float>( mHeight ) /  mParsedSvg->height;
49     float scale = scaleX < scaleY ? scaleX : scaleY;
50     unsigned int bufferStride = mWidth*Pixel::GetBytesPerPixel( Pixel::RGBA8888 );
51     unsigned int bufferSize = bufferStride * mHeight;
52
53     unsigned char* buffer = new unsigned char [bufferSize];
54     nsvgRasterize(rasterizer, mParsedSvg, 0.f,0.f,scale,
55         buffer, mWidth, mHeight,
56         bufferStride );
57
58     mPixelData = Dali::PixelData::New( buffer, bufferSize, mWidth, mHeight, Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY );
59   }
60 }
61
62 SvgVisual* RasterizingTask::GetSvgVisual() const
63 {
64   return mSvgVisual.Get();
65 }
66
67 PixelData RasterizingTask::GetPixelData() const
68 {
69   return mPixelData;
70 }
71
72 SvgRasterizeThread::SvgRasterizeThread( EventThreadCallback* trigger )
73 : mTrigger( trigger ),
74   mIsThreadWaiting( false )
75 {
76   mRasterizer = nsvgCreateRasterizer();
77 }
78
79 SvgRasterizeThread::~SvgRasterizeThread()
80 {
81
82   nsvgDeleteRasterizer( mRasterizer );
83   delete mTrigger;
84 }
85
86 void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread )
87 {
88   if( thread )
89   {
90     // add an empty task would stop the thread from conditional wait.
91     thread->AddTask( RasterizingTaskPtr() );
92     // stop the thread
93     thread->Join();
94     // delete the thread
95     delete thread;
96     thread = NULL;
97   }
98 }
99
100 void SvgRasterizeThread::AddTask( RasterizingTaskPtr task )
101 {
102   bool wasEmpty = false;
103
104   {
105     // Lock while adding task to the queue
106     ConditionalWait::ScopedLock lock( mConditionalWait );
107     wasEmpty = mRasterizeTasks.empty();
108     if( !wasEmpty && task != NULL)
109     {
110       // Remove the tasks with the same renderer.
111       // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
112       for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
113       {
114         if( (*it) && (*it)->GetSvgVisual() == task->GetSvgVisual() )
115         {
116           mRasterizeTasks.erase( it );
117           break;
118         }
119       }
120     }
121     mRasterizeTasks.push_back( task );
122   }
123
124   if( wasEmpty)
125   {
126     // wake up the image loading thread
127     mConditionalWait.Notify();
128   }
129 }
130
131 RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
132 {
133   // Lock while popping task out from the queue
134   Mutex::ScopedLock lock( mMutex );
135
136   if( mCompletedTasks.empty() )
137   {
138     return RasterizingTaskPtr();
139   }
140
141   std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin();
142   RasterizingTaskPtr nextTask = *next;
143   mCompletedTasks.erase( next );
144
145   return nextTask;
146 }
147
148 void SvgRasterizeThread::RemoveTask( SvgVisual* visual )
149 {
150   // Lock while remove task from the queue
151   ConditionalWait::ScopedLock lock( mConditionalWait );
152   if( !mRasterizeTasks.empty() )
153   {
154     for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
155     {
156       if( (*it) &&  (*it)->GetSvgVisual() == visual )
157       {
158         mRasterizeTasks.erase( it );
159         break;
160       }
161     }
162   }
163 }
164
165 void SvgRasterizeThread::DeleteImage( NSVGimage* parsedSvg )
166 {
167   // Lock while adding image to the delete queue
168   ConditionalWait::ScopedLock lock( mConditionalWait );
169
170   if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
171   {
172     nsvgDelete( parsedSvg );
173   }
174   else // wait to delete until current rasterization completed.
175   {
176     mDeleteSvg.PushBack( parsedSvg );
177   }
178 }
179
180 RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
181 {
182   // Lock while popping task out from the queue
183   ConditionalWait::ScopedLock lock( mConditionalWait );
184
185   // Delete the image here to make sure that it is not used in the nsvgRasterize()
186   if( !mDeleteSvg.Empty() )
187   {
188     for( Vector< NSVGimage* >::Iterator it = mDeleteSvg.Begin(), endIt = mDeleteSvg.End();
189         it != endIt;
190         ++it )
191     {
192       nsvgDelete( *it );
193     }
194     mDeleteSvg.Clear();
195   }
196
197   // conditional wait
198   while( mRasterizeTasks.empty() )
199   {
200     mIsThreadWaiting = true;
201     mConditionalWait.Wait( lock );
202   }
203   mIsThreadWaiting = false;
204
205   // pop out the next task from the queue
206   std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin();
207   RasterizingTaskPtr nextTask = *next;
208   mRasterizeTasks.erase( next );
209
210   return nextTask;
211 }
212
213 void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task )
214 {
215   // Lock while adding task to the queue
216   Mutex::ScopedLock lock( mMutex );
217   mCompletedTasks.push_back( task );
218
219   // wake up the main thread
220   mTrigger->Trigger();
221 }
222
223 void SvgRasterizeThread::Run()
224 {
225   SetThreadName( "SVGThread" );
226   while( RasterizingTaskPtr task = NextTaskToProcess() )
227   {
228     task->Rasterize( mRasterizer );
229     AddCompletedTask( task );
230   }
231 }
232
233 } // namespace Internal
234
235 } // namespace Toolkit
236
237 } // namespace Dali