common: support static scene mode (internal)

This adds support for a static scene mode,
allowing a scene to be treated as a static image.

In this mode, partial rendering for the inner
drawable components is skipped. This is especially
useful for scenes designed to be fully updated as a whole,
such as those used in fully dynamic Lottie contents.

issue: https://github.com/thorvg/thorvg/issues/1747
This commit is contained in:
Hermet Park 2025-06-17 01:01:51 +09:00 committed by Hermet Park
parent fc712c9c36
commit 749bc850ec
3 changed files with 43 additions and 9 deletions

View file

@ -23,6 +23,7 @@
#include <algorithm> #include <algorithm>
#include "tvgCommon.h" #include "tvgCommon.h"
#include "tvgMath.h" #include "tvgMath.h"
#include "tvgScene.h"
#include "tvgLottieModel.h" #include "tvgLottieModel.h"
#include "tvgLottieBuilder.h" #include "tvgLottieBuilder.h"
#include "tvgLottieExpressions.h" #include "tvgLottieExpressions.h"
@ -1560,4 +1561,7 @@ void LottieBuilder::build(LottieComposition* comp)
auto clip = Shape::gen(); auto clip = Shape::gen();
clip->appendRect(0, 0, comp->w, comp->h); clip->appendRect(0, 0, comp->w, comp->h);
comp->root->scene->clip(clip); comp->root->scene->clip(clip);
}
//turn off partial rendering for children
SCENE(comp->root->scene)->size({comp->w, comp->h});
}

View file

@ -149,6 +149,11 @@ namespace tvg
if (renderer) renderer->damage(bounds(renderer)); if (renderer) renderer->damage(bounds(renderer));
} }
void damage(const RenderRegion& vport)
{
if (renderer) renderer->damage(vport);
}
void mark(RenderUpdateFlag flag) void mark(RenderUpdateFlag flag)
{ {
renderFlag |= flag; renderFlag |= flag;

View file

@ -66,8 +66,10 @@ struct SceneImpl : Scene
list<Paint*> paints; //children list list<Paint*> paints; //children list
RenderRegion vport = {}; RenderRegion vport = {};
Array<RenderEffect*>* effects = nullptr; Array<RenderEffect*>* effects = nullptr;
uint8_t opacity; //for composition Point fsize; //fixed scene size
bool fixed = false; //true: fixed scene size, false: dynamic size
bool vdirty = false; bool vdirty = false;
uint8_t opacity; //for composition
SceneImpl() : impl(Paint::Impl(this)) SceneImpl() : impl(Paint::Impl(this))
{ {
@ -75,8 +77,14 @@ struct SceneImpl : Scene
~SceneImpl() ~SceneImpl()
{ {
resetEffects();
clearPaints(); clearPaints();
resetEffects();
}
void size(const Point& size)
{
this->fsize = size;
fixed = (size.x > 0 && size.y > 0) ? true : false;
} }
uint8_t needComposition(uint8_t opacity) uint8_t needComposition(uint8_t opacity)
@ -117,22 +125,36 @@ struct SceneImpl : Scene
this->opacity = opacity; this->opacity = opacity;
opacity = 255; opacity = 255;
} }
//allow partial rendering?
auto recover = fixed ? renderer->partial(true) : false;
for (auto paint : paints) { for (auto paint : paints) {
PAINT(paint)->update(renderer, transform, clips, opacity, flag, false); PAINT(paint)->update(renderer, transform, clips, opacity, flag, false);
} }
//recover the condition
renderer->partial(recover);
if (effects) { if (effects) {
ARRAY_FOREACH(p, *effects) { ARRAY_FOREACH(p, *effects) {
renderer->prepare(*p, transform); renderer->prepare(*p, transform);
} }
} }
//this viewport update is more performant than in bounds()? //this viewport update is more performant than in bounds(). No idea.
vport = renderer->viewport(); vport = renderer->viewport();
vdirty = true;
//bounds(renderer) here hinders parallelization. if (fixed) {
if (effects) renderer->damage(vport); auto pt = fsize * transform;
vport.intersect({int32_t(round(transform.e13)), int32_t(round(transform.e23))}, {int32_t(round(pt.x)), int32_t(round(pt.y))});
} else {
vdirty = true;
}
//bounds(renderer) here hinders parallelization
//TODO: we can bring the precise effects region here
if (fixed || effects) impl.damage(vport);
return true; return true;
} }
@ -262,10 +284,13 @@ struct SceneImpl : Scene
while (itr != paints.end()) { while (itr != paints.end()) {
auto paint = PAINT((*itr)); auto paint = PAINT((*itr));
//when the paint is destroyed damage will be triggered //when the paint is destroyed damage will be triggered
if (paint->refCnt > 1) paint->damage(); if (paint->refCnt > 1 && !fixed) paint->damage();
paint->unref(); paint->unref();
paints.erase(itr++); paints.erase(itr++);
} }
if (!effects && fixed) impl.damage(vport);
return Result::Success; return Result::Success;
} }
@ -318,7 +343,7 @@ struct SceneImpl : Scene
} }
delete(effects); delete(effects);
effects = nullptr; effects = nullptr;
impl.renderer->damage(vport); impl.damage(vport);
} }
return Result::Success; return Result::Success;
} }