lottie/vector: refactor vraster to optimize number of memory allocation. 22/184922/2
authorsubhransu mohanty <sub.mohanty@samsung.com>
Tue, 24 Jul 2018 00:57:20 +0000 (09:57 +0900)
committerYoungbok Shin <youngb.shin@samsung.com>
Tue, 24 Jul 2018 09:12:13 +0000 (09:12 +0000)
Change-Id: I55ffb29d9a039a458830200a56ff3a6a057ff361

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

index 53cd79a..a55bc3c 100644 (file)
@@ -25,12 +25,10 @@ void VDrawable::preprocess()
                 VDasher dasher(mStroke.dashArray, mStroke.dashArraySize);
                 newPath = dasher.dashed(mPath);
             }
-            FTOutline *outline = VRaster::toFTOutline(newPath);
-            mRleTask = VRaster::instance().generateStrokeInfo(outline, mStroke.cap, mStroke.join,
+            mRleTask = VRaster::instance().generateStrokeInfo(mPath, mStroke.cap, mStroke.join,
                                                               mStroke.width, mStroke.meterLimit);
         } else {
-            FTOutline *outline = VRaster::toFTOutline(mPath);
-            mRleTask = VRaster::instance().generateFillInfo(outline, mFillRule);
+            mRleTask = VRaster::instance().generateFillInfo(mPath, mFillRule);
         }
         mFlag &= ~DirtyFlag(DirtyState::Path);
     }
@@ -326,8 +324,7 @@ void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
     VPath path = mLocalPath;
     path.transform(parentMatrix);
 
-    FTOutline *outline = VRaster::toFTOutline(path);
-    mRleTask = VRaster::instance().generateFillInfo(outline);
+    mRleTask = VRaster::instance().generateFillInfo(path);
 }
 
 VRle LOTMaskItem::rle()
