lottie:render: added task stealing scheduler for async rle generation. 52/184452/2
authorsubhransu mohanty <sub.mohanty@samsung.com>
Wed, 18 Jul 2018 05:03:23 +0000 (14:03 +0900)
committerHermet Park <chuneon.park@samsung.com>
Thu, 19 Jul 2018 04:09:56 +0000 (04:09 +0000)
Change-Id: Ie5a48bb018db8bccef499aac5cb7788de5df5b61

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

index 0d62d4dee3db4fd3eac8125744fd3c87d5c1ff0d..86bda248f63b899d44a6d3f9987f41ce994e6d50 100644 (file)
@@ -27,18 +27,24 @@ void VDrawable::preprocess()
                 newPath = dasher.dashed(mPath);
             }
             FTOutline *outline = VRaster::toFTOutline(newPath);
-            mRle = VRaster::instance().generateStrokeInfo(outline, mStroke.cap, mStroke.join,
-                                                          mStroke.width, mStroke.meterLimit);
-            VRaster::deleteFTOutline(outline);
+            mRleTask = VRaster::instance().generateStrokeInfo(outline, mStroke.cap, mStroke.join,
+                                                              mStroke.width, mStroke.meterLimit);
         } else {
             FTOutline *outline = VRaster::toFTOutline(mPath);
-            mRle = VRaster::instance().generateFillInfo(outline, mFillRule);
-            VRaster::deleteFTOutline(outline);
+            mRleTask = VRaster::instance().generateFillInfo(outline, mFillRule);
         }
         mFlag &= ~DirtyFlag(DirtyState::Path);
     }
 }
 
+VRle VDrawable::rle()
+{
+    if (mRleTask.valid()) {
+        mRle = std::move(mRleTask.get());
+    }
+    return mRle;
+}
+
 void VDrawable::setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, float strokeWidth)
 {
     mStroke.enable = true;
@@ -310,19 +316,25 @@ void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
     }
     float opacity = mData->opacity(frameNo);
     opacity = opacity * parentAlpha;
+    mCombinedAlpha = opacity;
 
     VPath path = mLocalPath;
     path.transform(parentMatrix);
 
     FTOutline *outline = VRaster::toFTOutline(path);
-    mRle = VRaster::instance().generateFillInfo(outline);
-    VRaster::deleteFTOutline(outline);
-
-    mRle = mRle * (opacity * 255);
+    mRleTask = VRaster::instance().generateFillInfo(outline);
+}
 
-    if (mData->mInv) {
-        mRle = ~mRle;
+VRle LOTMaskItem::rle()
+{
+    if (mRleTask.valid()) {
+        mRle = std::move(mRleTask.get());
+        if (!vCompare(mCombinedAlpha, 1.0f))
+            mRle = mRle * (mCombinedAlpha * 255);
+        if (mData->mInv)
+            mRle = ~mRle;
     }
+    return mRle;
 }
 
 void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask)
@@ -336,35 +348,41 @@ void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask)
         else
             mask = mask & inheritMask;
     }
