lottie/render: Added custome future/promise to optimize the heap allocation. 12/195312/3
authorsubhransu mohanty <sub.mohanty@samsung.com>
Wed, 12 Dec 2018 10:47:23 +0000 (19:47 +0900)
committerHermet Park <chuneon.park@samsung.com>
Thu, 13 Dec 2018 06:26:13 +0000 (06:26 +0000)
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

src/lottie/lottieitem.cpp
src/lottie/lottieitem.h
src/vector/vdrawable.cpp
src/vector/vdrawable.h
src/vector/vraster.cpp
src/vector/vraster.h

index 631dae1..621f64c 100644 (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();
index 737ce43..891e94c 100644 (file)
@@ -163,7 +163,7 @@ public:
     VMatrix                  mCombinedMatrix;
     VPath                    mLocalPath;
     VPath                    mFinalPath;
-    std::future<VRle>        mRleTask;
+    RleShare                 mRleFuture;
     VRle                     mRle;
 };
 
index 13b0a2d..0eaad64 100644 (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;
 }
index 9d157f6..d07ad7e 100644 (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};
index cb2a7ae..25185c3 100644 (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
index a25b0d2..d159420 100644 (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());
 };