mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-28 10:52:16 +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
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public:
|
|||
void dispose(RenderEffect* effect) override;
|
||||
|
||||
//partial rendering
|
||||
void damage(const RenderRegion& region) override;
|
||||
void damage(RenderData rd, const RenderRegion& region) override;
|
||||
bool partial(bool disable) override;
|
||||
|
||||
static GlRenderer* gen(uint32_t threads);
|
||||
|
|
|
@ -162,7 +162,7 @@ struct SwShapeTask : SwTask
|
|||
}
|
||||
|
||||
curBox = renderBox; //sync
|
||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
||||
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||
return;
|
||||
|
||||
err:
|
||||
|
@ -170,7 +170,7 @@ struct SwShapeTask : SwTask
|
|||
shapeReset(&shape);
|
||||
rleReset(shape.strokeRle);
|
||||
shapeDelOutline(&shape, mpool, tid);
|
||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
||||
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||
}
|
||||
|
||||
void dispose() override
|
||||
|
@ -221,7 +221,7 @@ struct SwImageTask : SwTask
|
|||
auto clipper = static_cast<SwTask*>(*p);
|
||||
if (!clipper->clip(image.rle)) goto err;
|
||||
}
|
||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
||||
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ struct SwImageTask : SwTask
|
|||
rleReset(image.rle);
|
||||
end:
|
||||
imageDelOutline(&image, mpool, tid);
|
||||
if (!nodirty) dirtyRegion->add(&prvBox, &curBox);
|
||||
if (!nodirty) dirtyRegion->add(prvBox, curBox);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//partial rendering
|
||||
void damage(const RenderRegion& region) override;
|
||||
void damage(RenderData rd, const RenderRegion& region) override;
|
||||
bool partial(bool disable) override;
|
||||
|
||||
static SwRenderer* gen(uint32_t threads);
|
||||
|
|
|
@ -131,7 +131,12 @@ namespace tvg
|
|||
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
auto pvalid = prv ? prv->valid() : false;
|
||||
auto cvalid = cur ? cur->valid() : false;
|
||||
if (!pvalid && !cvalid) return;
|
||||
if (disabled) return false;
|
||||
|
||||
for (int idx = 0; idx < PARTITIONING; ++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);
|
||||
partition.list[partition.current].push(RenderRegion::intersect(*prv, partition.region));
|
||||
}
|
||||
if (cvalid && cur->intersected(partition.region)) {
|
||||
ScopedLock lock(key);
|
||||
partition.list[partition.current].push(RenderRegion::intersect(*cur, partition.region));
|
||||
partition.list[partition.current].push(RenderRegion::intersect(bbox, 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], 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,
|
||||
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) {
|
||||
auto current = partitions[idx].current;
|
||||
auto& targets = partitions[idx].list[current];
|
||||
if (targets.empty()) return;
|
||||
if (targets.empty()) continue;
|
||||
|
||||
current = !current; //swapping buffers
|
||||
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);
|
||||
|
||||
partitions[idx].current = current;
|
||||
|
|
|
@ -164,7 +164,8 @@ struct RenderRegion
|
|||
|
||||
void init(uint32_t w, uint32_t h);
|
||||
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();
|
||||
|
||||
bool deactivate(bool on)
|
||||
|
@ -541,7 +542,7 @@ public:
|
|||
virtual void dispose(RenderEffect* effect) = 0;
|
||||
|
||||
//partial rendering
|
||||
virtual void damage(const RenderRegion& region) = 0;
|
||||
virtual void damage(RenderData rd, const RenderRegion& region) = 0;
|
||||
virtual bool partial(bool disable) = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -280,19 +280,32 @@ struct SceneImpl : Scene
|
|||
|
||||
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();
|
||||
while (itr != paints.end()) {
|
||||
auto paint = PAINT((*itr));
|
||||
//when the paint is destroyed damage will be triggered
|
||||
if (paint->refCnt > 1 && partialDmg) paint->damage();
|
||||
paint->unref();
|
||||
paints.erase(itr++);
|
||||
}
|
||||
|
||||
if (effects || fixed) impl.damage(vport); //redraw scene full region
|
||||
if (fixed && impl.renderer) impl.renderer->partial(recover);
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
Result remove(Paint* paint)
|
||||
{
|
||||
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();
|
||||
paints.remove(paint);
|
||||
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
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
void dispose(RenderEffect* effect) override;
|
||||
|
||||
//partial rendering
|
||||
void damage(const RenderRegion& region) override;
|
||||
void damage(RenderData rd, const RenderRegion& region) override;
|
||||
bool partial(bool disable) override;
|
||||
|
||||
static WgRenderer* gen(uint32_t threads);
|
||||
|
|
Loading…
Add table
Reference in a new issue