+
+    // do preprocessing first to take advantage of thread pool.
     for(auto i : list) {
         i->preprocess();
+    }
+
+    for(auto i : list) {
         painter->setBrush(i->mBrush);
         if (!mask.isEmpty()) {
-            VRle rle = i->mRle & mask;
+            VRle rle = i->rle() & mask;
             painter->drawRle(VPoint(), rle);
         } else {
-            painter->drawRle(VPoint(), i->mRle);
+            painter->drawRle(VPoint(), i->rle());
         }
     }
 }
 
 VRle LOTLayerItem::maskRle(const VRect &clipRect)
 {
+
     VRle rle;
     for (auto &i : mMasks) {
         switch (i->maskMode()) {
             case LOTMaskData::Mode::Add: {
-                rle = rle + i->mRle;
+                rle = rle + i->rle();
                 break;
             }
             case LOTMaskData::Mode::Substarct: {
                 if (rle.isEmpty() && !clipRect.isEmpty())
                     rle = VRle::toRle(clipRect);
-                rle = rle - i->mRle;
+                rle = rle - i->rle();
                 break;
             }
             case LOTMaskData::Mode::Intersect: {
-                rle = rle & i->mRle;
+                rle = rle & i->rle();
                 break;
             }
             default:
index 72b7b237e64bfe9935255fb331963272b8fbe8d0..5054b6aacb0e545a86fa189e6761d27c01b3e529 100644 (file)
@@ -144,12 +144,14 @@ public:
     LOTMaskItem(LOTMaskData *data): mData(data), mCombinedAlpha(0){}
     void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag);
     LOTMaskData::Mode maskMode() const { return mData->mMode;}
+    VRle rle();
 public:
-    LOTMaskData *mData;
-    float        mCombinedAlpha;
-    VMatrix     mCombinedMatrix;
-    VPath       mLocalPath;
-    VRle        mRle;
+    LOTMaskData             *mData;
+    float                    mCombinedAlpha;
+    VMatrix                  mCombinedMatrix;
+    VPath                    mLocalPath;
+    std::future<VRle>        mRleTask;
+    VRle                     mRle;
 };
 
 class VDrawable
@@ -175,13 +177,15 @@ public:
     void setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, float strokeWidth);
     void setDashInfo(float *array, int size);
     void preprocess();
+    VRle rle();
 public:
     DirtyFlag          mFlag;
     VDrawable::Type    mType;
     VBrush             mBrush;
-    VPath             mPath;
+    VPath              mPath;
     FillRule           mFillRule;
-    VRle              mRle;
+    std::future<VRle>  mRleTask;
+    VRle               mRle;
     struct  {
          bool         enable;
          float        width;
index 7a5a892872330450bdc323105e434a3d0925009d..1d67f2a5e6f5fa33b8249ab8b395a35cdf8203c7 100644 (file)
@@ -5,6 +5,8 @@
 #include"vmatrix.h"
 #include<cstring>
 #include"vdebug.h"
+#include"vtaskqueue.h"
+#include<thread>
 
 V_BEGIN_NAMESPACE
 
@@ -36,6 +38,8 @@ public:
     bool           closed;
 };
 
+
+
 #define TO_FT_COORD(x) ((x) * 64) // to freetype 26.6 coordinate.
 
 void FTOutline::transform(const VMatrix &m)
@@ -133,54 +137,153 @@ rleGenerationCb( int count, const SW_FT_Span*  spans,void *user)
    rle->addSpan(rleSpan, count);
 }
 
-VRle generateFillInfoAsync(const SW_FT_Outline *outline)
+struct RleTask
 {
-    VRle rle;
-    SW_FT_Raster_Params params;
+    RleTask() {
+        receiver = sender.get_future();
+    }
+    std::promise<VRle>       sender;
+    std::future<VRle>        receiver;
+    bool                     stroke;
+    FTOutline               *outline;
+    SW_FT_Stroker_LineCap    cap;
+    SW_FT_Stroker_LineJoin   join;
+    int                      width;
+    int                      meterLimit;
+    SW_FT_Bool               closed;
+};
 
-    params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ;
-    params.gray_spans = &rleGenerationCb;
-    params.user = &rle;
-    params.source = outline;
+static VRle generateRleAsync(RleTask *task);
 
