diff --git a/src/loaders/lottie/meson.build b/src/loaders/lottie/meson.build index 3af9e254..cfa35656 100644 --- a/src/loaders/lottie/meson.build +++ b/src/loaders/lottie/meson.build @@ -11,6 +11,7 @@ source_file = [ 'tvgLottieParser.h', 'tvgLottieParserHandler.h', 'tvgLottieProperty.h', + 'tvgLottieRenderPooler.h', 'tvgLottieAnimation.cpp', 'tvgLottieBuilder.cpp', 'tvgLottieExpressions.cpp', diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index f5f60042..f8b88e27 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -28,7 +28,6 @@ #include "tvgPaint.h" #include "tvgShape.h" #include "tvgInlist.h" -#include "tvgTaskScheduler.h" #include "tvgLottieModel.h" #include "tvgLottieBuilder.h" #include "tvgLottieExpressions.h" @@ -1043,44 +1042,24 @@ static void _updatePrecomp(LottieLayer* precomp, float frameNo, LottieExpression } //clip the layer viewport - if (!precomp->clipper) { - precomp->clipper = Shape::gen().release(); - precomp->clipper->appendRect(0.0f, 0.0f, precomp->w, precomp->h); - PP(precomp->clipper)->ref(); - } - precomp->clipper->transform(precomp->cache.matrix); - precomp->scene->composite(cast(precomp->clipper), CompositeMethod::ClipPath); + auto clipper = precomp->pooling(); + clipper->transform(precomp->cache.matrix); + precomp->scene->composite(cast(clipper), CompositeMethod::ClipPath); } static void _updateSolid(LottieLayer* layer) { - layer->solidFill->opacity(layer->cache.opacity); - layer->scene->push(cast(layer->solidFill)); + auto solidFill = layer->pooling(); + solidFill->opacity(layer->cache.opacity); + layer->scene->push(cast(solidFill)); } static void _updateImage(LottieGroup* layer) { auto image = static_cast(layer->children.first()); - - if (!image->picture) { - image->picture = Picture::gen().release(); - - //force to load a picture on the same thread - TaskScheduler::async(false); - - if (image->size > 0) image->picture->load((const char*)image->b64Data, image->size, image->mimeType); - else image->picture->load(image->path); - - TaskScheduler::async(true); - - PP(image->picture)->ref(); - image->picture->size(image->width, image->height); - } - - if (image->refCnt == 1) layer->scene->push(tvg::cast(image->picture)); - else layer->scene->push(tvg::cast(image->picture->duplicate())); + layer->scene->push(tvg::cast(image->pooling())); } @@ -1344,7 +1323,6 @@ static void _buildReference(LottieComposition* comp, LottieLayer* layer) layer->reqFragment = assetLayer->reqFragment; } } else if (layer->type == LottieLayer::Image) { - ++static_cast(*asset)->refCnt; layer->children.push(*asset); } break; diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index 55723f1e..39523e70 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -23,6 +23,7 @@ #include "tvgMath.h" #include "tvgPaint.h" #include "tvgFill.h" +#include "tvgTaskScheduler.h" #include "tvgLottieModel.h" @@ -111,14 +112,32 @@ void LottieSlot::assign(LottieObject* target) LottieImage::~LottieImage() { - if (picture && PP(picture)->unref() == 0) { - delete(picture); - } free(b64Data); free(mimeType); } +void LottieImage::prepare() +{ + LottieObject::type = LottieObject::Image; + + auto picture = Picture::gen().release(); + + //force to load a picture on the same thread + TaskScheduler::async(false); + + if (size > 0) picture->load((const char*)b64Data, size, mimeType); + else picture->load(path); + + TaskScheduler::async(true); + + picture->size(width, height); + PP(picture)->ref(); + + pooler.push(picture); +} + + void LottieTrimpath::segment(float frameNo, float& start, float& end, LottieExpressions* exps) { start = this->start(frameNo, exps) * 0.01f; @@ -331,10 +350,6 @@ LottieLayer::~LottieLayer() delete(*m); } - //Remove tvg render paints - if (solidFill && PP(solidFill)->unref() == 0) delete(solidFill); - if (clipper && PP(clipper)->unref() == 0) delete(clipper); - delete(transform); free(name); } @@ -351,12 +366,19 @@ void LottieLayer::prepare(RGB24* color) return; } + //prepare the viewport clipper + if (type == LottieLayer::Precomp) { + auto clipper = Shape::gen().release(); + clipper->appendRect(0.0f, 0.0f, w, h); + PP(clipper)->ref(); + pooler.push(clipper); //prepare solid fill in advance if it is a layer type. - if (color && type == LottieLayer::Solid) { - solidFill = Shape::gen().release(); + } else if (color && type == LottieLayer::Solid) { + auto solidFill = Shape::gen().release(); solidFill->appendRect(0, 0, static_cast(w), static_cast(h)); solidFill->fill(color->rgb[0], color->rgb[1], color->rgb[2]); PP(solidFill)->ref(); + pooler.push(solidFill); } LottieGroup::prepare(LottieObject::Layer); diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index 7809850e..52508b04 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -28,6 +28,7 @@ #include "tvgCommon.h" #include "tvgRender.h" #include "tvgLottieProperty.h" +#include "tvgLottieRenderPooler.h" struct LottieComposition; @@ -490,25 +491,19 @@ struct LottieGradientStroke : LottieGradient, LottieStroke }; -struct LottieImage : LottieObject +struct LottieImage : LottieObject, LottieRenderPooler { union { char* b64Data = nullptr; char* path; }; - Picture* picture = nullptr; //tvg render data char* mimeType = nullptr; uint32_t size = 0; - uint16_t refCnt = 0; //refernce count float width = 0.0f; float height = 0.0f; ~LottieImage(); - - void prepare() - { - LottieObject::type = LottieObject::Image; - } + void prepare(); }; @@ -567,7 +562,7 @@ struct LottieGroup : LottieObject }; -struct LottieLayer : LottieGroup +struct LottieLayer : LottieGroup, LottieRenderPooler { enum Type : uint8_t {Precomp = 0, Solid, Image, Null, Shape, Text}; @@ -593,9 +588,6 @@ struct LottieLayer : LottieGroup Array masks; LottieLayer* matteTarget = nullptr; - tvg::Shape* solidFill = nullptr; - tvg::Shape* clipper = nullptr; - float timeStretch = 1.0f; float w = 0.0f, h = 0.0f; float inFrame = 0.0f; diff --git a/src/loaders/lottie/tvgLottieRenderPooler.h b/src/loaders/lottie/tvgLottieRenderPooler.h new file mode 100644 index 00000000..4bd818ba --- /dev/null +++ b/src/loaders/lottie/tvgLottieRenderPooler.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TVG_LOTTIE_RENDER_POOLER_H_ +#define _TVG_LOTTIE_RENDER_POOLER_H_ + +#include "tvgCommon.h" +#include "tvgArray.h" +#include "tvgPaint.h" + + +template +struct LottieRenderPooler +{ + Array pooler; + + ~LottieRenderPooler() + { + for (auto p = pooler.begin(); p < pooler.end(); ++p) { + if (PP(*p)->unref() == 0) delete(*p); + } + } + + T* pooling() + { + //return available one. + for (auto p = pooler.begin(); p < pooler.end(); ++p) { + if (PP(*p)->refCnt == 1) return *p; + } + + //no empty, generate a new one. + auto p = static_cast(pooler[0]->duplicate()); + PP(p)->ref(); + pooler.push(p); + return p; + } +}; + +#endif //_TVG_LOTTIE_RENDER_POOLER_H_ \ No newline at end of file