From: subhransu mohanty Date: Tue, 24 Jul 2018 00:57:20 +0000 (+0900) Subject: lottie/vector: refactor vraster to optimize number of memory allocation. X-Git-Tag: submit/tizen/20180917.042405~197 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=85a5463cc0b90b7c0d5a8e1d88bcb080c268b58c;p=platform%2Fcore%2Fuifw%2Flottie-player.git lottie/vector: refactor vraster to optimize number of memory allocation. Change-Id: I55ffb29d9a039a458830200a56ff3a6a057ff361 --- diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 53cd79a..a55bc3c 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -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() diff --git a/src/vector/vraster.cpp b/src/vector/vraster.cpp index 814d537..689db38 100644 --- a/src/vector/vraster.cpp +++ b/src/vector/vraster.cpp @@ -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(mMemory); + ft.tags = reinterpret_cast(mMemory + point_size); + ft.contours = reinterpret_cast(mMemory + point_size + tag_size); + + ft.n_points = ft.n_contours = 0; + ft.flags = 0x0; +} +void FTOutline::convert(const VPath &path) +{ + const std::vector &elements = path.elements(); + const std::vector &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 sender; std::future 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 strokeRle(FTOutline *outline, - SW_FT_Stroker_LineCap cap, - SW_FT_Stroker_LineJoin join, - int width, - int meterLimit, - SW_FT_Bool closed) { + std::future 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 fillRle(FTOutline *outline) { + std::future 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, ¶ms); - // 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, ¶ms); - 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 &elements = path.elements(); - const std::vector &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 -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 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 -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 promise; + promise.set_value(VRle()); + return promise.get_future(); + } + return std::move(raster_scheduler.strokeRle(path, cap, join, width, meterLimit)); } V_END_NAMESPACE diff --git a/src/vector/vraster.h b/src/vector/vraster.h index 65baab6..a2c1ad8 100644 --- a/src/vector/vraster.h +++ b/src/vector/vraster.h @@ -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 generateFillInfo(FTOutline *, FillRule fillRule = FillRule::Winding); - std::future generateStrokeInfo(FTOutline *, CapStyle cap, JoinStyle join, + std::future generateFillInfo(const VPath &path, FillRule fillRule = FillRule::Winding); + std::future generateStrokeInfo(const VPath &path, CapStyle cap, JoinStyle join, float width, float meterLimit); private: VRaster(); - VRasterPrivate *d; }; V_END_NAMESPACE