namespace tvg {
struct TaskQueue {
- deque<shared_ptr<Task>> taskDeque;
+ deque<Task*> taskDeque;
mutex mtx;
condition_variable ready;
bool done = false;
- bool tryPop(shared_ptr<Task> &task)
+ bool tryPop(Task** task)
{
unique_lock<mutex> lock{mtx, try_to_lock};
if (!lock || taskDeque.empty()) return false;
- task = move(taskDeque.front());
+ *task = taskDeque.front();
taskDeque.pop_front();
return true;
}
- bool tryPush(shared_ptr<Task> &&task)
+ bool tryPush(Task* task)
{
{
unique_lock<mutex> lock{mtx, try_to_lock};
if (!lock) return false;
- taskDeque.push_back(move(task));
+ taskDeque.push_back(task);
}
ready.notify_one();
ready.notify_all();
}
- bool pop(shared_ptr<Task> &task)
+ bool pop(Task** task)
{
unique_lock<mutex> lock{mtx};
if (taskDeque.empty()) return false;
- task = move(taskDeque.front());
+ *task = taskDeque.front();
taskDeque.pop_front();
return true;
}
- void push(shared_ptr<Task> &&task)
+ void push(Task* task)
{
{
unique_lock<mutex> lock{mtx};
- taskDeque.push_back(move(task));
+ taskDeque.push_back(task);
}
ready.notify_one();
vector<TaskQueue> taskQueues;
atomic<unsigned> idx{0};
- TaskSchedulerImpl(unsigned count) : taskQueues(count)
+ TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt)
{
- threadCnt = count;
for (unsigned i = 0; i < threadCnt; ++i) {
threads.emplace_back([&, i] { run(i); });
}
void run(unsigned i)
{
- shared_ptr<Task> task;
+ Task* task;
//Thread Loop
while (true) {
auto success = false;
-
for (unsigned i = 0; i < threadCnt * 2; ++i) {
- if (taskQueues[(i + i) % threadCnt].tryPop(task)) {
+ if (taskQueues[(i + i) % threadCnt].tryPop(&task)) {
success = true;
break;
}
}
- if (!success && !taskQueues[i].pop(task)) break;
-
+ if (!success && !taskQueues[i].pop(&task)) break;
(*task)();
}
}
- void request(shared_ptr<Task> task)
+ void request(Task* task)
{
//Async
if (threadCnt > 0) {
task->prepare();
auto i = idx++;
for (unsigned n = 0; n < threadCnt; ++n) {
- if (taskQueues[(i + n) % threadCnt].tryPush(move(task))) return;
+ if (taskQueues[(i + n) % threadCnt].tryPush(task)) return;
}
-
- taskQueues[i % threadCnt].push(move(task));
-
+ taskQueues[i % threadCnt].push(task);
//Sync
} else {
task->run();
}
-void TaskScheduler::request(shared_ptr<Task> task)
+void TaskScheduler::request(Task* task)
{
if (inst) {
- inst->request(move(task));
+ inst->request(task);
}
-}
\ No newline at end of file
+}
struct Task
{
private:
- std::promise<void> sender;
- std::future<void> receiver;
+ promise<void> sender;
+ future<void> receiver;
public:
virtual ~Task() = default;
void get()
{
- if (receiver.valid()) receiver.get();
+ if (receiver.valid()) {
+ receiver.get();
+ }
}
protected:
void prepare()
{
- sender = std::promise<void>();
+ sender = promise<void>();
receiver = sender.get_future();
}
{
static void init(unsigned threads);
static void term();
- static void request(shared_ptr<Task> task);
+ static void request(Task* task);
};
}
return res;
}
+
+void SvgTask::run()
+{
+ if (!simpleXmlParse(loader->content, loader->size, true, _svgLoaderParser, &(loader->loaderData))) return;
+
+ if (loader->loaderData.doc) {
+ _updateStyle(loader->loaderData.doc, nullptr);
+ auto defs = loader->loaderData.doc->node.doc.defs;
+ if (defs) _updateGradient(loader->loaderData.doc, defs->node.defs.gradients);
+ else {
+ if (!loader->loaderData.gradients.empty()) {
+ vector<SvgStyleGradient*> gradientList;
+ for (auto gradient : loader->loaderData.gradients) {
+ gradientList.push_back(gradient);
+ }
+ _updateGradient(loader->loaderData.doc, gradientList);
+ gradientList.clear();
+ }
+ }
+ }
+ loader->root = loader->builder.build(loader->loaderData.doc);
+};
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
-SvgLoader::SvgLoader()
+SvgLoader::SvgLoader() : task(new SvgTask)
{
+ task->loader = this;
}
{
if (!content || size == 0) return false;
- loaderData = {vector<SvgNode*>(),
- nullptr,
- nullptr,
- vector<SvgStyleGradient*>(),
- nullptr,
- nullptr,
- 0,
- false};
-
- loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser));
-
- if (!simpleXmlParse(content, size, true, _svgLoaderParser, &loaderData)) return false;
-
- if (loaderData.doc) {
- _updateStyle(loaderData.doc, nullptr);
- auto defs = loaderData.doc->node.doc.defs;
- if (defs) _updateGradient(loaderData.doc, defs->node.defs.gradients);
- else {
- if (!loaderData.gradients.empty()) {
- vector<SvgStyleGradient*> gradientList;
- std::copy(loaderData.gradients.begin(), loaderData.gradients.end(), gradientList.begin());
- _updateGradient(loaderData.doc, gradientList);
- gradientList.clear();
- }
- }
- }
-
- root = builder.build(loaderData.doc);
+ TaskScheduler::request(task);
return true;
}
bool SvgLoader::close()
{
+ if (task) {
+ task->get();
+ delete(task);
+ task = nullptr;
+ }
+
if (loaderData.svgParse) {
free(loaderData.svgParse);
loaderData.svgParse = nullptr;
unique_ptr<Scene> SvgLoader::data()
{
- return move(root);
+ if (task) task->get();
+ if (root) return move(root);
+ else return nullptr;
}
\ No newline at end of file
#include "tvgSvgLoaderCommon.h"
#include "tvgSvgSceneBuilder.h"
+class SvgLoader;
+
+struct SvgTask : Task
+{
+ SvgLoader* loader = nullptr;
+ void run() override;
+};
+
class SvgLoader : public Loader
{
-private:
+public:
string filePath;
const char* content = nullptr;
uint32_t size = 0;
SvgLoaderData loaderData;
SvgSceneBuilder builder;
unique_ptr<Scene> root;
+ SvgTask* task = nullptr;
-public:
SvgLoader();
~SvgLoader();
+#include <vector>
#include "testCommon.h"
/************************************************************************/
static int count = 0;
+static std::vector<unique_ptr<tvg::Picture>> pictures;
+
void svgDirCallback(const char* name, const char* path, void* data)
{
tvg::Canvas* canvas = static_cast<tvg::Canvas*>(data);
picture->translate((count % NUM_PER_LINE) * SIZE - x, SIZE * (count / NUM_PER_LINE) - y);
- canvas->push(move(picture));
+ pictures.push_back(move(picture));
cout << "SVG: " << buf << endl;
if (canvas->push(move(shape)) != tvg::Result::Success) return;
eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, canvas);
+
+ /* This showcase shows you asynchrounous loading of svg.
+ For this, pushing pictures at a certian sync time.
+ This means it earns the time to finish loading svg resources,
+ otherwise you can push pictures immediately. */
+ for (auto& paint : pictures) {
+ canvas->push(move(paint));
+ }
+
+ pictures.clear();
}