mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-29 03:11:42 +00:00
common: partial rendering stabilization++
There are more corner case issues after the partial rendering introduction, this covers all-in-one.
This commit is contained in:
parent
4fd6be9363
commit
f3d7e232ce
10 changed files with 69 additions and 28 deletions
|
@ -1481,7 +1481,7 @@ bool GlRenderer::postUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GlRenderer::damage(const RenderRegion& region)
|
void GlRenderer::damage(TVG_UNUSED RenderData rd, TVG_UNUSED const RenderRegion& region)
|
||||||
{
|
{
|
||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ public:
|
||||||
void dispose(RenderEffect* effect) override;
|
void dispose(RenderEffect* effect) override;
|
||||||
|
|
||||||
//partial rendering
|
//partial rendering
|
||||||
void damage(const RenderRegion& region) override;
|
void damage(RenderData rd, const RenderRegion& region) override;
|
||||||
bool partial(bool disable) override;
|
bool partial(bool disable) override;
|
||||||
|
|
||||||
static GlRenderer* gen(uint32_t threads);
|
static GlRenderer* gen(uint32_t threads);
|
||||||
|
|
|
@ -162,7 +162,7 @@ struct SwShapeTask : SwTask
|
||||||
}
|
}
|
||||||
|
|
||||||
curBox = renderBox; //sync
|
curBox = renderBox; //sync
|
||||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -170,7 +170,7 @@ struct SwShapeTask : SwTask
|
||||||
shapeReset(&shape);
|
shapeReset(&shape);
|
||||||
rleReset(shape.strokeRle);
|
rleReset(shape.strokeRle);
|
||||||
shapeDelOutline(&shape, mpool, tid);
|
shapeDelOutline(&shape, mpool, tid);
|
||||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() override
|
void dispose() override
|
||||||
|
@ -221,7 +221,7 @@ struct SwImageTask : SwTask
|
||||||
auto clipper = static_cast<SwTask*>(*p);
|
auto clipper = static_cast<SwTask*>(*p);
|
||||||
if (!clipper->clip(image.rle)) goto err;
|
if (!clipper->clip(image.rle)) goto err;
|
||||||
}
|
}
|
||||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ struct SwImageTask : SwTask
|
||||||
rleReset(image.rle);
|
rleReset(image.rle);
|
||||||
end:
|
end:
|
||||||
imageDelOutline(&image, mpool, tid);
|
imageDelOutline(&image, mpool, tid);
|
||||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() override
|
void dispose() override
|
||||||
|
@ -381,9 +381,11 @@ bool SwRenderer::postRender()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SwRenderer::damage(const RenderRegion& region)
|
void SwRenderer::damage(RenderData rd, const RenderRegion& region)
|
||||||
{
|
{
|
||||||
dirtyRegion.add(®ion, nullptr);
|
SwTask* task = static_cast<SwTask*>(rd);
|
||||||
|
if (task && task->opacity == 0) return;
|
||||||
|
dirtyRegion.add(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
void dispose(RenderEffect* effect) override;
|
void dispose(RenderEffect* effect) override;
|
||||||
|
|
||||||
//partial rendering
|
//partial rendering
|
||||||
void damage(const RenderRegion& region) override;
|
void damage(RenderData rd, const RenderRegion& region) override;
|
||||||
bool partial(bool disable) override;
|
bool partial(bool disable) override;
|
||||||
|
|
||||||
static SwRenderer* gen(uint32_t threads);
|
static SwRenderer* gen(uint32_t threads);
|
||||||
|
|
|
@ -131,7 +131,12 @@ namespace tvg
|
||||||
|
|
||||||
void damage(const RenderRegion& vport)
|
void damage(const RenderRegion& vport)
|
||||||
{
|
{
|
||||||
if (renderer) renderer->damage(vport);
|
if (renderer) renderer->damage(rd, vport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void damage()
|
||||||
|
{
|
||||||
|
if (renderer) renderer->damage(rd, bounds(renderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mark(CompositionFlag flag)
|
void mark(CompositionFlag flag)
|
||||||
|
|
|
@ -158,25 +158,39 @@ void RenderDirtyRegion::init(uint32_t w, uint32_t h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderDirtyRegion::add(const RenderRegion* prv, const RenderRegion* cur)
|
bool RenderDirtyRegion::add(const RenderRegion& bbox)
|
||||||
{
|
{
|
||||||
if (disabled) return;
|
if (disabled) return false;
|
||||||
|
|
||||||
auto pvalid = prv ? prv->valid() : false;
|
|
||||||
auto cvalid = cur ? cur->valid() : false;
|
|
||||||
if (!pvalid && !cvalid) return;
|
|
||||||
|
|
||||||
for (int idx = 0; idx < PARTITIONING; ++idx) {
|
for (int idx = 0; idx < PARTITIONING; ++idx) {
|
||||||
auto& partition = partitions[idx];
|
auto& partition = partitions[idx];
|
||||||
if (pvalid && prv->intersected(partition.region)) {
|
if (bbox.max.y <= partition.region.min.y) break;
|
||||||
|
if (bbox.intersected(partition.region)) {
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(key);
|
||||||
partition.list[partition.current].push(RenderRegion::intersect(*prv, partition.region));
|
partition.list[partition.current].push(RenderRegion::intersect(bbox, partition.region));
|
||||||
}
|
|
||||||
if (cvalid && cur->intersected(partition.region)) {
|
|
||||||
ScopedLock lock(key);
|
|
||||||
partition.list[partition.current].push(RenderRegion::intersect(*cur, partition.region));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RenderDirtyRegion::add(const RenderRegion& prv, const RenderRegion& cur)
|
||||||
|
{
|
||||||
|
if (disabled) return false;
|
||||||
|
if (prv == cur) return add(prv);
|
||||||
|
|
||||||
|
for (int idx = 0; idx < PARTITIONING; ++idx) {
|
||||||
|
auto& partition = partitions[idx];
|
||||||
|
if (prv.intersected(partition.region)) {
|
||||||
|
ScopedLock lock(key);
|
||||||
|
partition.list[partition.current].push(RenderRegion::intersect(prv, partition.region));
|
||||||
|
}
|
||||||
|
if (cur.intersected(partition.region)) {
|
||||||
|
ScopedLock lock(key);
|
||||||
|
partition.list[partition.current].push(RenderRegion::intersect(cur, partition.region));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -222,6 +236,12 @@ void RenderDirtyRegion::subdivide(Array<RenderRegion>& targets, uint32_t idx, Re
|
||||||
subtract(temp[0], lhs);
|
subtract(temp[0], lhs);
|
||||||
subtract(temp[0], rhs);
|
subtract(temp[0], rhs);
|
||||||
|
|
||||||
|
//Please reserve memory enough with targets.reserve()
|
||||||
|
if (targets.count + cnt - 1 > targets.reserved) {
|
||||||
|
TVGERR("RENDERER", "reserved(%d), required(%d)", targets.reserved, targets.count + cnt - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Considered using a list to avoid memory shifting,
|
/* Considered using a list to avoid memory shifting,
|
||||||
but ultimately, the array outperformed the list due to better cache locality. */
|
but ultimately, the array outperformed the list due to better cache locality. */
|
||||||
|
|
||||||
|
@ -246,12 +266,12 @@ void RenderDirtyRegion::commit()
|
||||||
for (int idx = 0; idx < PARTITIONING; ++idx) {
|
for (int idx = 0; idx < PARTITIONING; ++idx) {
|
||||||
auto current = partitions[idx].current;
|
auto current = partitions[idx].current;
|
||||||
auto& targets = partitions[idx].list[current];
|
auto& targets = partitions[idx].list[current];
|
||||||
if (targets.empty()) return;
|
if (targets.empty()) continue;
|
||||||
|
|
||||||
current = !current; //swapping buffers
|
current = !current; //swapping buffers
|
||||||
auto& output = partitions[idx].list[current];
|
auto& output = partitions[idx].list[current];
|
||||||
|
|
||||||
targets.reserve(targets.count * 5); //one intersection can be divided up to 5
|
targets.reserve(targets.count * 10); //one intersection can be divided up to 5
|
||||||
output.reserve(targets.count);
|
output.reserve(targets.count);
|
||||||
|
|
||||||
partitions[idx].current = current;
|
partitions[idx].current = current;
|
||||||
|
|
|
@ -164,7 +164,8 @@ struct RenderRegion
|
||||||
|
|
||||||
void init(uint32_t w, uint32_t h);
|
void init(uint32_t w, uint32_t h);
|
||||||
void commit();
|
void commit();
|
||||||
void add(const RenderRegion* prv, const RenderRegion* cur); //collect the old and new dirty regions together
|
bool add(const RenderRegion& bbox);
|
||||||
|
bool add(const RenderRegion& prv, const RenderRegion& cur); //collect the old and new dirty regions together
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
bool deactivate(bool on)
|
bool deactivate(bool on)
|
||||||
|
@ -541,7 +542,7 @@ public:
|
||||||
virtual void dispose(RenderEffect* effect) = 0;
|
virtual void dispose(RenderEffect* effect) = 0;
|
||||||
|
|
||||||
//partial rendering
|
//partial rendering
|
||||||
virtual void damage(const RenderRegion& region) = 0;
|
virtual void damage(RenderData rd, const RenderRegion& region) = 0;
|
||||||
virtual bool partial(bool disable) = 0;
|
virtual bool partial(bool disable) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -280,19 +280,32 @@ struct SceneImpl : Scene
|
||||||
|
|
||||||
Result clearPaints()
|
Result clearPaints()
|
||||||
{
|
{
|
||||||
|
if (paints.empty()) return Result::Success;
|
||||||
|
|
||||||
|
//Don't need to damage for children
|
||||||
|
auto recover = (fixed && impl.renderer) ? impl.renderer->partial(true) : false;
|
||||||
|
auto partialDmg = !(effects || fixed || recover);
|
||||||
|
|
||||||
auto itr = paints.begin();
|
auto itr = paints.begin();
|
||||||
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
|
||||||
|
if (paint->refCnt > 1 && partialDmg) paint->damage();
|
||||||
paint->unref();
|
paint->unref();
|
||||||
paints.erase(itr++);
|
paints.erase(itr++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (effects || fixed) impl.damage(vport); //redraw scene full region
|
||||||
|
if (fixed && impl.renderer) impl.renderer->partial(recover);
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result remove(Paint* paint)
|
Result remove(Paint* paint)
|
||||||
{
|
{
|
||||||
if (PAINT(paint)->parent != this) return Result::InsufficientCondition;
|
if (PAINT(paint)->parent != this) return Result::InsufficientCondition;
|
||||||
|
//when the paint is destroyed damage will be triggered
|
||||||
|
if (PAINT(paint)->refCnt > 1) PAINT(paint)->damage();
|
||||||
PAINT(paint)->unref();
|
PAINT(paint)->unref();
|
||||||
paints.remove(paint);
|
paints.remove(paint);
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
|
|
|
@ -581,7 +581,7 @@ bool WgRenderer::postUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WgRenderer::damage(const RenderRegion& region)
|
void WgRenderer::damage(TVG_UNUSED RenderData rd, TVG_UNUSED const RenderRegion& region)
|
||||||
{
|
{
|
||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
void dispose(RenderEffect* effect) override;
|
void dispose(RenderEffect* effect) override;
|
||||||
|
|
||||||
//partial rendering
|
//partial rendering
|
||||||
void damage(const RenderRegion& region) override;
|
void damage(RenderData rd, const RenderRegion& region) override;
|
||||||
bool partial(bool disable) override;
|
bool partial(bool disable) override;
|
||||||
|
|
||||||
static WgRenderer* gen(uint32_t threads);
|
static WgRenderer* gen(uint32_t threads);
|
||||||
|
|
Loading…
Add table
Reference in a new issue