-    sw_ft_grays_raster.raster_render(nullptr, &params);
+class RleTaskScheduler {
+    const unsigned _count{std::thread::hardware_concurrency()};
+    std::vector<std::thread> _threads;
+    std::vector<TaskQueue<RleTask>> _q{_count};
+    std::atomic<unsigned> _index{0};
 
-    return rle;
-}
+    void run(unsigned i) {
+        while (true) {
+            RleTask *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;
+
+            VRle rle = generateRleAsync(task);
+            task->sender.set_value(std::move(rle));
+            delete task;
+        }
+    }
+
+public:
+    RleTaskScheduler() {
+        for (unsigned n = 0; n != _count; ++n) {
+            _threads.emplace_back([&, n] { run(n); });
+        }
+    }
+
+    ~RleTaskScheduler() {
+        for (auto& e : _q)
+            e.done();
+
+        for (auto& e : _threads)
+            e.join();
+    }
+
+    std::future<VRle> async(RleTask *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);
+        }
 
-VRle generateStrokeInfoAsync(const SW_FT_Outline *outline, SW_FT_Stroker_LineCap cap,
-                             SW_FT_Stroker_LineJoin join,
-                             int width, int meterLimit,
-                             SW_FT_Bool closed)
+        _q[i % _count].push(task);
+
+        return std::move(receiver);
+    }
+
+    std::future<VRle> strokeRle(FTOutline *outline,
+                                SW_FT_Stroker_LineCap cap,
+                                SW_FT_Stroker_LineJoin join,
+                                int width,
+                                int meterLimit,
+                                SW_FT_Bool closed) {
+        RleTask *task = new RleTask();
+        task->stroke = true;
+        task->outline = outline;
+        task->cap = cap;
+        task->join = join;
+        task->width = width;
+        task->meterLimit = meterLimit;
+        task->closed = closed;
+        return async(task);
+    }
+
+    std::future<VRle> fillRle(FTOutline *outline) {
+        RleTask *task = new RleTask();
+        task->stroke = false;
+        task->outline = outline;
+        return async(task);
+    }
+};
+
+static RleTaskScheduler raster_scheduler;
+
+static VRle generateRleAsync(RleTask *task)
 {
-    SW_FT_Stroker stroker;
-    SW_FT_Stroker_New(&stroker);
+    if (task->stroke) {
+        // for stroke generation
+        SW_FT_Stroker stroker;
+        SW_FT_Stroker_New(&stroker);
 
-    uint points,contors;
-    SW_FT_Outline strokeOutline = { 0, 0, nullptr, nullptr, nullptr, SW_FT_OUTLINE_NONE };
+        uint points,contors;
+        SW_FT_Outline strokeOutline = { 0, 0, nullptr, nullptr, nullptr, SW_FT_OUTLINE_NONE };
 
-    SW_FT_Stroker_Set(stroker, width, cap, join, meterLimit);
-    SW_FT_Stroker_ParseOutline(stroker, outline, !closed);
-    SW_FT_Stroker_GetCounts(stroker,&points, &contors);
+        SW_FT_Stroker_Set(stroker, task->width, task->cap, task->join, task->meterLimit);
+        SW_FT_Stroker_ParseOutline(stroker, &task->outline->ft, !task->closed);
+        SW_FT_Stroker_GetCounts(stroker,&points, &contors);
 
-    strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
-    strokeOutline.tags = (char *) calloc(points, sizeof(char));
-    strokeOutline.contours = (short *) calloc(contors, sizeof(short));
+        strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
+        strokeOutline.tags = (char *) calloc(points, sizeof(char));
+        strokeOutline.contours = (short *) calloc(contors, sizeof(short));
 
-    SW_FT_Stroker_Export(stroker, &strokeOutline);
+        SW_FT_Stroker_Export(stroker, &strokeOutline);
 
-    SW_FT_Stroker_Done(stroker);
+        SW_FT_Stroker_Done(stroker);
 
-    VRle rle = generateFillInfoAsync(&strokeOutline);
+        VRle rle;
+        SW_FT_Raster_Params params;
 
-    // cleanup the outline data.
-    free(strokeOutline.points);
-    free(strokeOutline.tags);
-    free(strokeOutline.contours);
+        params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ;
+        params.gray_spans = &rleGenerationCb;
+        params.user = &rle;
+        params.source = &strokeOutline;
 
-    return rle;
-}
+        sw_ft_grays_raster.raster_render(nullptr, &params);
 
+        // cleanup the outline data.
+        free(strokeOutline.points);
+        free(strokeOutline.tags);
+        free(strokeOutline.contours);
+
+        return rle;
+    } else {
+        // fill generation
+        VRle rle;
+        SW_FT_Raster_Params params;
+
+        params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ;
+        params.gray_spans = &rleGenerationCb;
+        params.user = &rle;
+        params.source = &task->outline->ft;
+
+        sw_ft_grays_raster.raster_render(nullptr, &params);
+
+        return rle;
+    }
+}
 
 VRaster::VRaster()
 {
@@ -231,7 +334,8 @@ FTOutline *VRaster::toFTOutline(const VPath &path)
     return outline;
 }
 
