From f4a2c922be09aee4debce8a1dee646b02c8ca3b6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 5 Feb 2025 22:59:38 +0900 Subject: [PATCH] lottie: minor optimization use a reusable buffer for intermediate path generation. --- src/loaders/lottie/tvgLottieBuilder.cpp | 88 +++++++++++++----------- src/loaders/lottie/tvgLottieBuilder.h | 5 ++ src/loaders/lottie/tvgLottieModifier.cpp | 4 +- src/loaders/lottie/tvgLottieModifier.h | 2 +- src/renderer/tvgRender.h | 7 ++ 5 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index dc5cf331..65c93e9e 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -373,10 +373,15 @@ static void _repeat(LottieGroup* parent, Shape* path, RenderContext* ctx) } -static void _sharpRect(Point* pts, int& ptsCnt, PathCommand* cmds, int& cmdsCnt, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx) +static void _sharpRect(RenderPath& out, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx) { - ptsCnt = 4; - cmdsCnt = 5; + auto& pts = out.pts; + auto& cmds = out.cmds; + + pts.reserve(4); + pts.count = 4; + cmds.reserve(5); + cmds.count = 5; cmds[0] = PathCommand::MoveTo; cmds[1] = cmds[2] = cmds[3] = PathCommand::LineTo; @@ -394,10 +399,15 @@ static void _sharpRect(Point* pts, int& ptsCnt, PathCommand* cmds, int& cmdsCnt, } } -static void _roundRect(Point* pts, int& ptsCnt, PathCommand* cmds, int& cmdsCnt, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx) +static void _roundRect(RenderPath& out, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx) { - ptsCnt = 17; - cmdsCnt = 10; + auto& pts = out.pts; + auto& cmds = out.cmds; + + pts.reserve(17); + pts.count = 17; + cmds.reserve(10); + cmds.count = 10; auto hsize = size * 0.5f; auto rsize = Point{r > hsize.x ? hsize.x : r, r > hsize.y ? hsize.y : r}; @@ -435,23 +445,21 @@ static void _roundRect(Point* pts, int& ptsCnt, PathCommand* cmds, int& cmdsCnt, } -static void _appendRect(Shape* shape, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx) +void LottieBuilder::appendRect(Shape* shape, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx) { - Point pts[17]; - PathCommand cmds[10]; - int ptsCnt, cmdsCnt; + buffer.clear(); - if (tvg::zero(r)) _sharpRect(pts, ptsCnt, cmds, cmdsCnt, pos, size, r, clockwise, ctx); - else _roundRect(pts, ptsCnt, cmds, cmdsCnt, pos, size, r, clockwise, ctx); + if (tvg::zero(r)) _sharpRect(buffer, pos, size, r, clockwise, ctx); + else _roundRect(buffer, pos, size, r, clockwise, ctx); if (ctx->transform) { - for (int i = 0; i < ptsCnt; i++) { - pts[i] *= *ctx->transform; + ARRAY_FOREACH(pt, buffer.pts) { + *pt *= *ctx->transform; } } - if (ctx->offset) ctx->offset->modifyRect(cmds, cmdsCnt, pts, ptsCnt, SHAPE(shape)->rs.path); - else shape->appendPath(cmds, cmdsCnt, pts, ptsCnt); + if (ctx->offset) ctx->offset->modifyRect(buffer, SHAPE(shape)->rs.path); + else shape->appendPath(buffer.cmds.data, buffer.cmds.count, buffer.pts.data, buffer.pts.count); } @@ -471,11 +479,11 @@ void LottieBuilder::updateRect(LottieGroup* parent, LottieObject** child, float if (!ctx->repeaters.empty()) { auto shape = rect->pooling(); shape->reset(); - _appendRect(shape, pos, size, r, rect->clockwise, ctx); + appendRect(shape, pos, size, r, rect->clockwise, ctx); _repeat(parent, shape, ctx); } else { _draw(parent, rect, ctx); - _appendRect(ctx->merging, pos, size, r, rect->clockwise, ctx); + appendRect(ctx->merging, pos, size, r, rect->clockwise, ctx); } } @@ -550,7 +558,7 @@ void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float } -static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offset, float frameNo, Shape* merging, LottieExpressions* exps) +void LottieBuilder::updateStar(LottiePolyStar* star, float frameNo, Matrix* transform, Shape* merging, RenderContext* ctx) { static constexpr auto POLYSTAR_MAGIC_NUMBER = 0.47829f / 0.28f; @@ -569,10 +577,10 @@ static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Ma auto numPoints = size_t(ceilf(ptsCnt) * 2); auto direction = star->clockwise ? 1.0f : -1.0f; auto hasRoundness = false; - bool roundedCorner = roundness && (tvg::zero(innerRoundness) || tvg::zero(outerRoundness)); + bool roundedCorner = ctx->roundness && (tvg::zero(innerRoundness) || tvg::zero(outerRoundness)); Shape* shape; - if (roundedCorner || offset) { + if (roundedCorner || ctx->offset) { shape = star->pooling(); shape->reset(); } else { @@ -667,16 +675,16 @@ static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Ma shape->close(); if (roundedCorner) { - if (offset) { - RenderPath temp; - roundness->modifyPolystar(SHAPE(shape)->rs.path, temp, outerRoundness, hasRoundness); - offset->modifyPolystar(temp, SHAPE(merging)->rs.path); - } else roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, outerRoundness, hasRoundness); - } else if (offset) offset->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path); + if (ctx->offset) { + buffer.clear(); + ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, buffer, outerRoundness, hasRoundness); + ctx->offset->modifyPolystar(buffer, SHAPE(merging)->rs.path); + } else ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, outerRoundness, hasRoundness); + } else if (ctx->offset) ctx->offset->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path); } -static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offset, float frameNo, Shape* merging, LottieExpressions* exps) +void LottieBuilder::updatePolygon(LottieGroup* parent, LottiePolyStar* star, float frameNo, Matrix* transform, Shape* merging, RenderContext* ctx) { static constexpr auto POLYGON_MAGIC_NUMBER = 0.25f; @@ -688,14 +696,14 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr auto anglePerPoint = 2.0f * MATH_PI / float(ptsCnt); auto direction = star->clockwise ? 1.0f : -1.0f; auto hasRoundness = !tvg::zero(outerRoundness); - bool roundedCorner = roundness && !hasRoundness; + bool roundedCorner = ctx->roundness && !hasRoundness; auto x = radius * cosf(angle); auto y = radius * sinf(angle); angle += anglePerPoint * direction; Shape* shape; - if (roundedCorner || offset) { + if (roundedCorner || ctx->offset) { shape = star->pooling(); shape->reset(); } else { @@ -751,12 +759,12 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr shape->close(); if (roundedCorner) { - if (offset) { - RenderPath temp; - roundness->modifyPolystar(SHAPE(shape)->rs.path, temp, 0.0f, false); - offset->modifyPolystar(temp, SHAPE(merging)->rs.path); - } else roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, 0.0f, false); - } else if (offset) offset->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path); + if (ctx->offset) { + buffer.clear(); + ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, buffer, 0.0f, false); + ctx->offset->modifyPolystar(buffer, SHAPE(merging)->rs.path); + } else ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, 0.0f, false); + } else if (ctx->offset) ctx->offset->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path); } @@ -777,13 +785,13 @@ void LottieBuilder::updatePolystar(LottieGroup* parent, LottieObject** child, fl if (!ctx->repeaters.empty()) { auto shape = star->pooling(); shape->reset(); - if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offset, frameNo, shape, exps); - else _updatePolygon(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offset, frameNo, shape, exps); + if (star->type == LottiePolyStar::Star) updateStar(star, frameNo, (identity ? nullptr : &matrix), shape, ctx); + else updatePolygon(parent, star, frameNo, (identity ? nullptr : &matrix), shape, ctx); _repeat(parent, shape, ctx); } else { _draw(parent, star, ctx); - if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offset, frameNo, ctx->merging, exps); - else _updatePolygon(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offset, frameNo, ctx->merging, exps); + if (star->type == LottiePolyStar::Star) updateStar(star, frameNo, (identity ? nullptr : &matrix), ctx->merging, ctx); + else updatePolygon(parent, star, frameNo, (identity ? nullptr : &matrix), ctx->merging, ctx); PAINT(ctx->merging)->update(RenderUpdateFlag::Path); } } diff --git a/src/loaders/lottie/tvgLottieBuilder.h b/src/loaders/lottie/tvgLottieBuilder.h index 9e2f1d1a..6cc58a74 100644 --- a/src/loaders/lottie/tvgLottieBuilder.h +++ b/src/loaders/lottie/tvgLottieBuilder.h @@ -107,6 +107,8 @@ struct LottieBuilder void build(LottieComposition* comp); private: + void appendRect(Shape* shape, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx); + void updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo); void updateEffect(LottieLayer* layer, float frameNo); void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo); @@ -128,11 +130,14 @@ private: void updateEllipse(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); void updatePath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); void updatePolystar(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); + void updateStar(LottiePolyStar* star, float frameNo, Matrix* transform, Shape* merging, RenderContext* ctx); + void updatePolygon(LottieGroup* parent, LottiePolyStar* star, float frameNo, Matrix* transform, Shape* merging, RenderContext* ctx); void updateTrimpath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); void updateRepeater(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); void updateRoundedCorner(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); void updateOffsetPath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist& contexts, RenderContext* ctx); + RenderPath buffer; //resusable path LottieExpressions* exps; }; diff --git a/src/loaders/lottie/tvgLottieModifier.cpp b/src/loaders/lottie/tvgLottieModifier.cpp index d698a2f0..9d3a6327 100644 --- a/src/loaders/lottie/tvgLottieModifier.cpp +++ b/src/loaders/lottie/tvgLottieModifier.cpp @@ -381,9 +381,9 @@ bool LottieOffsetModifier::modifyPolystar(RenderPath& in, RenderPath& out) const } -bool LottieOffsetModifier::modifyRect(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, RenderPath& out) const +bool LottieOffsetModifier::modifyRect(RenderPath& in, RenderPath& out) const { - return modifyPath(inCmds, inCmdsCnt, inPts, inPtsCnt, out); + return modifyPath(in.cmds.data, in.cmds.count, in.pts.data, in.pts.count, out); } diff --git a/src/loaders/lottie/tvgLottieModifier.h b/src/loaders/lottie/tvgLottieModifier.h index e30fbc27..53a34f34 100644 --- a/src/loaders/lottie/tvgLottieModifier.h +++ b/src/loaders/lottie/tvgLottieModifier.h @@ -51,7 +51,7 @@ struct LottieOffsetModifier bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, RenderPath& out) const; bool modifyPolystar(RenderPath& in, RenderPath& out) const; - bool modifyRect(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, RenderPath& out) const; + bool modifyRect(RenderPath& in, RenderPath& out) const; bool modifyEllipse(Point& radius) const; private: diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index 7748b5be..ac45ea88 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -174,6 +174,13 @@ struct RenderPath { Array cmds; Array pts; + + void clear() + { + pts.clear(); + cmds.clear(); + } + }; struct RenderShape