lottie/render: Added custome future/promise to optimize the heap allocation.

As every future/promise shared data allocates in heap there was
lot of heap allocation when we generate span info using RleThread pool.
this custome future/promise will allocate 1 shared resource per drawable and
will reuse for all subsequent span info request for that drawable.

This reduced the number of heap allocation drastically and improves render performance.

Change-Id: Ic480030e7c36ad7ab730683e71417de026220297
This commit is contained in:
subhransu mohanty 2018-12-12 19:47:23 +09:00 committed by Hermet Park
parent 7e774a7bcd
commit fb6bf7bef9
6 changed files with 79 additions and 37 deletions

View File

@ -158,14 +158,17 @@ void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
VPath tmp = mFinalPath;
mRleTask = VRaster::generateFillInfo(std::move(tmp), std::move(mRle));
if (!mRleFuture) mRleFuture = std::make_shared<VSharedState<VRle>>();
mRleFuture->reuse();
VRaster::generateFillInfo(mRleFuture, std::move(tmp), std::move(mRle));
mRle = VRle();
}
VRle LOTMaskItem::rle()
{
if (mRleTask.valid()) {
mRle = mRleTask.get();
if (mRleFuture && mRleFuture->valid()) {
mRle = mRleFuture->get();
if (!vCompare(mCombinedAlpha, 1.0f))
mRle *= (mCombinedAlpha * 255);
if (mData->mInv) mRle.invert();

View File

@ -163,7 +163,7 @@ public:
VMatrix mCombinedMatrix;
VPath mLocalPath;
VPath mFinalPath;
std::future<VRle> mRleTask;
RleShare mRleFuture;
VRle mRle;
};

View File

@ -5,16 +5,21 @@
void VDrawable::preprocess(const VRect &clip)
{
if (mFlag & (DirtyState::Path)) {
if (!mRleFuture) mRleFuture = std::make_shared<VSharedState<VRle>>();
mRleFuture->reuse();
if (mStroke.enable) {
if (mStroke.mDash.size()) {
VDasher dasher(mStroke.mDash.data(), mStroke.mDash.size());
mPath = dasher.dashed(mPath);
}
mRleTask = VRaster::generateStrokeInfo(
VRaster::generateStrokeInfo(mRleFuture,
std::move(mPath), std::move(mRle), mStroke.cap, mStroke.join,
mStroke.width, mStroke.meterLimit, clip);
} else {
mRleTask = VRaster::generateFillInfo(
VRaster::generateFillInfo(mRleFuture,
std::move(mPath), std::move(mRle), mFillRule, clip);
}
mRle = VRle();
@ -24,8 +29,8 @@ void VDrawable::preprocess(const VRect &clip)
VRle VDrawable::rle()
{
if (mRleTask.valid()) {
mRle = mRleTask.get();
if (mRleFuture && mRleFuture->valid()) {
mRle = mRleFuture->get();
}
return mRle;
}

View File

@ -4,6 +4,7 @@
#include "vbrush.h"
#include "vpath.h"
#include "vrle.h"
#include "vraster.h"
class VDrawable {
public:
@ -40,7 +41,7 @@ public:
};
VBrush mBrush;
VPath mPath;
std::future<VRle> mRleTask;
RleShare mRleFuture;
VRle mRle;
StrokeInfo mStroke;
DirtyFlag mFlag{DirtyState::All};

View File

@ -244,7 +244,7 @@ static void bboxCb(int x, int y, int w, int h, void *user)
}
struct RleTask {
std::promise<VRle> sender;
RleShare mRlePromise;
VPath path;
VRle rle;
float width;
@ -348,7 +348,7 @@ class RleTaskScheduler {
if (!success && !_q[i].pop(task)) break;
task.sender.set_value((task)(outlineRef, stroker));
task.mRlePromise->set_value((task)(outlineRef, stroker));
}
// cleanup
@ -370,21 +370,18 @@ public:
for (auto &e : _threads) e.join();
}
std::future<VRle> async(RleTask &&task)
void async(RleTask &&task)
{
auto receiver = std::move(task.sender.get_future());
auto i = _index++;
for (unsigned n = 0; n != _count; ++n) {
if (_q[(i + n) % _count].try_push(std::move(task))) return receiver;
if (_q[(i + n) % _count].try_push(std::move(task))) return;
}
_q[i % _count].push(std::move(task));
return receiver;
}
std::future<VRle> strokeRle(VPath &&path, VRle &&rle, CapStyle cap, JoinStyle join,
void strokeRle(RleShare &promise, VPath &&path, VRle &&rle, CapStyle cap, JoinStyle join,
float width, float meterLimit, const VRect &clip)
{
RleTask task;
@ -396,10 +393,12 @@ public:
task.width = width;
task.meterLimit = meterLimit;
task.clip = clip;
return async(std::move(task));
task.mRlePromise = promise;
async(std::move(task));
}
std::future<VRle> fillRle(VPath &&path, VRle &&rle, FillRule fillRule, const VRect &clip)
void fillRle(RleShare &promise, VPath &&path, VRle &&rle, FillRule fillRule, const VRect &clip)
{
RleTask task;
task.path = std::move(path);
@ -407,33 +406,33 @@ public:
task.fillRule = fillRule;
task.clip = clip;
task.stroke = false;
return async(std::move(task));
task.mRlePromise = promise;
async(std::move(task));
}
};
static RleTaskScheduler raster_scheduler;
std::future<VRle> VRaster::generateFillInfo(VPath &&path, VRle &&rle,
FillRule fillRule, const VRect &clip)
void VRaster::generateFillInfo(RleShare &promise, VPath &&path, VRle &&rle,
FillRule fillRule, const VRect &clip)
{
if (path.empty()) {
std::promise<VRle> promise;
promise.set_value(VRle());
return promise.get_future();
promise->set_value(VRle());
return;
}
return raster_scheduler.fillRle(std::move(path), std::move(rle), fillRule, clip);
return raster_scheduler.fillRle(promise, std::move(path), std::move(rle), fillRule, clip);
}
std::future<VRle> VRaster::generateStrokeInfo(VPath &&path, VRle &&rle, CapStyle cap,
JoinStyle join, float width,
float meterLimit, const VRect &clip)
void VRaster::generateStrokeInfo(RleShare &promise, VPath &&path, VRle &&rle, CapStyle cap,
JoinStyle join, float width,
float meterLimit, const VRect &clip)
{
if (path.empty()) {
std::promise<VRle> promise;
promise.set_value(VRle());
return promise.get_future();
promise->set_value(VRle());
return;
}
return raster_scheduler.strokeRle(std::move(path), std::move(rle), cap, join, width, meterLimit, clip);
return raster_scheduler.strokeRle(promise, std::move(path), std::move(rle), cap, join, width, meterLimit, clip);
}
V_END_NAMESPACE

View File

@ -9,14 +9,48 @@ V_BEGIN_NAMESPACE
class VPath;
class VRle;
template <class R>
class VSharedState {
public:
void set_value(R value) {
if (_ready) return;
{
std::lock_guard<std::mutex> lock(_mutex);
_value = std::move(value);
_ready = true;
}
_cv.notify_one();
}
R get(){
std::unique_lock<std::mutex> lock(_mutex);
while(!_ready) _cv.wait(lock);
_valid = false;
return std::move(_value);
}
bool valid() const {return _valid;}
void reuse() {
_ready = false;
_valid = true;
}
private:
R _value;
std::mutex _mutex;
std::condition_variable _cv;
bool _ready{false};
bool _valid{true};
};
using RleShare = std::shared_ptr<VSharedState<VRle>>;
struct VRaster {
static std::future<VRle>
generateFillInfo(VPath &&path, VRle &&rle,
static void
generateFillInfo(RleShare &promise, VPath &&path, VRle &&rle,
FillRule fillRule = FillRule::Winding, const VRect &clip = VRect());
static std::future<VRle>
generateStrokeInfo(VPath &&path, VRle &&rle,
static void
generateStrokeInfo(RleShare &promise, VPath &&path, VRle &&rle,
CapStyle cap, JoinStyle join,
float width, float meterLimit, const VRect &clip = VRect());
};