diff options
author | reed <reed@google.com> | 2014-09-09 12:19:30 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-09 12:19:30 -0700 |
commit | 27a5e656c3d6ef22f9cb34de18e1b960da3aa241 (patch) | |
tree | b940544e91d9c4646d5e78e151ed6c4f656c61d4 /src/core/SkRasterClip.cpp | |
parent | f5b6bf775c331784964bfcc9b9ac707dc6a7c62b (diff) |
Allow SkCanvas to be initialized to force conservative rasterclips. This has the following effects:
1. Queries to the current clip will be conservatively large. This can mean the quickReject may return false more often.
2. The conservative clips mean less work is done.
3. Enabled by default for Gpu, Record, and NoSaveLayer canvases.
4. API is private for now.
R=robertphillips@google.com, bsalomon@google.com, mtklein@google.com, junov@google.com
Author: reed@google.com
Review URL: https://codereview.chromium.org/541593005
Diffstat (limited to 'src/core/SkRasterClip.cpp')
-rw-r--r-- | src/core/SkRasterClip.cpp | 138 |
1 files changed, 124 insertions, 14 deletions
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp index dab91d8f4c..f820c5a0a4 100644 --- a/src/core/SkRasterClip.cpp +++ b/src/core/SkRasterClip.cpp @@ -6,18 +6,12 @@ */ #include "SkRasterClip.h" - - -SkRasterClip::SkRasterClip() { - fIsBW = true; - fIsEmpty = true; - fIsRect = false; - SkDEBUGCODE(this->validate();) -} +#include "SkPath.h" SkRasterClip::SkRasterClip(const SkRasterClip& src) { AUTO_RASTERCLIP_VALIDATE(src); + fForceConservativeRects = src.fForceConservativeRects; fIsBW = src.fIsBW; if (fIsBW) { fBW = src.fBW; @@ -30,13 +24,22 @@ SkRasterClip::SkRasterClip(const SkRasterClip& src) { SkDEBUGCODE(this->validate();) } -SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) { +SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) { + fForceConservativeRects = forceConservativeRects; fIsBW = true; fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute fIsRect = !fIsEmpty; SkDEBUGCODE(this->validate();) } +SkRasterClip::SkRasterClip(bool forceConservativeRects) { + fForceConservativeRects = forceConservativeRects; + fIsBW = true; + fIsEmpty = true; + fIsRect = false; + SkDEBUGCODE(this->validate();) +} + SkRasterClip::~SkRasterClip() { SkDEBUGCODE(this->validate();) } @@ -70,9 +73,84 @@ bool SkRasterClip::setRect(const SkIRect& rect) { return fIsRect; } +///////////////////////////////////////////////////////////////////////////////////// + +bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) { + SkIRect ir; + r.roundOut(&ir); + + SkRegion::Op op; + if (isInverse) { + op = SkRegion::kDifference_Op; + } else { + op = SkRegion::kIntersect_Op; + } + fBW.setRect(clipR); + fBW.op(ir, op); + return this->updateCacheAndReturnNonEmpty(); +} + +///////////////////////////////////////////////////////////////////////////////////// + +enum MutateResult { + kDoNothing_MutateResult, + kReplaceClippedAgainstGlobalBounds_MutateResult, + kContinue_MutateResult, +}; + +static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) { + if (inverseFilled) { + switch (*op) { + case SkRegion::kIntersect_Op: + case SkRegion::kDifference_Op: + // These ops can only shrink the current clip. So leaving + // the clip unchanged conservatively respects the contract. + return kDoNothing_MutateResult; + case SkRegion::kUnion_Op: + case SkRegion::kReplace_Op: + case SkRegion::kReverseDifference_Op: + case SkRegion::kXOR_Op: { + // These ops can grow the current clip up to the extents of + // the input clip, which is inverse filled, so we just set + // the current clip to the device bounds. + *op = SkRegion::kReplace_Op; + return kReplaceClippedAgainstGlobalBounds_MutateResult; + } + } + } else { + // Not inverse filled + switch (*op) { + case SkRegion::kIntersect_Op: + case SkRegion::kUnion_Op: + case SkRegion::kReplace_Op: + return kContinue_MutateResult; + case SkRegion::kDifference_Op: + // Difference can only shrink the current clip. + // Leaving clip unchanged conservatively fullfills the contract. + return kDoNothing_MutateResult; + case SkRegion::kReverseDifference_Op: + // To reverse, we swap in the bounds with a replace op. + // As with difference, leave it unchanged. + *op = SkRegion::kReplace_Op; + return kContinue_MutateResult; + case SkRegion::kXOR_Op: + // Be conservative, based on (A XOR B) always included in (A union B), + // which is always included in (bounds(A) union bounds(B)) + *op = SkRegion::kUnion_Op; + return kContinue_MutateResult; + } + } + SkFAIL("should not get here"); + return kDoNothing_MutateResult; +} + bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); + if (fForceConservativeRects) { + return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType()); + } + if (this->isBW() && !doAA) { (void)fBW.setPath(path, clip); } else { @@ -90,7 +168,22 @@ bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, // base is used to limit the size (and therefore memory allocation) of the // region that results from scan converting devPath. SkRegion base; - + + if (fForceConservativeRects) { + SkIRect ir; + switch (mutate_conservative_op(&op, path.isInverseFillType())) { + case kDoNothing_MutateResult: + return !this->isEmpty(); + case kReplaceClippedAgainstGlobalBounds_MutateResult: + ir = SkIRect::MakeSize(size); + break; + case kContinue_MutateResult: + path.getBounds().roundOut(&ir); + break; + } + return this->op(ir, op); + } + if (SkRegion::kIntersect_Op == op) { // since we are intersect, we can do better (tighter) with currRgn's // bounds, than just using the device. However, if currRgn is complex, @@ -102,7 +195,7 @@ bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, return this->setPath(path, this->bwRgn(), doAA); } else { base.setRect(this->getBounds()); - SkRasterClip clip; + SkRasterClip clip(fForceConservativeRects); clip.setPath(path, base, doAA); return this->op(clip, op); } @@ -112,7 +205,7 @@ bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, if (SkRegion::kReplace_Op == op) { return this->setPath(path, base, doAA); } else { - SkRasterClip clip; + SkRasterClip clip(fForceConservativeRects); clip.setPath(path, base, doAA); return this->op(clip, op); } @@ -182,9 +275,24 @@ static bool nearly_integral(SkScalar x) { return x - SkScalarFloorToScalar(x) < domain; } -bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) { +bool SkRasterClip::op(const SkRect& r, const SkISize& size, SkRegion::Op op, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); + if (fForceConservativeRects) { + SkIRect ir; + switch (mutate_conservative_op(&op, false)) { + case kDoNothing_MutateResult: + return !this->isEmpty(); + case kReplaceClippedAgainstGlobalBounds_MutateResult: + ir = SkIRect::MakeSize(size); + break; + case kContinue_MutateResult: + r.roundOut(&ir); + break; + } + return this->op(ir, op); + } + if (fIsBW && doAA) { // check that the rect really needs aa, or is it close enought to // integer boundaries that we can just treat it as a BW rect? @@ -251,7 +359,9 @@ const SkRegion& SkRasterClip::forceGetBW() { void SkRasterClip::convertToAA() { AUTO_RASTERCLIP_VALIDATE(*this); - + + SkASSERT(!fForceConservativeRects); + SkASSERT(fIsBW); fAA.setRegion(fBW); fIsBW = false; |