lottie: introduced LottieRenderPooler

LottieRenderPooler is designed to manages rendering
instances(paints) efficiently through a simple pooling
mechanism to resuse among the animations

This replaces the previous individusal paints implemenations
among solidfill, precomp vierport and pictures,
also fix a potential paints corruption problems.
This commit is contained in:
Hermet Park 2024-07-12 15:13:10 +09:00
parent d13606e14b
commit 1131695ce4
5 changed files with 101 additions and 50 deletions

View file

@ -11,6 +11,7 @@ source_file = [
'tvgLottieParser.h', 'tvgLottieParser.h',
'tvgLottieParserHandler.h', 'tvgLottieParserHandler.h',
'tvgLottieProperty.h', 'tvgLottieProperty.h',
'tvgLottieRenderPooler.h',
'tvgLottieAnimation.cpp', 'tvgLottieAnimation.cpp',
'tvgLottieBuilder.cpp', 'tvgLottieBuilder.cpp',
'tvgLottieExpressions.cpp', 'tvgLottieExpressions.cpp',

View file

@ -28,7 +28,6 @@
#include "tvgPaint.h" #include "tvgPaint.h"
#include "tvgShape.h" #include "tvgShape.h"
#include "tvgInlist.h" #include "tvgInlist.h"
#include "tvgTaskScheduler.h"
#include "tvgLottieModel.h" #include "tvgLottieModel.h"
#include "tvgLottieBuilder.h" #include "tvgLottieBuilder.h"
#include "tvgLottieExpressions.h" #include "tvgLottieExpressions.h"
@ -1043,44 +1042,24 @@ static void _updatePrecomp(LottieLayer* precomp, float frameNo, LottieExpression
} }
//clip the layer viewport //clip the layer viewport
if (!precomp->clipper) { auto clipper = precomp->pooling();
precomp->clipper = Shape::gen().release(); clipper->transform(precomp->cache.matrix);
precomp->clipper->appendRect(0.0f, 0.0f, precomp->w, precomp->h); precomp->scene->composite(cast(clipper), CompositeMethod::ClipPath);
PP(precomp->clipper)->ref();
}
precomp->clipper->transform(precomp->cache.matrix);
precomp->scene->composite(cast(precomp->clipper), CompositeMethod::ClipPath);
} }
static void _updateSolid(LottieLayer* layer) static void _updateSolid(LottieLayer* layer)
{ {
layer->solidFill->opacity(layer->cache.opacity); auto solidFill = layer->pooling();
layer->scene->push(cast(layer->solidFill)); solidFill->opacity(layer->cache.opacity);
layer->scene->push(cast(solidFill));
} }
static void _updateImage(LottieGroup* layer) static void _updateImage(LottieGroup* layer)
{ {
auto image = static_cast<LottieImage*>(layer->children.first()); auto image = static_cast<LottieImage*>(layer->children.first());
layer->scene->push(tvg::cast(image->pooling()));
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, false);
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()));
} }
@ -1344,7 +1323,6 @@ static void _buildReference(LottieComposition* comp, LottieLayer* layer)
layer->reqFragment = assetLayer->reqFragment; layer->reqFragment = assetLayer->reqFragment;
} }
} else if (layer->type == LottieLayer::Image) { } else if (layer->type == LottieLayer::Image) {
++static_cast<LottieImage*>(*asset)->refCnt;
layer->children.push(*asset); layer->children.push(*asset);
} }
break; break;

View file

