namespace
{
Dali::Internal::Adaptor::VectorImageRenderer* gVectorImageRenderer = nullptr;
+
+/**
+ * @brief Check whether the data contain keyword as substring or not.
+ * It can be used as Naive Check-up to determine vector image loaded successfully or not.
+ *
+ * @param[in] data Raw data
+ * @param[in] keyword Keyword to check data holded or not.
+ * @return True if data contain keyword.
+ */
+bool CheckKeywordExist(const Vector<uint8_t>& data, std::string keyword)
+{
+ std::string trimedString;
+
+ // Remove useless character in data.
+ for(const uint8_t& it : data)
+ {
+ if(keyword.find(it) != std::string::npos)
+ {
+ trimedString.push_back(it);
+ }
+ }
+
+ if(trimedString.length() >= keyword.length())
+ {
+ if(trimedString.find(keyword) != std::string::npos)
+ {
+ return true;
+ }
+ }
+ return false;
}
+} // namespace
class VectorImageRenderer : public Dali::BaseObject
{
{
mRasterizeSuccess = false;
}
+ // Naive check-up whether data is valid format or not. Currently we only check svg and tvg file format.
+ else if(!CheckKeywordExist(data, "</svg>") && !CheckKeywordExist(data, "ThorVG"))
+ {
+ return false;
+ }
mLoadSuccess = true;
return true;
}
const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/application-icon-%02d.png";
const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
const char* TEST_MASK_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/mask.png";
+const char* TEST_WEBP_FILE_NAME = TEST_RESOURCE_DIR "/dali-logo.webp";
} // namespace
void CopyUrlsIntoArray(Property::Array& urls, int startIndex = 0)
END_TEST;
}
+
+int UtcDaliAnimatedImageVisualWrapMode(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliAnimatedImageVisualWrapMode");
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK(factory);
+
+ // Test wrap mode in animated image visual.
+ const int width = 950;
+ const int height = 1080;
+ const Vector4 pixelArea(0.0f, 0.0f, 950/ 40, 1.0f);
+
+ Property::Map propertyMap;
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_WEBP_FILE_NAME);
+ propertyMap.Insert(ImageVisual::Property::PIXEL_AREA, pixelArea);
+ propertyMap.Insert(ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT);
+
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+ textureTrace.EnableLogging(true);
+ TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+ texParameterTrace.Enable(true);
+ texParameterTrace.EnableLogging(true);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+ actor.SetProperty(Actor::Property::SIZE, Vector2(width, height));
+ actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 0u, TEST_LOCATION);
+ application.GetScene().Add(actor);
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+ // WITHOUT atlasing, the wrapping is handled by setting gl texture parameters
+ std::stringstream out;
+ out << std::hex << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_REPEAT;
+ DALI_TEST_CHECK(texParameterTrace.FindMethodAndParams("TexParameteri", out.str()));
+
+ // test the uniforms which used to handle the wrap mode
+ Renderer renderer = actor.GetRendererAt(0u);
+ DALI_TEST_CHECK(renderer);
+
+ Property::Value pixelAreaValue = renderer.GetProperty(renderer.GetPropertyIndex("pixelArea"));
+ DALI_TEST_EQUALS(pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION);
+
+ actor.Unparent();
+ DALI_TEST_CHECK(actor.GetRendererCount() == 0u);
+
+ END_TEST;
+}
// FILE HEADER\r
#include <dali-scene-loader/public-api/facial-animation-loader.h>\r
\r
+// EXTERNAL INCLUDES\r
+#include <sstream>\r
+\r
// INTERNAL INCLUDES\r
#include <dali-scene-loader/internal/json-reader.h>\r
#include <dali-scene-loader/public-api/blend-shape-details.h>\r
}\r
\r
// Set the property names\r
- char weightNameBuffer[32];\r
- char* const pWeightName = weightNameBuffer + sprintf(weightNameBuffer, "%s", BlendShapes::WEIGHTS_UNIFORM.c_str());\r
- uint32_t targets = 0u;\r
+ uint32_t targets = 0u;\r
for(const auto& blendShape : facialAnimation.mBlendShapes)\r
{\r
for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)\r
\r
animatedProperty.mNodeName = blendShape.mNodeName;\r
\r
- snprintf(pWeightName, sizeof(weightNameBuffer) - (pWeightName - weightNameBuffer), "[%d]", morphTargetIndex);\r
- animatedProperty.mPropertyName = weightNameBuffer;\r
+ std::stringstream weightPropertyStream;\r
+ weightPropertyStream << BlendShapes::WEIGHTS_UNIFORM << "[" << morphTargetIndex << "]";\r
+ animatedProperty.mPropertyName = weightPropertyStream.str();\r
}\r
targets += blendShape.mNumberOfMorphTarget;\r
}\r
#define DALI_TOOLKIT_INTERNAL_ROUND_ROBIN_CONTAINER_VIEW_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
/**
+ * @brief Clear all elements.
+ */
+ void Clear()
+ {
+ mElements.clear();
+ }
+
+ /**
* @brief Reset the position of the iterator returned by GetNext() to the first element.
*/
void Reset()
return mElements.cend();
}
+ /**
+ * @brief Returns the element count.
+ * @return The element count
+ */
+ size_t GetElementCount() const
+ {
+ return mElements.size();
+ }
+
// default members
~RoundRobinContainerView() = default;
if(mAnimatedImageLoading)
{
- mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, IsSynchronousLoadingRequired(), mFactoryCache.GetPreMultiplyOnLoad());
+ mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, mWrapModeU, mWrapModeV, IsSynchronousLoadingRequired(), mFactoryCache.GetPreMultiplyOnLoad());
}
else if(mImageUrls)
{
ImageCache::FrameReadyObserver& observer,
uint16_t cacheSize,
uint16_t batchSize,
+ const Dali::WrapMode::Type& wrapModeU,
+ const Dali::WrapMode::Type& wrapModeV,
bool isSynchronousLoading,
bool preMultiplyOnLoad)
: ImageCache(textureManager, maskingData, observer, batchSize, 0u),
mFrameIndex(FIRST_FRAME_INDEX),
mCacheSize(cacheSize),
mQueue(cacheSize),
+ mWrapModeU(wrapModeU),
+ mWrapModeV(wrapModeV),
mIsSynchronousLoading(isSynchronousLoading),
mPreMultiplyOnLoad(preMultiplyOnLoad)
{
loadTextureId,
mMaskingData,
SamplingMode::BOX_THEN_LINEAR,
- Dali::WrapMode::Type::DEFAULT,
- Dali::WrapMode::Type::DEFAULT,
+ mWrapModeU,
+ mWrapModeV,
synchronousLoading,
this,
preMultiplyOnLoading);
DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId);
LOG_CACHE;
- MakeFrameReady(loadSuccess, mTextureManager.GetTextureSet(textureInformation.textureId), textureInformation.interval);
+ TextureSet textureSet = mTextureManager.GetTextureSet(textureInformation.textureId);
+ if(textureSet)
+ {
+ Sampler sampler = Sampler::New();
+ sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+ textureSet.SetSampler(0u, sampler);
+ }
+
+ MakeFrameReady(loadSuccess, textureSet, textureInformation.interval);
if(loadSuccess)
{
* @param[in] observer FrameReady observer
* @param[in] cacheSize The size of the cache
* @param[in] batchSize The size of a batch to load
+ * @param[in] wrapModeU Horizontal Wrap mode
+ * @param[in] wrapModeV Vertical Wrap mode
* @param[in] isSynchronousLoading The flag to define whether to load first frame synchronously
+ * @param[in] preMultiplyOnLoad The flag if image's color should be multiplied by it's alpha
*
* This will start loading textures immediately, according to the
* batch and cache sizes.
ImageCache::FrameReadyObserver& observer,
uint16_t cacheSize,
uint16_t batchSize,
+ const Dali::WrapMode::Type& wrapModeU,
+ const Dali::WrapMode::Type& wrapModeV,
bool isSynchronousLoading,
bool preMultiplyOnLoad);
std::vector<int32_t> mIntervals;
std::vector<uint32_t> mLoadWaitingQueue;
CircularQueue<ImageFrame> mQueue;
+ Dali::WrapMode::Type mWrapModeU : 3;
+ Dali::WrapMode::Type mWrapModeV : 3;
bool mIsSynchronousLoading;
bool mPreMultiplyOnLoad;
};
#include "svg-rasterize-thread.h"
// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
#include <dali/devel-api/adaptor-framework/file-loader.h>
#include <dali/devel-api/adaptor-framework/thread-settings.h>
#include <dali/integration-api/adaptor-framework/adaptor.h>
{
namespace Internal
{
+namespace
+{
+constexpr auto DEFAULT_NUMBER_OF_SVG_RASTERIZE_THREADS = size_t{4u};
+constexpr auto NUMBER_OF_SVG_RASTERIZE_THREADS_ENV = "DALI_SVG_RASTERIZE_THREADS";
+
+size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
+{
+ auto numberString = EnvironmentVariable::GetEnvironmentVariable(environmentVariable);
+ auto numberOfThreads = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
+ constexpr auto MAX_NUMBER_OF_THREADS = 10u;
+ DALI_ASSERT_DEBUG(numberOfThreads < MAX_NUMBER_OF_THREADS);
+ return (numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS) ? numberOfThreads : defaultValue;
+}
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorImageLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_IMAGE");
+#endif
+
+} // unnamed namespace
+
SvgTask::SvgTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer)
: mSvgVisual(svgVisual),
mVectorRenderer(vectorRenderer),
return;
}
+ DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "Rasterize: (%d x %d) [%p]\n", mWidth, mHeight, this);
+
Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
if(!pixelBuffer)
{
mHasSucceeded = true;
}
+bool SvgRasterizingTask::IsReady()
+{
+ return mVectorRenderer.IsLoaded();
+}
+
PixelData SvgRasterizingTask::GetPixelData() const
{
return mPixelData;
}
-SvgRasterizeThread::SvgRasterizeThread()
-: mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeThread::ApplyRasterizedSVGToSampler))),
+SvgRasterizeThread::SvgRasterizeThread(SvgRasterizeManager& svgRasterizeManager)
+: mConditionalWait(),
mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
- mIsThreadWaiting(false),
- mProcessorRegistered(false)
+ mSvgRasterizeManager(svgRasterizeManager),
+ mDestroyThread(false),
+ mIsThreadStarted(false),
+ mIsThreadIdle(true)
{
}
SvgRasterizeThread::~SvgRasterizeThread()
{
- if(mProcessorRegistered)
+ // Stop the thread
{
- Adaptor::Get().UnregisterProcessor(*this);
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+ mDestroyThread = true;
+ mConditionalWait.Notify(lock);
}
+
+ Join();
}
-void SvgRasterizeThread::TerminateThread(SvgRasterizeThread*& thread)
+bool SvgRasterizeThread::RequestRasterize()
{
- if(thread)
+ if(!mIsThreadStarted)
{
- // add an empty task would stop the thread from conditional wait.
- thread->AddTask(SvgTaskPtr());
- // stop the thread
- thread->Join();
- // delete the thread
- delete thread;
- thread = NULL;
+ Start();
+ mIsThreadStarted = true;
}
+
+ {
+ // Lock while adding task to the queue
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+
+ if(mIsThreadIdle)
+ {
+ mIsThreadIdle = false;
+
+ // wake up the thread
+ mConditionalWait.Notify(lock);
+ return true;
+ }
+ }
+
+ return false;
}
-void SvgRasterizeThread::AddTask(SvgTaskPtr task)
+void SvgRasterizeThread::Run()
{
- bool wasEmpty = false;
+ SetThreadName("SvgRasterizeThread");
+ mLogFactory.InstallLogFunction();
+ while(!mDestroyThread)
+ {
+ SvgTaskPtr task = mSvgRasterizeManager.NextTaskToProcess();
+ if(!task)
+ {
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+ mIsThreadIdle = true;
+ mConditionalWait.Wait(lock);
+ }
+ else
+ {
+ task->Process();
+
+ mSvgRasterizeManager.AddCompletedTask(task);
+ }
+ }
+}
+
+SvgRasterizeManager::SvgRasterizeManager()
+: mRasterizers(GetNumberOfThreads(NUMBER_OF_SVG_RASTERIZE_THREADS_ENV, DEFAULT_NUMBER_OF_SVG_RASTERIZE_THREADS), [&]() { return RasterizeHelper(*this); }),
+ mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeManager::ApplyRasterizedSVGToSampler))),
+ mProcessorRegistered(false)
+{
+}
+
+SvgRasterizeManager::~SvgRasterizeManager()
+{
+ if(mProcessorRegistered)
+ {
+ Adaptor::Get().UnregisterProcessor(*this);
+ }
+
+ mRasterizers.Clear();
+}
+
+void SvgRasterizeManager::AddTask(SvgTaskPtr task)
+{
{
// Lock while adding task to the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
- wasEmpty = mRasterizeTasks.empty();
- if(!wasEmpty && task)
+ Mutex::ScopedLock lock(mMutex);
+
+ // There are other tasks waiting for the rasterization
+ if(!mRasterizeTasks.empty())
{
// Remove the tasks with the same renderer.
// Older task which waiting to rasterize and apply the svg to the same renderer is expired.
}
}
}
+
mRasterizeTasks.push_back(task);
+ }
+
+ size_t count = mRasterizers.GetElementCount();
+ size_t index = 0;
+ while(index++ < count)
+ {
+ auto rasterizerHelperIt = mRasterizers.GetNext();
+ DALI_ASSERT_ALWAYS(rasterizerHelperIt != mRasterizers.End());
- if(!mProcessorRegistered)
+ if(rasterizerHelperIt->RequestRasterize())
{
- Adaptor::Get().RegisterProcessor(*this);
- mProcessorRegistered = true;
+ break;
}
+ // If all threads are busy, then it's ok just to push the task because they will try to get the next job.
}
- if(wasEmpty)
+ if(!mProcessorRegistered)
{
- // wake up the image loading thread
- mConditionalWait.Notify();
+ Adaptor::Get().RegisterProcessor(*this);
+ mProcessorRegistered = true;
}
+
+ return;
}
-SvgTaskPtr SvgRasterizeThread::NextCompletedTask()
+SvgTaskPtr SvgRasterizeManager::NextCompletedTask()
{
// Lock while popping task out from the queue
Mutex::ScopedLock lock(mMutex);
return nextTask;
}
-void SvgRasterizeThread::RemoveTask(SvgVisual* visual)
+void SvgRasterizeManager::RemoveTask(SvgVisual* visual)
{
- // Lock while remove task from the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
- if(!mRasterizeTasks.empty())
{
- for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(); it != mRasterizeTasks.end();)
+ // Lock while remove task from the queue
+ Mutex::ScopedLock lock(mMutex);
+ if(!mRasterizeTasks.empty())
{
- if((*it) && (*it)->GetSvgVisual() == visual)
- {
- it = mRasterizeTasks.erase(it);
- }
- else
+ for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(); it != mRasterizeTasks.end();)
{
- it++;
+ if((*it) && (*it)->GetSvgVisual() == visual)
+ {
+ it = mRasterizeTasks.erase(it);
+ }
+ else
+ {
+ it++;
+ }
}
}
}
UnregisterProcessor();
}
-SvgTaskPtr SvgRasterizeThread::NextTaskToProcess()
+SvgTaskPtr SvgRasterizeManager::NextTaskToProcess()
{
// Lock while popping task out from the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
+ Mutex::ScopedLock lock(mMutex);
- // conditional wait
- while(mRasterizeTasks.empty())
+ // pop out the next task from the queue
+ SvgTaskPtr nextTask = nullptr;
+
+ for(auto iter = mRasterizeTasks.begin(), endIter = mRasterizeTasks.end(); iter != endIter; ++iter)
{
- mIsThreadWaiting = true;
- mConditionalWait.Wait(lock);
+ if((*iter)->IsReady())
+ {
+ nextTask = *iter;
+ mRasterizeTasks.erase(iter);
+ break;
+ }
}
- mIsThreadWaiting = false;
-
- // pop out the next task from the queue
- std::vector<SvgTaskPtr>::iterator next = mRasterizeTasks.begin();
- SvgTaskPtr nextTask = *next;
- mRasterizeTasks.erase(next);
return nextTask;
}
-void SvgRasterizeThread::AddCompletedTask(SvgTaskPtr task)
+void SvgRasterizeManager::AddCompletedTask(SvgTaskPtr task)
{
// Lock while adding task to the queue
Mutex::ScopedLock lock(mMutex);
mTrigger->Trigger();
}
-void SvgRasterizeThread::Run()
-{
- SetThreadName("SVGThread");
- mLogFactory.InstallLogFunction();
-
- while(SvgTaskPtr task = NextTaskToProcess())
- {
- task->Process();
- AddCompletedTask(task);
- }
-}
-
-void SvgRasterizeThread::ApplyRasterizedSVGToSampler()
+void SvgRasterizeManager::ApplyRasterizedSVGToSampler()
{
while(SvgTaskPtr task = NextCompletedTask())
{
+ DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "task = %p\n", task.Get());
+
task->GetSvgVisual()->ApplyRasterizedImage(task->GetPixelData(), task->HasSucceeded());
}
UnregisterProcessor();
}
-void SvgRasterizeThread::Process(bool postProcessor)
+void SvgRasterizeManager::Process(bool postProcessor)
{
ApplyRasterizedSVGToSampler();
}
-void SvgRasterizeThread::UnregisterProcessor()
+void SvgRasterizeManager::UnregisterProcessor()
{
+ Mutex::ScopedLock lock(mMutex);
+
if(mProcessorRegistered)
{
if(mRasterizeTasks.empty() && mCompletedTasks.empty())
}
}
+SvgRasterizeManager::RasterizeHelper::RasterizeHelper(SvgRasterizeManager& svgRasterizeManager)
+: RasterizeHelper(std::unique_ptr<SvgRasterizeThread>(new SvgRasterizeThread(svgRasterizeManager)), svgRasterizeManager)
+{
+}
+
+SvgRasterizeManager::RasterizeHelper::RasterizeHelper(RasterizeHelper&& rhs)
+: RasterizeHelper(std::move(rhs.mRasterizer), rhs.mSvgRasterizeManager)
+{
+}
+
+SvgRasterizeManager::RasterizeHelper::RasterizeHelper(std::unique_ptr<SvgRasterizeThread> rasterizer, SvgRasterizeManager& svgRasterizeManager)
+: mRasterizer(std::move(rasterizer)),
+ mSvgRasterizeManager(svgRasterizeManager)
+{
+}
+
+bool SvgRasterizeManager::RasterizeHelper::RequestRasterize()
+{
+ return mRasterizer->RequestRasterize();
+}
} // namespace Internal
} // namespace Toolkit
#include <memory>
// INTERNAL INCLUDES
+#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
#include <dali-toolkit/internal/visuals/visual-url.h>
namespace Dali
typedef IntrusivePtr<SvgVisual> SvgVisualPtr;
class SvgTask;
typedef IntrusivePtr<SvgTask> SvgTaskPtr;
+class SvgRasterizeManager;
/**
* The svg rasterizing tasks to be processed in the worker thread.
virtual void Process() = 0;
/**
+ * Whether the task is ready to process.
+ * @return True if the task is ready to process.
+ */
+ virtual bool IsReady()
+ {
+ return true;
+ }
+
+ /**
* Whether the task has succeeded.
* @return True if the task has succeeded.
*/
void Process() override;
/**
+ * Whether the task is ready to process.
+ * @return True if the task is ready to process.
+ */
+ bool IsReady() override;
+
+ /**
* Get the rasterization result.
* @return The pixel data with the rasterized pixels.
*/
/**
* The worker thread for SVG rasterization.
*/
-class SvgRasterizeThread : public Thread, Integration::Processor
+class SvgRasterizeThread : public Thread
+{
+public:
+ /**
+ * Constructor.
+ */
+ SvgRasterizeThread(SvgRasterizeManager& svgRasterizeManager);
+
+ /**
+ * Destructor.
+ */
+ ~SvgRasterizeThread() override;
+
+ /**
+ * @brief Request the thread to rasterizes the task.
+ * @return True if the request succeeds, otherwise false.
+ */
+ bool RequestRasterize();
+
+protected:
+ /**
+ * The entry function of the worker thread.
+ * It rasterizes the image.
+ */
+ void Run() override;
+
+private:
+ // Undefined
+ SvgRasterizeThread(const SvgRasterizeThread& thread) = delete;
+
+ // Undefined
+ SvgRasterizeThread& operator=(const SvgRasterizeThread& thread) = delete;
+
+private:
+ ConditionalWait mConditionalWait;
+ const Dali::LogFactoryInterface& mLogFactory;
+ SvgRasterizeManager& mSvgRasterizeManager;
+ bool mDestroyThread;
+ bool mIsThreadStarted;
+ bool mIsThreadIdle;
+};
+
+/**
+ * The manager for SVG rasterization.
+ */
+class SvgRasterizeManager : Integration::Processor
{
public:
/**
*
* @param[in] trigger The trigger to wake up the main thread.
*/
- SvgRasterizeThread();
+ SvgRasterizeManager();
/**
- * Terminate the svg rasterize thread, join and delete.
+ * Destructor.
*/
- static void TerminateThread(SvgRasterizeThread*& thread);
+ ~SvgRasterizeManager() override;
/**
* Add a rasterization task into the waiting queue, called by main thread.
*/
void Process(bool postProcessor) override;
-private:
/**
* Pop the next task out from the queue.
*
*/
void AddCompletedTask(SvgTaskPtr task);
+private:
/**
* Applies the rasterized image to material
*/
*/
void UnregisterProcessor();
-protected:
- /**
- * Destructor.
- */
- ~SvgRasterizeThread() override;
-
+private:
/**
- * The entry function of the worker thread.
- * It fetches task from the Queue, rasterizes the image and apply to the renderer.
+ * @brief Helper class to keep the relation between SvgRasterizeThread and corresponding container
*/
- void Run() override;
+ class RasterizeHelper
+ {
+ public:
+ /**
+ * @brief Create an RasterizeHelper.
+ *
+ * @param[in] svgRasterizeManager Reference to the SvgRasterizeManager
+ */
+ RasterizeHelper(SvgRasterizeManager& svgRasterizeManager);
+
+ /**
+ * @brief Request the thread to rasterizes the task.
+ * @return True if the request succeeds, otherwise false.
+ */
+ bool RequestRasterize();
+
+ public:
+ RasterizeHelper(const RasterizeHelper&) = delete;
+ RasterizeHelper& operator=(const RasterizeHelper&) = delete;
+
+ RasterizeHelper(RasterizeHelper&& rhs);
+ RasterizeHelper& operator=(RasterizeHelper&& rhs) = delete;
+
+ private:
+ /**
+ * @brief Main constructor that used by all other constructors
+ */
+ RasterizeHelper(std::unique_ptr<SvgRasterizeThread> rasterizer, SvgRasterizeManager& svgRasterizeManager);
+
+ private:
+ std::unique_ptr<SvgRasterizeThread> mRasterizer;
+ SvgRasterizeManager& mSvgRasterizeManager;
+ };
private:
// Undefined
- SvgRasterizeThread(const SvgRasterizeThread& thread);
+ SvgRasterizeManager(const SvgRasterizeManager& thread);
// Undefined
- SvgRasterizeThread& operator=(const SvgRasterizeThread& thread);
+ SvgRasterizeManager& operator=(const SvgRasterizeManager& thread);
private:
std::vector<SvgTaskPtr> mRasterizeTasks; //The queue of the tasks waiting to rasterize the SVG image
std::vector<SvgTaskPtr> mCompletedTasks; //The queue of the tasks with the SVG rasterization completed
- ConditionalWait mConditionalWait;
+ RoundRobinContainerView<RasterizeHelper> mRasterizers;
+
Dali::Mutex mMutex;
std::unique_ptr<EventThreadCallback> mTrigger;
- const Dali::LogFactoryInterface& mLogFactory;
- bool mIsThreadWaiting;
bool mProcessorRegistered;
};
}
else
{
- mFactoryCache.GetSVGRasterizationThread()->AddTask(newTask);
+ mFactoryCache.GetSVGRasterizationManager()->AddTask(newTask);
}
}
void SvgVisual::DoSetOffScene(Actor& actor)
{
- mFactoryCache.GetSVGRasterizationThread()->RemoveTask(this);
+ mFactoryCache.GetSVGRasterizationManager()->RemoveTask(this);
actor.RemoveRenderer(mImpl->mRenderer);
mPlacementActor.Reset();
}
else
{
- mFactoryCache.GetSVGRasterizationThread()->AddTask(newTask);
+ mFactoryCache.GetSVGRasterizationManager()->AddTask(newTask);
}
}
}
}
VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
-: mSvgRasterizeThread(NULL),
- mVectorAnimationManager(),
+: mSvgRasterizeManager(nullptr),
+ mVectorAnimationManager(nullptr),
mPreMultiplyOnLoad(preMultiplyOnLoad),
mBrokenImageInfoContainer(),
mDefaultBrokenImageUrl(""),
VisualFactoryCache::~VisualFactoryCache()
{
- SvgRasterizeThread::TerminateThread(mSvgRasterizeThread);
}
Geometry VisualFactoryCache::GetGeometry(GeometryType type)
return mNPatchLoader;
}
-SvgRasterizeThread* VisualFactoryCache::GetSVGRasterizationThread()
+SvgRasterizeManager* VisualFactoryCache::GetSVGRasterizationManager()
{
- if(!mSvgRasterizeThread)
+ if(!mSvgRasterizeManager)
{
- mSvgRasterizeThread = new SvgRasterizeThread();
- mSvgRasterizeThread->Start();
+ mSvgRasterizeManager = std::unique_ptr<SvgRasterizeManager>(new SvgRasterizeManager());
}
- return mSvgRasterizeThread;
+ return mSvgRasterizeManager.get();
}
VectorAnimationManager& VisualFactoryCache::GetVectorAnimationManager()
NPatchLoader& GetNPatchLoader();
/**
- * Get the SVG rasterization thread.
- * @return A raw pointer pointing to the SVG rasterization thread.
+ * Get the SVG rasterization manager.
+ * @return A raw pointer pointing to the SVG rasterization manager.
*/
- SvgRasterizeThread* GetSVGRasterizationThread();
+ SvgRasterizeManager* GetSVGRasterizationManager();
/**
* Get the vector animation manager.
TextureManager mTextureManager;
NPatchLoader mNPatchLoader;
- SvgRasterizeThread* mSvgRasterizeThread;
+ std::unique_ptr<SvgRasterizeManager> mSvgRasterizeManager;
std::unique_ptr<VectorAnimationManager> mVectorAnimationManager;
bool mPreMultiplyOnLoad;
std::vector<BrokenImageInfo> mBrokenImageInfoContainer;