lottie: minor optimization

use a reusable buffer for intermediate path generation.
This commit is contained in:
Hermet Park 2025-02-05 22:59:38 +09:00 committed by Hermet Park
parent 4edaf311c6
commit f4a2c922be
5 changed files with 63 additions and 43 deletions

View file

@ -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; auto& pts = out.pts;
cmdsCnt = 5; auto& cmds = out.cmds;
pts.reserve(4);
pts.count = 4;
cmds.reserve(5);
cmds.count = 5;
cmds[0] = PathCommand::MoveTo; cmds[0] = PathCommand::MoveTo;
cmds[1] = cmds[2] = cmds[3] = PathCommand::LineTo; 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; auto& pts = out.pts;
cmdsCnt = 10; auto& cmds = out.cmds;
pts.reserve(17);
pts.count = 17;
cmds.reserve(10);
cmds.count = 10;
auto hsize = size * 0.5f; auto hsize = size * 0.5f;
auto rsize = Point{r > hsize.x ? hsize.x : r, r > hsize.y ? hsize.y : r}; 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]; buffer.clear();
PathCommand cmds[10];
int ptsCnt, cmdsCnt;
if (tvg::zero(r)) _sharpRect(pts, ptsCnt, cmds, cmdsCnt, pos, size, r, clockwise, ctx); if (tvg::zero(r)) _sharpRect(buffer, pos, size, r, clockwise, ctx);
else _roundRect(pts, ptsCnt, cmds, cmdsCnt, pos, size, r, clockwise, ctx); else _roundRect(buffer, pos, size, r, clockwise, ctx);
if (ctx->transform) { if (ctx->transform) {
for (int i = 0; i < ptsCnt; i++) { ARRAY_FOREACH(pt, buffer.pts) {
pts[i] *= *ctx->transform; *pt *= *ctx->transform;
} }
} }
if (ctx->offset) ctx->offset->modifyRect(cmds, cmdsCnt, pts, ptsCnt, SHAPE(shape)->rs.path); if (ctx->offset) ctx->offset->modifyRect(buffer, SHAPE(shape)->rs.path);
else shape->appendPath(cmds, cmdsCnt, pts, ptsCnt); 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()) { if (!ctx->repeaters.empty()) {
auto shape = rect->pooling(); auto shape = rect->pooling();
shape->reset(); shape->reset();
_appendRect(shape, pos, size, r, rect->clockwise, ctx); appendRect(shape, pos, size, r, rect->clockwise, ctx);
_repeat(parent, shape, ctx); _repeat(parent, shape, ctx);
} else { } else {
_draw(parent, rect, ctx); _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; 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 numPoints = size_t(ceilf(ptsCnt) * 2);
auto direction = star->clockwise ? 1.0f : -1.0f; auto direction = star->clockwise ? 1.0f : -1.0f;
auto hasRoundness = false; auto hasRoundness = false;
bool roundedCorner = roundness && (tvg::zero(innerRoundness) || tvg::zero(outerRoundness)); bool roundedCorner = ctx->roundness && (tvg::zero(innerRoundness) || tvg::zero(outerRoundness));
Shape* shape; Shape* shape;
if (roundedCorner || offset) { if (roundedCorner || ctx->offset) {
shape = star->pooling(); shape = star->pooling();
shape->reset(); shape->reset();
} else { } else {
@ -667,16 +675,16 @@ static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Ma
shape->close(); shape->close();
if (roundedCorner) { if (roundedCorner) {
if (offset) { if (ctx->offset) {
RenderPath temp; buffer.clear();
roundness->modifyPolystar(SHAPE(shape)->rs.path, temp, outerRoundness, hasRoundness); ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, buffer, outerRoundness, hasRoundness);
offset->modifyPolystar(temp, SHAPE(merging)->rs.path); ctx->offset->modifyPolystar(buffer, SHAPE(merging)->rs.path);
} else roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, outerRoundness, hasRoundness); } else ctx->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); } 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; 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 anglePerPoint = 2.0f * MATH_PI / float(ptsCnt);
auto direction = star->clockwise ? 1.0f : -1.0f; auto direction = star->clockwise ? 1.0f : -1.0f;
auto hasRoundness = !tvg::zero(outerRoundness); auto hasRoundness = !tvg::zero(outerRoundness);
bool roundedCorner = roundness && !hasRoundness; bool roundedCorner = ctx->roundness && !hasRoundness;
auto x = radius * cosf(angle); auto x = radius * cosf(angle);
auto y = radius * sinf(angle); auto y = radius * sinf(angle);
angle += anglePerPoint * direction; angle += anglePerPoint * direction;
Shape* shape; Shape* shape;
if (roundedCorner || offset) { if (roundedCorner || ctx->offset) {
shape = star->pooling(); shape = star->pooling();
shape->reset(); shape->reset();
} else { } else {
@ -751,12 +759,12 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr
shape->close(); shape->close();
if (roundedCorner) { if (roundedCorner) {
if (offset) { if (ctx->offset) {
RenderPath temp; buffer.clear();
roundness->modifyPolystar(SHAPE(shape)->rs.path, temp, 0.0f, false); ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, buffer, 0.0f, false);
offset->modifyPolystar(temp, SHAPE(merging)->rs.path); ctx->offset->modifyPolystar(buffer, SHAPE(merging)->rs.path);
} else roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, 0.0f, false); } else ctx->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); } 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()) { if (!ctx->repeaters.empty()) {
auto shape = star->pooling(); auto shape = star->pooling();
shape->reset(); shape->reset();
if (star->type == LottiePolyStar::Star) _updateStar(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, identity ? nullptr : &matrix, ctx->roundness, ctx->offset, frameNo, shape, exps); else updatePolygon(parent, star, frameNo, (identity ? nullptr : &matrix), shape, ctx);
_repeat(parent, shape, ctx); _repeat(parent, shape, ctx);
} else { } else {
_draw(parent, star, ctx); _draw(parent, star, ctx);
if (star->type == LottiePolyStar::Star) _updateStar(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, identity ? nullptr : &matrix, ctx->roundness, ctx->offset, frameNo, ctx->merging, exps); else updatePolygon(parent, star, frameNo, (identity ? nullptr : &matrix), ctx->merging, ctx);
PAINT(ctx->merging)->update(RenderUpdateFlag::Path); PAINT(ctx->merging)->update(RenderUpdateFlag::Path);
} }
} }