@ -23,6 +23,7 @@
#include "tvgMath.h" #include "tvgMath.h"
#include "tvgPaint.h" #include "tvgPaint.h"
#include "tvgFill.h" #include "tvgFill.h"
#include "tvgTaskScheduler.h"
#include "tvgLottieModel.h" #include "tvgLottieModel.h"
@ -111,14 +112,32 @@ void LottieSlot::assign(LottieObject* target)
LottieImage::~LottieImage() LottieImage::~LottieImage()
{ {
if (picture && PP(picture)->unref() == 0) {
delete(picture);
}
free(b64Data); free(b64Data);
free(mimeType); 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, false);
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) void LottieTrimpath::segment(float frameNo, float& start, float& end, LottieExpressions* exps)
{ {
start = this->start(frameNo, exps) * 0.01f; start = this->start(frameNo, exps) * 0.01f;
@ -331,10 +350,6 @@ LottieLayer::~LottieLayer()
delete(*m); delete(*m);
} }
//Remove tvg render paints
if (solidFill && PP(solidFill)->unref() == 0) delete(solidFill);
if (clipper && PP(clipper)->unref() == 0) delete(clipper);
delete(transform); delete(transform);
free(name); free(name);
} }
@ -351,12 +366,19 @@ void LottieLayer::prepare(RGB24* color)
return; 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. //prepare solid fill in advance if it is a layer type.
if (color && type == LottieLayer::Solid) { } else if (color && type == LottieLayer::Solid) {
solidFill = Shape::gen().release(); auto solidFill = Shape::gen().release();
solidFill->appendRect(0, 0, static_cast<float>(w), static_cast<float>(h)); solidFill->appendRect(0, 0, static_cast<float>(w), static_cast<float>(h));
solidFill->fill(color->rgb[0], color->rgb[1], color->rgb[2]); solidFill->fill(color->rgb[0], color->rgb[1], color->rgb[2]);
PP(solidFill)->ref(); PP(solidFill)->ref();
pooler.push(solidFill);
} }
LottieGroup::prepare(LottieObject::Layer); LottieGroup::prepare(LottieObject::Layer);

View file

@ -28,6 +28,7 @@
#include "tvgCommon.h" #include "tvgCommon.h"
#include "tvgRender.h" #include "tvgRender.h"
#include "tvgLottieProperty.h" #include "tvgLottieProperty.h"
#include "tvgLottieRenderPooler.h"
struct LottieComposition; struct LottieComposition;
@ -490,25 +491,19 @@ struct LottieGradientStroke : LottieGradient, LottieStroke
}; };
struct LottieImage : LottieObject struct LottieImage : LottieObject, LottieRenderPooler<tvg::Picture>
{ {
union { union {
char* b64Data = nullptr; char* b64Data = nullptr;
char* path; char* path;
}; };
Picture* picture = nullptr; //tvg render data
char* mimeType = nullptr; char* mimeType = nullptr;
uint32_t size = 0; uint32_t size = 0;
uint16_t refCnt = 0; //refernce count
float width = 0.0f; float width = 0.0f;
float height = 0.0f; float height = 0.0f;
~LottieImage(); ~LottieImage();
void prepare();
void prepare()
{
LottieObject::type = LottieObject::Image;
}
}; };
@ -567,7 +562,7 @@ struct LottieGroup : LottieObject
}; };
struct LottieLayer : LottieGroup struct LottieLayer : LottieGroup, LottieRenderPooler<tvg::Shape>
{ {
enum Type : uint8_t {Precomp = 0, Solid, Image, Null, Shape, Text}; enum Type : uint8_t {Precomp = 0, Solid, Image, Null, Shape, Text};
@ -593,9 +588,6 @@ struct LottieLayer : LottieGroup
Array<LottieMask*> masks; Array<LottieMask*> masks;
LottieLayer* matteTarget = nullptr; LottieLayer* matteTarget = nullptr;
tvg::Shape* solidFill = nullptr;
tvg::Shape* clipper = nullptr;
float timeStretch = 1.0f; float timeStretch = 1.0f;
float w = 0.0f, h = 0.0f; float w = 0.0f, h = 0.0f;
float inFrame = 0.0f; float inFrame = 0.0f;

View file

@ -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<typename T>
struct LottieRenderPooler
{
Array<T*> 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<T*>(pooler[0]->duplicate());
PP(p)->ref();
pooler.push(p);
return p;
}
};
#endif //_TVG_LOTTIE_RENDER_POOLER_H_