mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 11:36:25 +00:00
lottie: introduced static layer cache.
lottie builder doesn't need to rebuild the layer object if it has no any animation frame data. That case, we can cache the layer scene in order to reuse it. Tested on local machine (single thread): - Lottie: appx. 2ms enhanced. - Binary: +204
This commit is contained in:
parent
978f85c3ea
commit
d37c500262
4 changed files with 45 additions and 16 deletions
|
@ -84,7 +84,7 @@ struct RenderContext
|
|||
|
||||
|
||||
static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderContext>& contexts);
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo);
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo, bool caching);
|
||||
static bool _buildComposition(LottieComposition* comp, LottieGroup* parent);
|
||||
|
||||
static void _rotateX(Matrix* m, float degree)
|
||||
|
@ -803,15 +803,14 @@ static void _updateChildren(LottieGroup* parent, float frameNo, queue<RenderCont
|
|||
}
|
||||
|
||||
|
||||
static void _updatePrecomp(LottieLayer* precomp, float frameNo)
|
||||
static void _updatePrecomp(LottieLayer* precomp, float frameNo, bool caching)
|
||||
{
|
||||
if (precomp->children.count == 0) return;
|
||||
|
||||
frameNo = precomp->remap(frameNo);
|
||||
|
||||
//TODO: skip if the layer is static.
|
||||
for (auto child = precomp->children.end() - 1; child >= precomp->children.data; --child) {
|
||||
_updateLayer(precomp, static_cast<LottieLayer*>(*child), frameNo);
|
||||
_updateLayer(precomp, static_cast<LottieLayer*>(*child), frameNo, caching);
|
||||
}
|
||||
|
||||
//clip the layer viewport
|
||||
|
@ -875,12 +874,18 @@ static void _updateMaskings(LottieLayer* layer, float frameNo)
|
|||
}
|
||||
|
||||
|
||||
static bool _updateMatte(LottieLayer* root, LottieLayer* layer, float frameNo)
|
||||
static bool _updateMatte(LottieLayer* root, LottieLayer* layer, float frameNo, bool caching)
|
||||
{
|
||||
auto target = layer->matte.target;
|
||||
if (!target) return true;
|
||||
|
||||
_updateLayer(root, target, frameNo);
|
||||
if (target->cache.scene) {
|
||||
//TODO: remove duplicate, share the scene.
|
||||
layer->scene->composite(cast(target->cache.scene->duplicate()), layer->matte.type);
|
||||
return true;
|
||||
}
|
||||
|
||||
_updateLayer(root, target, frameNo, caching);
|
||||
|
||||
if (target->scene) {
|
||||
layer->scene->composite(cast(target->scene), layer->matte.type);
|
||||
|
@ -894,18 +899,31 @@ static bool _updateMatte(LottieLayer* root, LottieLayer* layer, float frameNo)
|
|||
}
|
||||
|
||||
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo)
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo, bool caching)
|
||||
{
|
||||
layer->scene = nullptr;
|
||||
|
||||
//visibility
|
||||
if (frameNo < layer->inFrame || frameNo >= layer->outFrame) return;
|
||||
|
||||
//static layer, no need to update it again. use a cache.
|
||||
if (layer->cache.scene) {
|
||||
//TODO: remove duplicate, share the scene.
|
||||
root->scene->push(cast(layer->cache.scene->duplicate()));
|
||||
return;
|
||||
}
|
||||
|
||||
_updateTransform(layer, frameNo);
|
||||
|
||||
//full transparent scene. no need to perform
|
||||
if (layer->type != LottieLayer::Null && layer->cache.opacity == 0) return;
|
||||
|
||||
//figure out this scene is static, reusable.
|
||||
auto cache = false;
|
||||
if (layer->statical && !layer->cache.scene && !caching) {
|
||||
cache = caching = true;
|
||||
}
|
||||
|
||||
//Prepare render data
|
||||
layer->scene = Scene::gen().release();
|
||||
|
||||
|
@ -916,14 +934,14 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo)
|
|||
|
||||
if (layer->matte.target && layer->masks.count > 0) TVGERR("LOTTIE", "FIXME: Matte + Masking??");
|
||||
|
||||
if (!_updateMatte(root, layer, frameNo)) return;
|
||||
if (!_updateMatte(root, layer, frameNo, caching)) return;
|
||||
|
||||
_updateMaskings(layer, frameNo);
|
||||
|
||||
switch (layer->type) {
|
||||
case LottieLayer::Precomp: {
|
||||
if (!layer->children.empty()) {
|
||||
_updatePrecomp(layer, frameNo);
|
||||
_updatePrecomp(layer, frameNo, caching);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -943,6 +961,12 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, float frameNo)
|
|||
|
||||
//the given matte source was composited by the target earlier.
|
||||
if (!layer->matteSrc) root->scene->push(cast(layer->scene));
|
||||
|
||||
//cache this static layer scene
|
||||
if (cache) {
|
||||
//TODO: remove duplicate, share the scene.
|
||||
layer->cache.scene = layer->scene->duplicate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1037,10 +1061,14 @@ static bool _buildComposition(LottieComposition* comp, LottieGroup* parent)
|
|||
_bulidHierarchy(parent, child->matte.target);
|
||||
//precomp referencing
|
||||
if (child->matte.target->refId) _buildReference(comp, child->matte.target);
|
||||
child->statical &= child->matte.target->statical;
|
||||
}
|
||||
_bulidHierarchy(parent, child);
|
||||
|
||||
_checkFragment(static_cast<LottieGroup*>(*c));
|
||||
|
||||
child->statical &= parent->statical;
|
||||
parent->statical &= child->statical;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1069,9 +1097,8 @@ bool LottieBuilder::update(LottieComposition* comp, float frameNo)
|
|||
}
|
||||
|
||||
//update children layers
|
||||
//TODO: skip if the layer is static.
|
||||
for (auto child = root->children.end() - 1; child >= root->children.data; --child) {
|
||||
_updateLayer(root, static_cast<LottieLayer*>(*child), frameNo);
|
||||
_updateLayer(root, static_cast<LottieLayer*>(*child), frameNo, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -145,6 +145,7 @@ void LottieGroup::prepare(LottieObject::Type type)
|
|||
void LottieLayer::prepare()
|
||||
{
|
||||
if (transform) statical &= transform->statical;
|
||||
if (timeRemap.frames) statical = false;
|
||||
|
||||
/* if layer is hidden, only useful data is its transform matrix.
|
||||
so force it to be a Null Layer and release all resource. */
|
||||
|
|
|
@ -173,7 +173,7 @@ struct LottieGradient
|
|||
} else {
|
||||
colorStops.count = populate(colorStops.value);
|
||||
}
|
||||
if (start.frames || end.frames || height.frames || angle.frames || colorStops.frames) return true;
|
||||
if (start.frames || end.frames || height.frames || angle.frames || opacity.frames || colorStops.frames) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -475,7 +475,6 @@ struct LottieGroup : LottieObject
|
|||
void prepare(LottieObject::Type type = LottieObject::Group);
|
||||
|
||||
Scene* scene = nullptr; //tvg render data
|
||||
|
||||
Array<LottieObject*> children;
|
||||
|
||||
bool reqFragment = false; //requirment to fragment the render context
|
||||
|
@ -500,6 +499,7 @@ struct LottieLayer : LottieGroup
|
|||
|
||||
delete(matte.target);
|
||||
delete(transform);
|
||||
delete(cache.scene);
|
||||
}
|
||||
|
||||
uint8_t opacity(float frameNo)
|
||||
|
@ -539,6 +539,7 @@ struct LottieLayer : LottieGroup
|
|||
float frameNo = -1.0f;
|
||||
Matrix matrix;
|
||||
uint8_t opacity;
|
||||
Paint* scene = nullptr; //tvg statc render ddata
|
||||
} cache;
|
||||
|
||||
Type type = Null;
|
||||
|
|
|
@ -971,7 +971,9 @@ void LottieParser::parseMasks(LottieLayer* layer)
|
|||
{
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
layer->masks.push(parseMask());
|
||||
auto mask = parseMask();
|
||||
if (mask->dynamic()) layer->statical = false;
|
||||
layer->masks.push(mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1053,13 +1055,11 @@ LottieLayer* LottieParser::parseLayers()
|
|||
auto matte = static_cast<LottieLayer*>(root->children.last());
|
||||
if (matte->matteSrc) {
|
||||
layer->matte.target = matte;
|
||||
layer->statical &= layer->matte.target->statical;
|
||||
} else {
|
||||
TVGLOG("LOTTIE", "Matte Source(%s) is not designated?", matte->name);
|
||||
}
|
||||
root->children.last() = layer;
|
||||
}
|
||||
root->statical &= layer->statical;
|
||||
}
|
||||
}
|
||||
root->prepare();
|
||||
|
|
Loading…
Add table
Reference in a new issue