renderer: optimize the ClipPath fast-track.

this optimization applies when the clipper is
not an axis-aligned rectangle under the following conditions:

a. Coverage where the clipper is a regional superset of the viewport.
b. Coverage where the clipper is completely outside of the viewport.

issue: https://github.com/thorvg/thorvg/issues/2332
This commit is contained in:
Hermet Park 2024-06-07 10:40:25 +09:00 committed by Hermet Park
parent fc754f3f6b
commit 7b5de2fdb3

View file

@ -41,8 +41,39 @@
} }
static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before)
{
//sorting
Point tmp[4];
Point min = {FLT_MAX, FLT_MAX};
Point max = {0.0f, 0.0f};
static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) for (int i = 0; i < 4; ++i) {
tmp[i] = pts[i];
if (rTransform) tmp[i] *= rTransform->m;
if (pTransform) tmp[i] *= pTransform->m;
if (tmp[i].x < min.x) min.x = tmp[i].x;
if (tmp[i].x > max.x) max.x = tmp[i].x;
if (tmp[i].y < min.y) min.y = tmp[i].y;
if (tmp[i].y > max.y) max.y = tmp[i].y;
}
float region[4] = {float(before.x), float(before.x + before.w), float(before.y), float(before.y + before.h)};
//figure out if the clipper is a superset of the current viewport(before) region
if (min.x <= region[0] && max.x >= region[1] && min.y <= region[2] && max.y >= region[3]) {
//viewport region is same, nothing to do.
return Result::Success;
//figure out if the clipper is totally outside of the viewport
} else if (max.x <= region[0] || min.x >= region[1] || max.y <= region[2] || min.y >= region[3]) {
renderer->viewport({0, 0, 0, 0});
return Result::Success;
}
return Result::InsufficientCondition;
}
static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before)
{ {
/* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */
auto shape = static_cast<Shape*>(cmpTarget); auto shape = static_cast<Shape*>(cmpTarget);
@ -58,9 +89,13 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
if (rTransform) rTransform->update(); if (rTransform) rTransform->update();
//No rotation and no skewing //No rotation and no skewing, still can try out clipping the rect region.
if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return Result::InsufficientCondition; auto tryClip = false;
if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return Result::InsufficientCondition;
if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) tryClip = true;
if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) tryClip = true;
if (tryClip) return _clipRect(renderer, pts, pTransform, rTransform, before);
//Perpendicular Rectangle? //Perpendicular Rectangle?
auto pt1 = pts + 0; auto pt1 = pts + 0;
@ -71,6 +106,8 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
if ((mathEqual(pt1->x, pt2->x) && mathEqual(pt2->y, pt3->y) && mathEqual(pt3->x, pt4->x) && mathEqual(pt1->y, pt4->y)) || if ((mathEqual(pt1->x, pt2->x) && mathEqual(pt2->y, pt3->y) && mathEqual(pt3->x, pt4->x) && mathEqual(pt1->y, pt4->y)) ||
(mathEqual(pt2->x, pt3->x) && mathEqual(pt1->y, pt2->y) && mathEqual(pt1->x, pt4->x) && mathEqual(pt3->y, pt4->y))) { (mathEqual(pt2->x, pt3->x) && mathEqual(pt1->y, pt2->y) && mathEqual(pt1->x, pt4->x) && mathEqual(pt3->y, pt4->y))) {
RenderRegion after;
auto v1 = *pt1; auto v1 = *pt1;
auto v2 = *pt3; auto v2 = *pt3;
@ -88,13 +125,16 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
if (v1.x > v2.x) std::swap(v1.x, v2.x); if (v1.x > v2.x) std::swap(v1.x, v2.x);
if (v1.y > v2.y) std::swap(v1.y, v2.y); if (v1.y > v2.y) std::swap(v1.y, v2.y);
viewport.x = static_cast<int32_t>(v1.x); after.x = static_cast<int32_t>(v1.x);
viewport.y = static_cast<int32_t>(v1.y); after.y = static_cast<int32_t>(v1.y);
viewport.w = static_cast<int32_t>(ceil(v2.x - viewport.x)); after.w = static_cast<int32_t>(ceil(v2.x - after.x));
viewport.h = static_cast<int32_t>(ceil(v2.y - viewport.y)); after.h = static_cast<int32_t>(ceil(v2.y - after.y));
if (viewport.w < 0) viewport.w = 0; if (after.w < 0) after.w = 0;
if (viewport.h < 0) viewport.h = 0; if (after.h < 0) after.h = 0;
after.intersect(before);
renderer->viewport(after);
return Result::Success; return Result::Success;
} }
@ -255,11 +295,8 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
} }
} }
if (tryFastTrack) { if (tryFastTrack) {
RenderRegion viewport2; viewport = renderer->viewport();
if ((compFastTrack = _compFastTrack(target, pTransform, target->pImpl->rTransform, viewport2)) == Result::Success) { if ((compFastTrack = _compFastTrack(renderer, target, pTransform, target->pImpl->rTransform, viewport)) == Result::Success) {
viewport = renderer->viewport();
viewport2.intersect(viewport);
renderer->viewport(viewport2);
target->pImpl->ctxFlag |= ContextFlag::FastTrack; target->pImpl->ctxFlag |= ContextFlag::FastTrack;
} }
} }