From f3d7e232cea46a8ac8b4b58dd44eb4fa8ea33857 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 26 Jun 2025 13:12:41 +0900 Subject: [PATCH] common: partial rendering stabilization++ There are more corner case issues after the partial rendering introduction, this covers all-in-one. --- src/renderer/gl_engine/tvgGlRenderer.cpp | 2 +- src/renderer/gl_engine/tvgGlRenderer.h | 2 +- src/renderer/sw_engine/tvgSwRenderer.cpp | 14 ++++--- src/renderer/sw_engine/tvgSwRenderer.h | 2 +- src/renderer/tvgPaint.h | 7 +++- src/renderer/tvgRender.cpp | 48 +++++++++++++++++------- src/renderer/tvgRender.h | 5 ++- src/renderer/tvgScene.h | 13 +++++++ src/renderer/wg_engine/tvgWgRenderer.cpp | 2 +- src/renderer/wg_engine/tvgWgRenderer.h | 2 +- 10 files changed, 69 insertions(+), 28 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index a8879c4b..72601efe 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -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 } diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index 794d130f..237fe0a8 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -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); diff --git a/src/renderer/sw_engine/tvgSwRenderer.cpp b/src/renderer/sw_engine/tvgSwRenderer.cpp index 28daace6..b6297a24 100644 --- a/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -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(*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(rd); + if (task && task->opacity == 0) return; + dirtyRegion.add(region); } diff --git a/src/renderer/sw_engine/tvgSwRenderer.h b/src/renderer/sw_engine/tvgSwRenderer.h index f3ecefb2..23a36d50 100644 --- a/src/renderer/sw_engine/tvgSwRenderer.h +++ b/src/renderer/sw_engine/tvgSwRenderer.h @@ -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); diff --git a/src/renderer/tvgPaint.h b/src/renderer/tvgPaint.h index 327eae4d..e79d39ad 100644 --- a/src/renderer/tvgPaint.h +++ b/src/renderer/tvgPaint.h @@ -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) diff --git a/src/renderer/tvgRender.cpp b/src/renderer/tvgRender.cpp index 5b77a7d7..221d0000 100644 --- a/src/renderer/tvgRender.cpp +++ b/src/renderer/tvgRender.cpp @@ -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& 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; diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index bf9c0b6e..5f28bd9a 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -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; }; diff --git a/src/renderer/tvgScene.h b/src/renderer/tvgScene.h index 5c5c67c9..41c529c2 100644 --- a/src/renderer/tvgScene.h +++ b/src/renderer/tvgScene.h @@ -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; diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index a96a7f92..fa78d43c 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -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 } diff --git a/src/renderer/wg_engine/tvgWgRenderer.h b/src/renderer/wg_engine/tvgWgRenderer.h index 609d22b0..4ead7075 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.h +++ b/src/renderer/wg_engine/tvgWgRenderer.h @@ -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);