Clipping performance improvements
Create a ClipArea class to handle tracking clip regions. This class can
select the most efficient implementation depending on the types of
clipping presented.
ClipArea re-used the rectangle and region-based clipping
implementations as well as adding a "list of rotated rectangles"
approach that is more efficient for rotated views with children.
Change-Id: I2133761a2462ebc0852b394220e265974b3086f0
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index d4ca99e..49fb4ba 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -35,11 +35,10 @@
, invisible(false)
, empty(false)
, alpha(1.0f)
- , roundRectClipState(nullptr) {
+ , roundRectClipState(nullptr)
+ , mClipArea(&mClipAreaRoot) {
transform = &mTransformRoot;
- clipRect = &mClipRectRoot;
region = nullptr;
- clipRegion = &mClipRegionRoot;
}
/**
@@ -55,6 +54,7 @@
, empty(false)
, alpha(s->alpha)
, roundRectClipState(s->roundRectClipState)
+ , mClipArea(nullptr)
, mViewportData(s->mViewportData)
, mRelativeLightCenter(s->mRelativeLightCenter) {
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
@@ -65,15 +65,10 @@
}
if (saveFlags & SkCanvas::kClip_SaveFlag) {
- mClipRectRoot.set(*s->clipRect);
- clipRect = &mClipRectRoot;
- if (!s->clipRegion->isEmpty()) {
- mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op);
- }
- clipRegion = &mClipRegionRoot;
+ mClipAreaRoot = s->getClipArea();
+ mClipArea = &mClipAreaRoot;
} else {
- clipRect = s->clipRect;
- clipRegion = s->clipRegion;
+ mClipArea = s->mClipArea;
}
if (s->flags & Snapshot::kFlagFboTarget) {
@@ -88,88 +83,23 @@
// Clipping
///////////////////////////////////////////////////////////////////////////////
-void Snapshot::ensureClipRegion() {
- if (clipRegion->isEmpty()) {
- clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
- }
-}
-
-void Snapshot::copyClipRectFromRegion() {
- if (!clipRegion->isEmpty()) {
- const SkIRect& bounds = clipRegion->getBounds();
- clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
-
- if (clipRegion->isRect()) {
- clipRegion->setEmpty();
- }
- } else {
- clipRect->setEmpty();
- }
-}
-
-bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) {
- SkIRect tmp;
- tmp.set(left, top, right, bottom);
- clipRegion->op(tmp, op);
- copyClipRectFromRegion();
- return true;
-}
-
bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
- ensureClipRegion();
- clipRegion->op(region, op);
- copyClipRectFromRegion();
flags |= Snapshot::kFlagClipSet;
- return true;
+ return mClipArea->clipRegion(region, op);
}
bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
- Rect r(left, top, right, bottom);
- transform->mapRect(r);
- return clipTransformed(r, op);
+ flags |= Snapshot::kFlagClipSet;
+ return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
}
-bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
- bool clipped = false;
-
- switch (op) {
- case SkRegion::kIntersect_Op: {
- if (CC_UNLIKELY(!clipRegion->isEmpty())) {
- ensureClipRegion();
- clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op);
- } else {
- clipped = clipRect->intersect(r);
- if (!clipped) {
- clipRect->setEmpty();
- clipped = true;
- }
- }
- break;
- }
- case SkRegion::kReplace_Op: {
- setClip(r.left, r.top, r.right, r.bottom);
- clipped = true;
- break;
- }
- default: {
- ensureClipRegion();
- clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op);
- break;
- }
- }
-
- if (clipped) {
- flags |= Snapshot::kFlagClipSet;
- }
-
- return clipped;
+bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
+ flags |= Snapshot::kFlagClipSet;
+ return mClipArea->clipPathWithTransform(path, transform, op);
}
void Snapshot::setClip(float left, float top, float right, float bottom) {
- clipRect->set(left, top, right, bottom);
- if (!clipRegion->isEmpty()) {
- clipRegion->setEmpty();
- }
+ mClipArea->setClip(left, top, right, bottom);
flags |= Snapshot::kFlagClipSet;
}
@@ -181,7 +111,7 @@
mat4 inverse;
inverse.loadInverse(*transform);
- mLocalClip.set(*clipRect);
+ mLocalClip.set(mClipArea->getClipRect());
inverse.mapRect(mLocalClip);
return mLocalClip;
@@ -191,8 +121,7 @@
// TODO: This is incorrect, when we start rendering into a new layer,
// we may have to modify the previous snapshot's clip rect and clip
// region if the previous restore() call did not restore the clip
- clipRect = &mClipRectRoot;
- clipRegion = &mClipRegionRoot;
+ mClipArea = &mClipAreaRoot;
setClip(left, top, right, bottom);
}
@@ -219,7 +148,7 @@
void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
float radius, bool highPriority) {
if (bounds.isEmpty()) {
- clipRect->setEmpty();
+ mClipArea->setEmpty();
return;
}
@@ -272,9 +201,10 @@
void Snapshot::dump() const {
ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
- this, flags, previous.get(), getViewportHeight(), isIgnored(), clipRegion && !clipRegion->isEmpty());
+ this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
+ const Rect& clipRect(mClipArea->getClipRect());
ALOGD(" ClipRect (at %p) %.1f %.1f %.1f %.1f",
- clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+ clipRect, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
ALOGD(" Transform (at %p):", transform);
transform->dump();
}