-VRle VRaster::generateFillInfo(const FTOutline *outline, FillRule fillRule)
+std::future<VRle>
+VRaster::generateFillInfo(FTOutline *outline, FillRule fillRule)
 {
     int fillRuleFlag = SW_FT_OUTLINE_NONE;
     switch (fillRule) {
@@ -242,19 +346,21 @@ VRle VRaster::generateFillInfo(const FTOutline *outline, FillRule fillRule)
         fillRuleFlag = SW_FT_OUTLINE_NONE;
         break;
     }
-    FTOutline *outlineRef = const_cast<FTOutline *>(outline);
-    outlineRef->ft.flags =  fillRuleFlag;
-    return generateFillInfoAsync(&outlineRef->ft);
+
+    outline->ft.flags =  fillRuleFlag;
+
+    return std::move(raster_scheduler.fillRle(outline));
 }
 
-VRle VRaster::generateStrokeInfo(const FTOutline *outline, CapStyle cap, JoinStyle join,
-                                 float width, float meterLimit)
+std::future<VRle>
+VRaster::generateStrokeInfo(FTOutline *outline, CapStyle cap, JoinStyle join,
+                            float width, float meterLimit)
 {
     SW_FT_Stroker_LineCap ftCap;
     SW_FT_Stroker_LineJoin ftJoin;
     int ftWidth;
     int ftMeterLimit;
-    SW_FT_Bool ftbool = (SW_FT_Bool) outline->closed;
+    SW_FT_Bool ftclose = (SW_FT_Bool) outline->closed;
 
     // map strokeWidth to freetype. It uses as the radius of the pen not the diameter
     width = width/2.0;
@@ -288,8 +394,8 @@ VRle VRaster::generateStrokeInfo(const FTOutline *outline, CapStyle cap, JoinSty
            break;
       }
 
-    return generateStrokeInfoAsync(&outline->ft, ftCap, ftJoin,
-                                   ftWidth, ftMeterLimit, ftbool);
+    return std::move(raster_scheduler.strokeRle(outline, ftCap, ftJoin,
+                                                ftWidth, ftMeterLimit, ftclose));
 }
 
 V_END_NAMESPACE
index 5b8d0ad2990b5c9ab7e7858f73a53c9edb7802b1..65baab662c501109a907b5b13c4daa8760144165 100644 (file)
@@ -25,9 +25,9 @@ public:
 
     static FTOutline *toFTOutline(const VPath &path);
     static void deleteFTOutline(FTOutline *);
-    VRle generateFillInfo(const FTOutline *, FillRule fillRule = FillRule::Winding);
-    VRle generateStrokeInfo(const FTOutline *, CapStyle cap, JoinStyle join,
-                            float width, float meterLimit);
+    std::future<VRle> generateFillInfo(FTOutline *, FillRule fillRule = FillRule::Winding);
+    std::future<VRle> generateStrokeInfo(FTOutline *, CapStyle cap, JoinStyle join,
+                                         float width, float meterLimit);
 private:
     VRaster();
     VRasterPrivate *d;