View file

@ -107,6 +107,8 @@ struct LottieBuilder
void build(LottieComposition* comp); void build(LottieComposition* comp);
private: private:
void appendRect(Shape* shape, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx);
void updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo); void updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo);
void updateEffect(LottieLayer* layer, float frameNo); void updateEffect(LottieLayer* layer, float frameNo);
void updateLayer(LottieComposition* comp, Scene* scene, 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<RenderContext>& contexts, RenderContext* ctx); void updateEllipse(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx);
void updatePath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx); void updatePath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx);
void updatePolystar(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx); void updatePolystar(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& 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<RenderContext>& contexts, RenderContext* ctx); void updateTrimpath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx);
void updateRepeater(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx); void updateRepeater(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx);
void updateRoundedCorner(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx); void updateRoundedCorner(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx);
void updateOffsetPath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx); void updateOffsetPath(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx);
RenderPath buffer; //resusable path
LottieExpressions* exps; LottieExpressions* exps;
}; };

View file

@ -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);
} }

View file

@ -51,7 +51,7 @@ struct LottieOffsetModifier
bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, RenderPath& out) const; bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, RenderPath& out) const;
bool modifyPolystar(RenderPath& in, 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; bool modifyEllipse(Point& radius) const;
private: private:

View file

@ -174,6 +174,13 @@ struct RenderPath
{ {
Array<PathCommand> cmds; Array<PathCommand> cmds;
Array<Point> pts; Array<Point> pts;
void clear()
{
pts.clear();
cmds.clear();
}
}; };
struct RenderShape struct RenderShape