2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "svg-rasterize-thread.h"
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>
29 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
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";
42 size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
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;
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gVectorImageLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_IMAGE");
55 } // unnamed namespace
57 SvgTask::SvgTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer)
58 : mSvgVisual(svgVisual),
59 mVectorRenderer(vectorRenderer),
64 SvgVisual* SvgTask::GetSvgVisual() const
66 return mSvgVisual.Get();
69 PixelData SvgTask::GetPixelData() const
74 bool SvgTask::HasSucceeded() const
79 SvgLoadingTask::SvgLoadingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi)
80 : SvgTask(svgVisual, vectorRenderer),
86 SvgLoadingTask::~SvgLoadingTask()
90 void SvgLoadingTask::Process()
92 if(mVectorRenderer.IsLoaded())
99 Dali::Vector<uint8_t> buffer;
101 if(!mUrl.IsLocalResource())
103 if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), buffer))
105 DALI_LOG_ERROR("Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
111 if(!Dali::FileLoader::ReadFile(mUrl.GetUrl(), buffer))
113 DALI_LOG_ERROR("Failed to read file! [%s]\n", mUrl.GetUrl().c_str());
118 buffer.PushBack('\0');
120 if(!mVectorRenderer.Load(buffer, mDpi))
122 DALI_LOG_ERROR("Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
126 mHasSucceeded = true;
129 SvgRasterizingTask::SvgRasterizingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, unsigned int width, unsigned int height)
130 : SvgTask(svgVisual, vectorRenderer),
136 SvgRasterizingTask::~SvgRasterizingTask()
140 void SvgRasterizingTask::Process()
142 if(!mVectorRenderer.IsLoaded())
144 DALI_LOG_ERROR("File is not loaded!\n");
148 DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "Rasterize: (%d x %d) [%p]\n", mWidth, mHeight, this);
150 Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
153 DALI_LOG_ERROR("Rasterize is failed!\n");
157 mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
158 mHasSucceeded = true;
161 bool SvgRasterizingTask::IsReady()
163 return mVectorRenderer.IsLoaded();
166 PixelData SvgRasterizingTask::GetPixelData() const
171 SvgRasterizeThread::SvgRasterizeThread(SvgRasterizeManager& svgRasterizeManager)
172 : mConditionalWait(),
173 mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
174 mSvgRasterizeManager(svgRasterizeManager),
175 mDestroyThread(false),
176 mIsThreadStarted(false),
181 SvgRasterizeThread::~SvgRasterizeThread()
185 ConditionalWait::ScopedLock lock(mConditionalWait);
186 mDestroyThread = true;
187 mConditionalWait.Notify(lock);
193 bool SvgRasterizeThread::RequestRasterize()
195 if(!mIsThreadStarted)
198 mIsThreadStarted = true;
202 // Lock while adding task to the queue
203 ConditionalWait::ScopedLock lock(mConditionalWait);
207 mIsThreadIdle = false;
209 // wake up the thread
210 mConditionalWait.Notify(lock);
218 void SvgRasterizeThread::Run()
220 SetThreadName("SvgRasterizeThread");
221 mLogFactory.InstallLogFunction();
223 while(!mDestroyThread)
225 SvgTaskPtr task = mSvgRasterizeManager.NextTaskToProcess();
228 ConditionalWait::ScopedLock lock(mConditionalWait);
229 mIsThreadIdle = true;
230 mConditionalWait.Wait(lock);
236 mSvgRasterizeManager.AddCompletedTask(task);
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)
248 SvgRasterizeManager::~SvgRasterizeManager()
250 if(mProcessorRegistered)
252 Adaptor::Get().UnregisterProcessor(*this);
255 mRasterizers.Clear();
258 void SvgRasterizeManager::AddTask(SvgTaskPtr task)
261 // Lock while adding task to the queue
262 Mutex::ScopedLock lock(mMutex);
264 // There are other tasks waiting for the rasterization
265 if(!mRasterizeTasks.empty())
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)
272 if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual())
274 SvgRasterizingTask* oldTask = dynamic_cast<SvgRasterizingTask*>(it->Get());
275 SvgRasterizingTask* newTask = dynamic_cast<SvgRasterizingTask*>(task.Get());
276 if(oldTask && newTask)
278 mRasterizeTasks.erase(it);
285 mRasterizeTasks.push_back(task);
288 size_t count = mRasterizers.GetElementCount();
290 while(index++ < count)
292 auto rasterizerHelperIt = mRasterizers.GetNext();
293 DALI_ASSERT_ALWAYS(rasterizerHelperIt != mRasterizers.End());
295 if(rasterizerHelperIt->RequestRasterize())
299 // If all threads are busy, then it's ok just to push the task because they will try to get the next job.
302 if(!mProcessorRegistered)
304 Adaptor::Get().RegisterProcessor(*this);
305 mProcessorRegistered = true;
311 SvgTaskPtr SvgRasterizeManager::NextCompletedTask()
313 // Lock while popping task out from the queue
314 Mutex::ScopedLock lock(mMutex);
316 if(mCompletedTasks.empty())
321 std::vector<SvgTaskPtr>::iterator next = mCompletedTasks.begin();
322 SvgTaskPtr nextTask = *next;
323 mCompletedTasks.erase(next);
328 void SvgRasterizeManager::RemoveTask(SvgVisual* visual)
331 // Lock while remove task from the queue
332 Mutex::ScopedLock lock(mMutex);
333 if(!mRasterizeTasks.empty())
335 for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(); it != mRasterizeTasks.end();)
337 if((*it) && (*it)->GetSvgVisual() == visual)
339 it = mRasterizeTasks.erase(it);
349 UnregisterProcessor();
352 SvgTaskPtr SvgRasterizeManager::NextTaskToProcess()
354 // Lock while popping task out from the queue
355 Mutex::ScopedLock lock(mMutex);
357 // pop out the next task from the queue
358 SvgTaskPtr nextTask = nullptr;
360 for(auto iter = mRasterizeTasks.begin(), endIter = mRasterizeTasks.end(); iter != endIter; ++iter)
362 if((*iter)->IsReady())
365 mRasterizeTasks.erase(iter);
373 void SvgRasterizeManager::AddCompletedTask(SvgTaskPtr task)
375 // Lock while adding task to the queue
376 Mutex::ScopedLock lock(mMutex);
377 mCompletedTasks.push_back(task);
379 // wake up the main thread
383 void SvgRasterizeManager::ApplyRasterizedSVGToSampler()
385 while(SvgTaskPtr task = NextCompletedTask())
387 DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "task = %p\n", task.Get());
389 task->GetSvgVisual()->ApplyRasterizedImage(task->GetPixelData(), task->HasSucceeded());
392 UnregisterProcessor();
395 void SvgRasterizeManager::Process(bool postProcessor)
397 ApplyRasterizedSVGToSampler();
400 void SvgRasterizeManager::UnregisterProcessor()
402 Mutex::ScopedLock lock(mMutex);
404 if(mProcessorRegistered)
406 if(mRasterizeTasks.empty() && mCompletedTasks.empty())
408 Adaptor::Get().UnregisterProcessor(*this);
409 mProcessorRegistered = false;
414 SvgRasterizeManager::RasterizeHelper::RasterizeHelper(SvgRasterizeManager& svgRasterizeManager)
415 : RasterizeHelper(std::unique_ptr<SvgRasterizeThread>(new SvgRasterizeThread(svgRasterizeManager)), svgRasterizeManager)
419 SvgRasterizeManager::RasterizeHelper::RasterizeHelper(RasterizeHelper&& rhs)
420 : RasterizeHelper(std::move(rhs.mRasterizer), rhs.mSvgRasterizeManager)
424 SvgRasterizeManager::RasterizeHelper::RasterizeHelper(std::unique_ptr<SvgRasterizeThread> rasterizer, SvgRasterizeManager& svgRasterizeManager)
425 : mRasterizer(std::move(rasterizer)),
426 mSvgRasterizeManager(svgRasterizeManager)
430 bool SvgRasterizeManager::RasterizeHelper::RequestRasterize()
432 return mRasterizer->RequestRasterize();
434 } // namespace Internal
436 } // namespace Toolkit