index 814d537..689db38 100644 (file)
@@ -13,46 +13,133 @@ V_BEGIN_NAMESPACE
 struct FTOutline
 {
 public:
-    FTOutline() = delete;
-    FTOutline(int points, int segments)
-    {
-        ft.points = new SW_FT_Vector[points + segments];
-        ft.tags   = new char[points + segments];
-        ft.contours = new short[segments];
-        ft.n_points = ft.n_contours = 0;
-        ft.flags = 0x0;
+    FTOutline():mMemory(nullptr){}
+    ~FTOutline(){delete[] mMemory;}
+    void releaseMemory() {
+        if (mMemory) delete [] mMemory;
+        mMemory = nullptr;
     }
+    void grow(int, int);
+    void convert(const VPath &path);
+    void convert(CapStyle, JoinStyle, float, float);
     void moveTo(const VPointF &pt);
     void lineTo(const VPointF &pt);
     void cubicTo(const VPointF &ctr1, const VPointF &ctr2, const VPointF end);
     void close();
     void end();
     void transform(const VMatrix &m);
-    ~FTOutline()
-    {
-        delete[] ft.points;
-        delete[] ft.tags;
-        delete[] ft.contours;
-    }
-    SW_FT_Outline  ft;
-    bool           closed;
+    SW_FT_Outline            ft;
+    SW_FT_Vector            *mMemory{nullptr};
+    int                      mPointSize{0};
+    int                      mSegmentSize{0};
+    bool                     closed{false};
+    SW_FT_Stroker_LineCap    ftCap;
+    SW_FT_Stroker_LineJoin   ftJoin;
+    int                      ftWidth;
+    int                      ftMeterLimit;
+    SW_FT_Bool               ftClosed;
 };
 
+void FTOutline::grow(int points, int segments)
+{
+    if (mPointSize > points && mSegmentSize > segments)
+        return;
+    mPointSize = points;
+    mSegmentSize = segments;
+
+    int point_size = (points + segments);
+    int contour_size = ((sizeof(short) * segments) / sizeof(SW_FT_Vector)) + 1;
+    int tag_size = ((sizeof(char) * (points + segments)) / sizeof(SW_FT_Vector)) + 1;
+
+    releaseMemory();
+
+    /*
+     * Optimization, instead of allocating 3 different buffer
+     * allocate one big buffer and divide the buffer into 3 different
+     * segment.
+     */
+    mMemory = new SW_FT_Vector[point_size + contour_size + tag_size];
+    ft.points = reinterpret_cast<SW_FT_Vector *>(mMemory);
+    ft.tags = reinterpret_cast<char *>(mMemory + point_size);
+    ft.contours = reinterpret_cast<short *>(mMemory + point_size + tag_size);
+
+    ft.n_points = ft.n_contours = 0;
+    ft.flags = 0x0;
+}
 
+void FTOutline::convert(const VPath &path)
+{
+    const std::vector<VPath::Element> &elements = path.elements();
+    const std::vector<VPointF> &points = path.points();
 
-#define TO_FT_COORD(x) ((x) * 64) // to freetype 26.6 coordinate.
+    grow(points.size(), path.segments());
 
-void FTOutline::transform(const VMatrix &m)
-{
-    VPointF pt;
-    if (m.isIdentity()) return;
-    for (auto i = 0; i < ft.n_points; i++) {
-        pt = m.map(VPointF(ft.points[i].x/64.0, ft.points[i].y/64.0));
-        ft.points[i].x = TO_FT_COORD(pt.x());
-        ft.points[i].y = TO_FT_COORD(pt.y());
+    int index = 0;
+    for(auto element : elements) {
+        switch (element){
+        case VPath::Element::MoveTo:
+            moveTo(points[index]);
+            index++;
+            break;
+        case VPath::Element::LineTo:
+            lineTo(points[index]);
+            index++;
+            break;
+        case VPath::Element::CubicTo:
+            cubicTo(points[index], points[index+1], points[index+2]);
+            index = index+3;
+            break;
+        case VPath::Element::Close:
+            close();
+            break;
+        default:
+            break;
+        }
     }
+    end();
+}
+
+void FTOutline::convert(CapStyle cap, JoinStyle join,
+                        float width, float meterLimit)
+{
+    ftClosed = (SW_FT_Bool) closed;
+
+    // map strokeWidth to freetype. It uses as the radius of the pen not the diameter
+    width = width/2.0;
+    // convert to freetype co-ordinate
+    ftWidth = int(width * 64);
+    ftMeterLimit = int(meterLimit * 64);
+
+    // map to freetype capstyle
+    switch (cap)
+      {
+         case CapStyle::Square:
+           ftCap = SW_FT_STROKER_LINECAP_SQUARE;
+           break;
+         case CapStyle::Round:
+           ftCap = SW_FT_STROKER_LINECAP_ROUND;
+           break;
+         default:
+           ftCap = SW_FT_STROKER_LINECAP_BUTT;
+           break;
+      }
+    switch (join)
+      {
+         case JoinStyle::Bevel:
+           ftJoin = SW_FT_STROKER_LINEJOIN_BEVEL;
+           break;
+         case JoinStyle::Round:
+           ftJoin = SW_FT_STROKER_LINEJOIN_ROUND;
+           break;
+         default:
+           ftJoin = SW_FT_STROKER_LINEJOIN_MITER;
+           break;
+      }
 }
 
+
+#define TO_FT_COORD(x) ((x) * 64) // to freetype 26.6 coordinate.
+
 void FTOutline::moveTo(const VPointF &pt)
 {
     ft.points[ft.n_points].x = TO_FT_COORD(pt.x());
@@ -145,15 +232,15 @@ struct RleTask
     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;
+    VPath                    path;
+    FillRule                 fillRule;
+    CapStyle                 cap;
+    JoinStyle                join;
+    float                    width;
+    float                    meterLimit;
 };
 
-static VRle generateRleAsync(RleTask *task);
+static VRle generateRleAsync(RleTask *task, FTOutline &outRef);
 
 class RleTaskScheduler {
     const unsigned _count{std::thread::hardware_concurrency()};
@@ -164,14 +251,15 @@ class RleTaskScheduler {
     void run(unsigned i) {
         while (true) {
             RleTask *task = nullptr;
-
+            //@TODO why the outline creation dosen't work
+            //outside of while loop.
+            FTOutline  outlineRef;
             for (unsigned n = 0; n != _count * 32; ++n) {
                 if (_q[(i + n) % _count].try_pop(task)) break;
             }
             if (!task && !_q[i].pop(task)) break;
 
-            task->sender.set_value(generateRleAsync(task));
-            delete task->outline;
+            task->sender.set_value(generateRleAsync(task, outlineRef));
             delete task;
         }
     }
@@ -204,52 +292,51 @@ public:
         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) {
+    std::future<VRle> strokeRle(const VPath &path,
+                                CapStyle cap,
+                                JoinStyle join,
+                                float width,
+                                float meterLimit) {
         RleTask *task = new RleTask();
         task->stroke = true;
-        task->outline = outline;
+        task->path = path;
         task->cap = cap;
         task->join = join;
         task->width = width;
         task->meterLimit = meterLimit;
-        task->closed = closed;
         return async(task);
     }
 
-    std::future<VRle> fillRle(FTOutline *outline) {
+    std::future<VRle> fillRle(const VPath &path, FillRule fillRule) {
         RleTask *task = new RleTask();
+        task->path = path;
+        task->fillRule = fillRule;
         task->stroke = false;
-        task->outline = outline;
         return async(task);
     }
 };
 
 static RleTaskScheduler raster_scheduler;
 
-static VRle generateRleAsync(RleTask *task)
+static VRle generateRleAsync(RleTask *task, FTOutline &outRef)
 {
     if (task->stroke) {
+        outRef.convert(task->path);
+        outRef.convert(task->cap, task->join, task->width, task->meterLimit);
         // 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 };
 
-        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_Set(stroker, outRef.ftWidth, outRef.ftCap, outRef.ftJoin, outRef.ftMeterLimit);
+        SW_FT_Stroker_ParseOutline(stroker, &outRef.ft, !outRef.ftClosed);
         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));
+        FTOutline strokeOutline;
+        strokeOutline.grow(points, contors);
 
-        SW_FT_Stroker_Export(stroker, &strokeOutline);
+        SW_FT_Stroker_Export(stroker, &strokeOutline.ft);
 
         SW_FT_Stroker_Done(stroker);
 
@@ -263,24 +350,29 @@ static VRle generateRleAsync(RleTask *task)
 
         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
+        outRef.convert(task->path);
+        int fillRuleFlag = SW_FT_OUTLINE_NONE;
+        switch (task->fillRule) {
+        case FillRule::EvenOdd:
+            fillRuleFlag = SW_FT_OUTLINE_EVEN_ODD_FILL;
+            break;
+        default:
+            fillRuleFlag = SW_FT_OUTLINE_NONE;
+            break;
+        }
+        outRef.ft.flags =  fillRuleFlag;
         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;
+        params.source = &outRef.ft;
 
         sw_ft_grays_raster.raster_render(nullptr, &params);
-
         return rle;
     }
 }
@@ -293,109 +385,27 @@ VRaster::~VRaster()
 {
 }
 
-void VRaster::deleteFTOutline(FTOutline *outline)
-{
-    delete outline;
-}
-
-FTOutline *VRaster::toFTOutline(const VPath &path)
-{
-    if (path.isEmpty())
-        return nullptr;
-
-    const std::vector<VPath::Element> &elements = path.elements();
-    const std::vector<VPointF> &points = path.points();
-
-    FTOutline *outline = new FTOutline(points.size(), path.segments());
-
-    int index = 0;
-    for(auto element : elements) {
-        switch (element){
-        case VPath::Element::MoveTo:
-            outline->moveTo(points[index]);
-            index++;
-            break;
-        case VPath::Element::LineTo:
-            outline->lineTo(points[index]);
-            index++;
-            break;
-        case VPath::Element::CubicTo:
-            outline->cubicTo(points[index], points[index+1], points[index+2]);
-            index = index+3;
-            break;
-        case VPath::Element::Close:
-            outline->close();
-            break;
-        default:
-            break;
-        }
-    }
-    outline->end();
-    return outline;
-}
-
 std::future<VRle>
-VRaster::generateFillInfo(FTOutline *outline, FillRule fillRule)
+VRaster::generateFillInfo(const VPath &path, FillRule fillRule)
 {
-    int fillRuleFlag = SW_FT_OUTLINE_NONE;
-    switch (fillRule) {
-    case FillRule::EvenOdd:
-        fillRuleFlag = SW_FT_OUTLINE_EVEN_ODD_FILL;
-        break;
-    default:
-        fillRuleFlag = SW_FT_OUTLINE_NONE;
-        break;
+    if (path.isEmpty()) {
+        std::promise<VRle> promise;
+        promise.set_value(VRle());
+        return promise.get_future();
     }
-
-    outline->ft.flags =  fillRuleFlag;
-
-    return std::move(raster_scheduler.fillRle(outline));
+    return std::move(raster_scheduler.fillRle(path, fillRule));
 }
 
 std::future<VRle>
-VRaster::generateStrokeInfo(FTOutline *outline, CapStyle cap, JoinStyle join,
+VRaster::generateStrokeInfo(const VPath &path, 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 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;
-    // convert to freetype co-ordinate
-    ftWidth = int(width * 64);
-    ftMeterLimit = int(meterLimit * 64);
-
-    // map to freetype capstyle
-    switch (cap)
-      {
-         case CapStyle::Square:
-           ftCap = SW_FT_STROKER_LINECAP_SQUARE;
-           break;
-         case CapStyle::Round:
-           ftCap = SW_FT_STROKER_LINECAP_ROUND;
-           break;
-         default:
-           ftCap = SW_FT_STROKER_LINECAP_BUTT;
-           break;
-      }
-    switch (join)
-      {
-         case JoinStyle::Bevel:
-           ftJoin = SW_FT_STROKER_LINEJOIN_BEVEL;
-           break;
-         case JoinStyle::Round:
-           ftJoin = SW_FT_STROKER_LINEJOIN_ROUND;
-           break;
-         default:
-           ftJoin = SW_FT_STROKER_LINEJOIN_MITER;
-           break;
-      }
-
-    return std::move(raster_scheduler.strokeRle(outline, ftCap, ftJoin,
-                                                ftWidth, ftMeterLimit, ftclose));
+    if (path.isEmpty()) {
+        std::promise<VRle> promise;
+        promise.set_value(VRle());
+        return promise.get_future();
+    }
+    return std::move(raster_scheduler.strokeRle(path, cap, join, width, meterLimit));
 }
 
 V_END_NAMESPACE
index 65baab6..a2c1ad8 100644 (file)
@@ -23,14 +23,11 @@ public:
     VRaster& operator=(VRaster const&) = delete;
     VRaster& operator=(VRaster &&) = delete;
 
-    static FTOutline *toFTOutline(const VPath &path);
-    static void deleteFTOutline(FTOutline *);
-    std::future<VRle> generateFillInfo(FTOutline *, FillRule fillRule = FillRule::Winding);
-    std::future<VRle> generateStrokeInfo(FTOutline *, CapStyle cap, JoinStyle join,
+    std::future<VRle> generateFillInfo(const VPath &path, FillRule fillRule = FillRule::Winding);
+    std::future<VRle> generateStrokeInfo(const VPath &path, CapStyle cap, JoinStyle join,
                                          float width, float meterLimit);
 private:
     VRaster();
-    VRasterPrivate *d;
 };
 
 V_END_NAMESPACE