Skip non-AA intersect rects in GrReducedClip
Skips non-AA rects whose op is intersect or replace, and who do not
precede elements that grow the clip, by tightening fIBounds.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2271493002
Review-Url: https://codereview.chromium.org/2271493002
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 251155b..237ea22 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -11,322 +11,13 @@
typedef SkClipStack::Element Element;
-static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack,
- const SkRect& queryBounds,
- const SkIRect& clipIBounds,
- GrReducedClip::ElementList* result,
- int32_t* resultGenID,
- bool* requiresAA) {
-
- // walk backwards until we get to:
- // a) the beginning
- // b) an operation that is known to make the bounds all inside/outside
- // c) a replace operation
-
- enum class InitialTriState {
- kUnknown = -1,
- kAllIn = (int)GrReducedClip::InitialState::kAllIn,
- kAllOut = (int)GrReducedClip::InitialState::kAllOut
- } initialState = InitialTriState::kUnknown;
-
- // During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
- // TODO: track these per saved clip so that we can consider them on the forward pass.
- bool embiggens = false;
- bool emsmallens = false;
-
- // We use a slightly relaxed set of query bounds for element containment tests. This is to
- // account for floating point rounding error that may have occurred during coord transforms.
- SkRect relaxedQueryBounds = queryBounds.makeInset(GrClip::kBoundsTolerance,
- GrClip::kBoundsTolerance);
-
- SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
- int numAAElements = 0;
- while (InitialTriState::kUnknown == initialState) {
- const Element* element = iter.prev();
- if (nullptr == element) {
- initialState = InitialTriState::kAllIn;
- break;
- }
- if (SkClipStack::kEmptyGenID == element->getGenID()) {
- initialState = InitialTriState::kAllOut;
- break;
- }
- if (SkClipStack::kWideOpenGenID == element->getGenID()) {
- initialState = InitialTriState::kAllIn;
- break;
- }
-
- bool skippable = false;
- bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
-
- switch (element->getOp()) {
- case SkRegion::kDifference_Op:
- // check if the shape subtracted either contains the entire bounds (and makes
- // the clip empty) or is outside the bounds and therefore can be skipped.
- if (element->isInverseFilled()) {
- if (element->contains(relaxedQueryBounds)) {
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- }
- } else {
- if (element->contains(relaxedQueryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- skippable = true;
- }
- }
- if (!skippable) {
- emsmallens = true;
- }
- break;
- case SkRegion::kIntersect_Op:
- // check if the shape intersected contains the entire bounds and therefore can
- // be skipped or it is outside the entire bounds and therefore makes the clip
- // empty.
- if (element->isInverseFilled()) {
- if (element->contains(relaxedQueryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- skippable = true;
- }
- } else {
- if (element->contains(relaxedQueryBounds)) {
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- }
- }
- if (!skippable) {
- emsmallens = true;
- }
- break;
- case SkRegion::kUnion_Op:
- // If the union-ed shape contains the entire bounds then after this element
- // the bounds is entirely inside the clip. If the union-ed shape is outside the
- // bounds then this op can be skipped.
- if (element->isInverseFilled()) {
- if (element->contains(relaxedQueryBounds)) {
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = InitialTriState::kAllIn;
- skippable = true;
- }
- } else {
- if (element->contains(relaxedQueryBounds)) {
- initialState = InitialTriState::kAllIn;
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- skippable = true;
- }
- }
- if (!skippable) {
- embiggens = true;
- }
- break;
- case SkRegion::kXOR_Op:
- // If the bounds is entirely inside the shape being xor-ed then the effect is
- // to flip the inside/outside state of every point in the bounds. We may be
- // able to take advantage of this in the forward pass. If the xor-ed shape
- // doesn't intersect the bounds then it can be skipped.
- if (element->isInverseFilled()) {
- if (element->contains(relaxedQueryBounds)) {
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- isFlip = true;
- }
- } else {
- if (element->contains(relaxedQueryBounds)) {
- isFlip = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- skippable = true;
- }
- }
- if (!skippable) {
- emsmallens = embiggens = true;
- }
- break;
- case SkRegion::kReverseDifference_Op:
- // When the bounds is entirely within the rev-diff shape then this behaves like xor
- // and reverses every point inside the bounds. If the shape is completely outside
- // the bounds then we know after this element is applied that the bounds will be
- // all outside the current clip.B
- if (element->isInverseFilled()) {
- if (element->contains(relaxedQueryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- isFlip = true;
- }
- } else {
- if (element->contains(relaxedQueryBounds)) {
- isFlip = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- }
- }
- if (!skippable) {
- emsmallens = embiggens = true;
- }
- break;
-
- case SkRegion::kReplace_Op:
- // Replace will always terminate our walk. We will either begin the forward walk
- // at the replace op or detect here than the shape is either completely inside
- // or completely outside the bounds. In this latter case it can be skipped by
- // setting the correct value for initialState.
- if (element->isInverseFilled()) {
- if (element->contains(relaxedQueryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = InitialTriState::kAllIn;
- skippable = true;
- }
- } else {
- if (element->contains(relaxedQueryBounds)) {
- initialState = InitialTriState::kAllIn;
- skippable = true;
- } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
- initialState = InitialTriState::kAllOut;
- skippable = true;
- }
- }
- if (!skippable) {
- initialState = InitialTriState::kAllOut;
- embiggens = emsmallens = true;
- }
- break;
- default:
- SkDEBUGFAIL("Unexpected op.");
- break;
- }
- if (!skippable) {
- if (0 == result->count()) {
- // This will be the last element. Record the stricter genID.
- *resultGenID = element->getGenID();
- }
-
- // if it is a flip, change it to a bounds-filling rect
- if (isFlip) {
- SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
- SkRegion::kReverseDifference_Op == element->getOp());
- result->addToHead(SkRect::Make(clipIBounds), SkRegion::kReverseDifference_Op,
- false);
- } else {
- Element* newElement = result->addToHead(*element);
- if (newElement->isAA()) {
- ++numAAElements;
- }
- // Intersecting an inverse shape is the same as differencing the non-inverse shape.
- // Replacing with an inverse shape is the same as setting initialState=kAllIn and
- // differencing the non-inverse shape.
- bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
- if (newElement->isInverseFilled() &&
- (SkRegion::kIntersect_Op == newElement->getOp() || isReplace)) {
- newElement->invertShapeFillType();
- newElement->setOp(SkRegion::kDifference_Op);
- if (isReplace) {
- SkASSERT(InitialTriState::kAllOut == initialState);
- initialState = InitialTriState::kAllIn;
- }
- }
- }
- }
- }
-
- if ((InitialTriState::kAllOut == initialState && !embiggens) ||
- (InitialTriState::kAllIn == initialState && !emsmallens)) {
- result->reset();
- numAAElements = 0;
- } else {
- Element* element = result->headIter().get();
- while (element) {
- bool skippable = false;
- switch (element->getOp()) {
- case SkRegion::kDifference_Op:
- // subtracting from the empty set yields the empty set.
- skippable = InitialTriState::kAllOut == initialState;
- break;
- case SkRegion::kIntersect_Op:
- // intersecting with the empty set yields the empty set
- if (InitialTriState::kAllOut == initialState) {
- skippable = true;
- } else {
- // We can clear to zero and then simply draw the clip element.
- initialState = InitialTriState::kAllOut;
- element->setOp(SkRegion::kReplace_Op);
- }
- break;
- case SkRegion::kUnion_Op:
- if (InitialTriState::kAllIn == initialState) {
- // unioning the infinite plane with anything is a no-op.
- skippable = true;
- } else {
- // unioning the empty set with a shape is the shape.
- element->setOp(SkRegion::kReplace_Op);
- }
- break;
- case SkRegion::kXOR_Op:
- if (InitialTriState::kAllOut == initialState) {
- // xor could be changed to diff in the kAllIn case, not sure it's a win.
- element->setOp(SkRegion::kReplace_Op);
- }
- break;
- case SkRegion::kReverseDifference_Op:
- if (InitialTriState::kAllIn == initialState) {
- // subtracting the whole plane will yield the empty set.
- skippable = true;
- initialState = InitialTriState::kAllOut;
- } else {
- // this picks up flips inserted in the backwards pass.
- skippable = element->isInverseFilled() ?
- GrClip::IsOutsideClip(element->getBounds(), queryBounds) :
- element->contains(relaxedQueryBounds);
- if (skippable) {
- initialState = InitialTriState::kAllIn;
- } else {
- element->setOp(SkRegion::kReplace_Op);
- }
- }
- break;
- case SkRegion::kReplace_Op:
- skippable = false; // we would have skipped it in the backwards walk if we
- // could've.
- break;
- default:
- SkDEBUGFAIL("Unexpected op.");
- break;
- }
- if (!skippable) {
- break;
- } else {
- if (element->isAA()) {
- --numAAElements;
- }
- result->popHead();
- element = result->headIter().get();
- }
- }
- }
- *requiresAA = numAAElements > 0;
-
- SkASSERT(InitialTriState::kUnknown != initialState);
- return static_cast<GrReducedClip::InitialState>(initialState);
-}
-
-/*
-There are plenty of optimizations that could be added here. Maybe flips could be folded into
-earlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps
-for the case where the bounds are kInsideOut_BoundsType. We could restrict earlier operations
-based on later intersect operations, and perhaps remove intersect-rects. We could optionally
-take a rect in case the caller knows a bound on what is to be drawn through this clip.
-*/
+/**
+ * There are plenty of optimizations that could be added here. Maybe flips could be folded into
+ * earlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps
+ * for the case where the bounds are kInsideOut_BoundsType. We could restrict earlier operations
+ * based on later intersect operations, and perhaps remove intersect-rects. We could optionally
+ * take a rect in case the caller knows a bound on what is to be drawn through this clip.
+ */
GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds) {
SkASSERT(!queryBounds.isEmpty());
fHasIBounds = false;
@@ -393,6 +84,340 @@
// Now that we have determined the bounds to use and filtered out the trivial cases, call the
// helper that actually walks the stack.
- fInitialState = reduced_stack_walker(stack, tighterQuery, fIBounds, &fElements, &fElementsGenID,
- &fRequiresAA);
+ this->walkStack(stack, tighterQuery);
+}
+
+void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBounds) {
+ // walk backwards until we get to:
+ // a) the beginning
+ // b) an operation that is known to make the bounds all inside/outside
+ // c) a replace operation
+
+ enum class InitialTriState {
+ kUnknown = -1,
+ kAllIn = (int)GrReducedClip::InitialState::kAllIn,
+ kAllOut = (int)GrReducedClip::InitialState::kAllOut
+ } initialTriState = InitialTriState::kUnknown;
+
+ // During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
+ // TODO: track these per saved clip so that we can consider them on the forward pass.
+ bool embiggens = false;
+ bool emsmallens = false;
+
+ // We use a slightly relaxed set of query bounds for element containment tests. This is to
+ // account for floating point rounding error that may have occurred during coord transforms.
+ SkRect relaxedQueryBounds = queryBounds.makeInset(GrClip::kBoundsTolerance,
+ GrClip::kBoundsTolerance);
+
+ SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
+ int numAAElements = 0;
+ while (InitialTriState::kUnknown == initialTriState) {
+ const Element* element = iter.prev();
+ if (nullptr == element) {
+ initialTriState = InitialTriState::kAllIn;
+ break;
+ }
+ if (SkClipStack::kEmptyGenID == element->getGenID()) {
+ initialTriState = InitialTriState::kAllOut;
+ break;
+ }
+ if (SkClipStack::kWideOpenGenID == element->getGenID()) {
+ initialTriState = InitialTriState::kAllIn;
+ break;
+ }
+
+ bool skippable = false;
+ bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
+
+ switch (element->getOp()) {
+ case SkRegion::kDifference_Op:
+ // check if the shape subtracted either contains the entire bounds (and makes
+ // the clip empty) or is outside the bounds and therefore can be skipped.
+ if (element->isInverseFilled()) {
+ if (element->contains(relaxedQueryBounds)) {
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ }
+ } else {
+ if (element->contains(relaxedQueryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ skippable = true;
+ }
+ }
+ if (!skippable) {
+ emsmallens = true;
+ }
+ break;
+ case SkRegion::kIntersect_Op:
+ // check if the shape intersected contains the entire bounds and therefore can
+ // be skipped or it is outside the entire bounds and therefore makes the clip
+ // empty.
+ if (element->isInverseFilled()) {
+ if (element->contains(relaxedQueryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ skippable = true;
+ }
+ } else {
+ if (element->contains(relaxedQueryBounds)) {
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ } else if (!embiggens && !element->isAA() &&
+ Element::kRect_Type == element->getType()) {
+ // fIBounds and queryBounds have already acccounted for this element via
+ // clip stack bounds; here we just apply the non-aa rounding effect.
+ SkIRect nonaaRect;
+ element->getRect().round(&nonaaRect);
+ if (!this->intersectIBounds(nonaaRect)) {
+ return;
+ }
+ skippable = true;
+ }
+ }
+ if (!skippable) {
+ emsmallens = true;
+ }
+ break;
+ case SkRegion::kUnion_Op:
+ // If the union-ed shape contains the entire bounds then after this element
+ // the bounds is entirely inside the clip. If the union-ed shape is outside the
+ // bounds then this op can be skipped.
+ if (element->isInverseFilled()) {
+ if (element->contains(relaxedQueryBounds)) {
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ initialTriState = InitialTriState::kAllIn;
+ skippable = true;
+ }
+ } else {
+ if (element->contains(relaxedQueryBounds)) {
+ initialTriState = InitialTriState::kAllIn;
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ skippable = true;
+ }
+ }
+ if (!skippable) {
+ embiggens = true;
+ }
+ break;
+ case SkRegion::kXOR_Op:
+ // If the bounds is entirely inside the shape being xor-ed then the effect is
+ // to flip the inside/outside state of every point in the bounds. We may be
+ // able to take advantage of this in the forward pass. If the xor-ed shape
+ // doesn't intersect the bounds then it can be skipped.
+ if (element->isInverseFilled()) {
+ if (element->contains(relaxedQueryBounds)) {
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ isFlip = true;
+ }
+ } else {
+ if (element->contains(relaxedQueryBounds)) {
+ isFlip = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ skippable = true;
+ }
+ }
+ if (!skippable) {
+ emsmallens = embiggens = true;
+ }
+ break;
+ case SkRegion::kReverseDifference_Op:
+ // When the bounds is entirely within the rev-diff shape then this behaves like xor
+ // and reverses every point inside the bounds. If the shape is completely outside
+ // the bounds then we know after this element is applied that the bounds will be
+ // all outside the current clip.B
+ if (element->isInverseFilled()) {
+ if (element->contains(relaxedQueryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ isFlip = true;
+ }
+ } else {
+ if (element->contains(relaxedQueryBounds)) {
+ isFlip = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ }
+ }
+ if (!skippable) {
+ emsmallens = embiggens = true;
+ }
+ break;
+
+ case SkRegion::kReplace_Op:
+ // Replace will always terminate our walk. We will either begin the forward walk
+ // at the replace op or detect here than the shape is either completely inside
+ // or completely outside the bounds. In this latter case it can be skipped by
+ // setting the correct value for initialTriState.
+ if (element->isInverseFilled()) {
+ if (element->contains(relaxedQueryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ initialTriState = InitialTriState::kAllIn;
+ skippable = true;
+ }
+ } else {
+ if (element->contains(relaxedQueryBounds)) {
+ initialTriState = InitialTriState::kAllIn;
+ skippable = true;
+ } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
+ initialTriState = InitialTriState::kAllOut;
+ skippable = true;
+ } else if (!embiggens && !element->isAA() &&
+ Element::kRect_Type == element->getType()) {
+ // fIBounds and queryBounds have already acccounted for this element via
+ // clip stack bounds; here we just apply the non-aa rounding effect.
+ SkIRect nonaaRect;
+ element->getRect().round(&nonaaRect);
+ if (!this->intersectIBounds(nonaaRect)) {
+ return;
+ }
+ initialTriState = InitialTriState::kAllIn;
+ skippable = true;
+ }
+ }
+ if (!skippable) {
+ initialTriState = InitialTriState::kAllOut;
+ embiggens = emsmallens = true;
+ }
+ break;
+ default:
+ SkDEBUGFAIL("Unexpected op.");
+ break;
+ }
+ if (!skippable) {
+ if (0 == fElements.count()) {
+ // This will be the last element. Record the stricter genID.
+ fElementsGenID = element->getGenID();
+ }
+
+ // if it is a flip, change it to a bounds-filling rect
+ if (isFlip) {
+ SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
+ SkRegion::kReverseDifference_Op == element->getOp());
+ fElements.addToHead(SkRect::Make(fIBounds), SkRegion::kReverseDifference_Op, false);
+ } else {
+ Element* newElement = fElements.addToHead(*element);
+ if (newElement->isAA()) {
+ ++numAAElements;
+ }
+ // Intersecting an inverse shape is the same as differencing the non-inverse shape.
+ // Replacing with an inverse shape is the same as setting initialState=kAllIn and
+ // differencing the non-inverse shape.
+ bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
+ if (newElement->isInverseFilled() &&
+ (SkRegion::kIntersect_Op == newElement->getOp() || isReplace)) {
+ newElement->invertShapeFillType();
+ newElement->setOp(SkRegion::kDifference_Op);
+ if (isReplace) {
+ SkASSERT(InitialTriState::kAllOut == initialTriState);
+ initialTriState = InitialTriState::kAllIn;
+ }
+ }
+ }
+ }
+ }
+
+ if ((InitialTriState::kAllOut == initialTriState && !embiggens) ||
+ (InitialTriState::kAllIn == initialTriState && !emsmallens)) {
+ fElements.reset();
+ numAAElements = 0;
+ } else {
+ Element* element = fElements.headIter().get();
+ while (element) {
+ bool skippable = false;
+ switch (element->getOp()) {
+ case SkRegion::kDifference_Op:
+ // subtracting from the empty set yields the empty set.
+ skippable = InitialTriState::kAllOut == initialTriState;
+ break;
+ case SkRegion::kIntersect_Op:
+ // intersecting with the empty set yields the empty set
+ if (InitialTriState::kAllOut == initialTriState) {
+ skippable = true;
+ } else {
+ // We can clear to zero and then simply draw the clip element.
+ initialTriState = InitialTriState::kAllOut;
+ element->setOp(SkRegion::kReplace_Op);
+ }
+ break;
+ case SkRegion::kUnion_Op:
+ if (InitialTriState::kAllIn == initialTriState) {
+ // unioning the infinite plane with anything is a no-op.
+ skippable = true;
+ } else {
+ // unioning the empty set with a shape is the shape.
+ element->setOp(SkRegion::kReplace_Op);
+ }
+ break;
+ case SkRegion::kXOR_Op:
+ if (InitialTriState::kAllOut == initialTriState) {
+ // xor could be changed to diff in the kAllIn case, not sure it's a win.
+ element->setOp(SkRegion::kReplace_Op);
+ }
+ break;
+ case SkRegion::kReverseDifference_Op:
+ if (InitialTriState::kAllIn == initialTriState) {
+ // subtracting the whole plane will yield the empty set.
+ skippable = true;
+ initialTriState = InitialTriState::kAllOut;
+ } else {
+ // this picks up flips inserted in the backwards pass.
+ skippable = element->isInverseFilled() ?
+ GrClip::IsOutsideClip(element->getBounds(), queryBounds) :
+ element->contains(relaxedQueryBounds);
+ if (skippable) {
+ initialTriState = InitialTriState::kAllIn;
+ } else {
+ element->setOp(SkRegion::kReplace_Op);
+ }
+ }
+ break;
+ case SkRegion::kReplace_Op:
+ skippable = false; // we would have skipped it in the backwards walk if we
+ // could've.
+ break;
+ default:
+ SkDEBUGFAIL("Unexpected op.");
+ break;
+ }
+ if (!skippable) {
+ break;
+ } else {
+ if (element->isAA()) {
+ --numAAElements;
+ }
+ fElements.popHead();
+ element = fElements.headIter().get();
+ }
+ }
+ }
+ fRequiresAA = numAAElements > 0;
+
+ SkASSERT(InitialTriState::kUnknown != initialTriState);
+ fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState);
+}
+
+inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) {
+ SkASSERT(fHasIBounds);
+ if (!fIBounds.intersect(irect)) {
+ fHasIBounds = false;
+ fElements.reset();
+ fRequiresAA = false;
+ fInitialState = InitialState::kAllOut;
+ return false;
+ }
+ return true;
}