From: subhransu mohanty Date: Fri, 20 Jul 2018 01:25:06 +0000 (+0900) Subject: lottie/render: implement render_scheduler to enable multithreading render job. X-Git-Tag: submit/tizen/20180917.042405~214 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F55%2F184655%2F2;p=platform%2Fcore%2Fuifw%2Flottie-player.git lottie/render: implement render_scheduler to enable multithreading render job. Change-Id: If3ab28cd7fab0e16703fae5b8f3d158bf40a77e3 --- diff --git a/inc/lottieplayer.h b/inc/lottieplayer.h index 8644f1d..c7fd5c9 100644 --- a/inc/lottieplayer.h +++ b/inc/lottieplayer.h @@ -56,8 +56,8 @@ public: //TODO: Consider correct position... void setSize(int width, int height); void size(int &width, int &height) const; - std::future render(float pos, const LOTBuffer &buffer); - bool renderSync(float pos, const LOTBuffer &buffer); + std::future render(float pos, LOTBuffer &buffer); + bool renderSync(float pos, LOTBuffer &buffer); public: LOTPlayerPrivate *d; diff --git a/src/lottie/lottieplayer.cpp b/src/lottie/lottieplayer.cpp index 314a8f2..3313f5f 100644 --- a/src/lottie/lottieplayer.cpp +++ b/src/lottie/lottieplayer.cpp @@ -24,7 +24,7 @@ public: std::shared_ptr mModel; std::unique_ptr mCompItem; VSize mSize; - + std::atomic mRenderInProgress; private: float mPos; }; @@ -88,17 +88,26 @@ float LOTPlayerPrivate::pos() bool LOTPlayerPrivate::render(float pos, const LOTBuffer &buffer) { + bool renderInProgress = mRenderInProgress.load(); + if (renderInProgress) + vCritical<<"Already Rendering Scheduled for this Player"; + + mRenderInProgress.store(true); + + bool result; if (setPos(pos)) { if (mCompItem->render(buffer)) - return true; + result = true; else - return false; + result = false; } else { - return false; + result = false; } + mRenderInProgress.store(false); + return result; } -LOTPlayerPrivate::LOTPlayerPrivate():mPos(-1) +LOTPlayerPrivate::LOTPlayerPrivate():mRenderInProgress(false), mPos(-1) { } @@ -121,6 +130,90 @@ LOTPlayerPrivate::setFilePath(std::string path) return false; } +/* + * Implement a task stealing schduler to perform render task + * As each player draws into its own buffer we can delegate this + * task to a slave thread. The scheduler creates a threadpool depending + * on the number of cores available in the system and does a simple fair + * scheduling by assigning the task in a round-robin fashion. Each thread + * in the threadpool has its own queue. once it finishes all the task on its + * own queue it goes through rest of the queue and looks for task if it founds one + * it steals the task from it and executes. if it couldn't find one then it just waits + * for new task on its own queue. + */ +struct RenderTask +{ + RenderTask() { + receiver = sender.get_future(); + } + std::promise sender; + std::future receiver; + LOTPlayerPrivate *playerImpl; + float pos; + LOTBuffer buffer; +}; + +#include +class RenderTaskScheduler { + const unsigned _count{std::thread::hardware_concurrency()}; + std::vector _threads; + std::vector> _q{_count}; + std::atomic _index{0}; + + void run(unsigned i) { + while (true) { + RenderTask *task = nullptr; + + for (unsigned n = 0; n != _count * 32; ++n) { + if (_q[(i + n) % _count].try_pop(task)) break; + } + if (!task && !_q[i].pop(task)) break; + + bool result = task->playerImpl->render(task->pos, task->buffer); + task->sender.set_value(result); + delete task; + } + } + +public: + RenderTaskScheduler() { + for (unsigned n = 0; n != _count; ++n) { + _threads.emplace_back([&, n] { run(n); }); + } + } + + ~RenderTaskScheduler() { + for (auto& e : _q) + e.done(); + + for (auto& e : _threads) + e.join(); + } + + std::future async(RenderTask *task) { + auto receiver = std::move(task->receiver); + auto i = _index++; + + for (unsigned n = 0; n != _count; ++n) { + if (_q[(i + n) % _count].try_push(task)) return std::move(receiver); + } + + _q[i % _count].push(task); + + return std::move(receiver); + } + + std::future render(LOTPlayerPrivate *impl, + float pos, LOTBuffer &buffer) { + RenderTask *task = new RenderTask(); + task->playerImpl = impl; + task->pos = pos; + task->buffer = buffer; + return async(task); + } +}; +static RenderTaskScheduler render_scheduler; + LOTPlayer::LOTPlayer():d(new LOTPlayerPrivate()) { @@ -173,12 +266,12 @@ const std::vector& LOTPlayer::renderList()const return d->renderList(); } -std::future LOTPlayer::render(float pos, const LOTBuffer &buffer) +std::future LOTPlayer::render(float pos, LOTBuffer &buffer) { - return std::async(std::launch::async, &LOTPlayerPrivate::render, d, pos, buffer); + return render_scheduler.render(d, pos, buffer); } -bool LOTPlayer::renderSync(float pos, const LOTBuffer &buffer) +bool LOTPlayer::renderSync(float pos, LOTBuffer &buffer) { return d->render(pos, buffer); } @@ -192,3 +285,4 @@ LOTNode::LOTNode() } +