Index: src/gpu/GrReducedClip.cpp |
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp |
index 2083af907ecc18a806fecfc0b6cf85ca18d80dc5..3040b463137bce1d137f2149aac7d6013c3f75ab 100644 |
--- a/src/gpu/GrReducedClip.cpp |
+++ b/src/gpu/GrReducedClip.cpp |
@@ -1,4 +1,3 @@ |
- |
/* |
* Copyright 2012 Google Inc. |
* |
@@ -9,151 +8,21 @@ |
#include "GrReducedClip.h" |
typedef SkClipStack::Element Element; |
-//////////////////////////////////////////////////////////////////////////////// |
- |
-namespace GrReducedClip { |
- |
-// helper function |
-void reduced_stack_walker(const SkClipStack& stack, |
- const SkRect& queryBounds, |
- ElementList* result, |
- int32_t* resultGenID, |
- InitialState* initialState, |
- bool* requiresAA); |
- |
-/* |
-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. |
-*/ |
-void ReduceClipStack(const SkClipStack& stack, |
- const SkIRect& queryBounds, |
- ElementList* result, |
- int32_t* resultGenID, |
- InitialState* initialState, |
- SkIRect* tighterBounds, |
- bool* requiresAA) { |
- result->reset(); |
- |
- // The clip established by the element list might be cached based on the last |
- // generation id. When we make early returns, we do not know what was the generation |
- // id that lead to the state. Make a conservative guess. |
- *resultGenID = stack.getTopmostGenID(); |
- |
- if (stack.isWideOpen()) { |
- *initialState = kAllIn_InitialState; |
- return; |
- } |
- |
- |
- // We initially look at whether the bounds alone is sufficient. We also use the stack bounds to |
- // attempt to compute the tighterBounds. |
- |
- SkClipStack::BoundsType stackBoundsType; |
- SkRect stackBounds; |
- bool iior; |
- stack.getBounds(&stackBounds, &stackBoundsType, &iior); |
- |
- const SkIRect* bounds = &queryBounds; |
- |
- SkRect scalarQueryBounds = SkRect::Make(queryBounds); |
- |
- if (iior) { |
- SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType); |
- SkRect isectRect; |
- if (stackBounds.contains(scalarQueryBounds)) { |
- *initialState = kAllIn_InitialState; |
- if (tighterBounds) { |
- *tighterBounds = queryBounds; |
- } |
- if (requiresAA) { |
- *requiresAA = false; |
- } |
- } else if (isectRect.intersect(stackBounds, scalarQueryBounds)) { |
- // If the caller asked for tighter integer bounds we may be able to |
- // return kAllIn and give the bounds with no elements |
- if (tighterBounds) { |
- isectRect.roundOut(tighterBounds); |
- SkRect scalarTighterBounds = SkRect::Make(*tighterBounds); |
- if (scalarTighterBounds == isectRect) { |
- // the round-out didn't add any area outside the clip rect. |
- if (requiresAA) { |
- *requiresAA = false; |
- } |
- *initialState = kAllIn_InitialState; |
- return; |
- } |
- } |
- *initialState = kAllOut_InitialState; |
- // iior should only be true if aa/non-aa status matches among all elements. |
- SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); |
- bool doAA = iter.prev()->isAA(); |
- SkNEW_INSERT_AT_LLIST_HEAD(result, Element, (isectRect, SkRegion::kReplace_Op, doAA)); |
- if (requiresAA) { |
- *requiresAA = doAA; |
- } |
- } else { |
- *initialState = kAllOut_InitialState; |
- if (requiresAA) { |
- *requiresAA = false; |
- } |
- } |
- return; |
- } else { |
- if (SkClipStack::kNormal_BoundsType == stackBoundsType) { |
- if (!SkRect::Intersects(stackBounds, scalarQueryBounds)) { |
- *initialState = kAllOut_InitialState; |
- if (requiresAA) { |
- *requiresAA = false; |
- } |
- return; |
- } |
- if (tighterBounds) { |
- SkIRect stackIBounds; |
- stackBounds.roundOut(&stackIBounds); |
- tighterBounds->intersect(queryBounds, stackIBounds); |
- bounds = tighterBounds; |
- } |
- } else { |
- if (stackBounds.contains(scalarQueryBounds)) { |
- *initialState = kAllOut_InitialState; |
- if (requiresAA) { |
- *requiresAA = false; |
- } |
- return; |
- } |
- if (tighterBounds) { |
- *tighterBounds = queryBounds; |
- } |
- } |
- } |
- |
- SkRect scalarBounds = SkRect::Make(*bounds); |
- |
- // Now that we have determined the bounds to use and filtered out the trivial cases, call the |
- // helper that actually walks the stack. |
- reduced_stack_walker(stack, scalarBounds, result, resultGenID, initialState, requiresAA); |
- |
- // The list that was computed in this function may be cached based on the gen id of the last |
- // element. |
- SkASSERT(SkClipStack::kInvalidGenID != *resultGenID); |
-} |
-void reduced_stack_walker(const SkClipStack& stack, |
- const SkRect& queryBounds, |
- ElementList* result, |
- int32_t* resultGenID, |
- InitialState* initialState, |
- bool* requiresAA) { |
+static void reduced_stack_walker(const SkClipStack& stack, |
+ const SkRect& queryBounds, |
+ GrReducedClip::ElementList* result, |
+ int32_t* resultGenID, |
+ GrReducedClip::InitialState* initialState, |
+ 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 |
- static const InitialState kUnknown_InitialState = static_cast<InitialState>(-1); |
+ static const GrReducedClip::InitialState kUnknown_InitialState = |
+ static_cast<GrReducedClip::InitialState>(-1); |
*initialState = kUnknown_InitialState; |
// During our backwards walk, track whether we've seen ops that either grow or shrink the clip. |
@@ -166,15 +35,15 @@ void reduced_stack_walker(const SkClipStack& stack, |
while ((kUnknown_InitialState == *initialState)) { |
const Element* element = iter.prev(); |
if (NULL == element) { |
- *initialState = kAllIn_InitialState; |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
break; |
} |
if (SkClipStack::kEmptyGenID == element->getGenID()) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
break; |
} |
if (SkClipStack::kWideOpenGenID == element->getGenID()) { |
- *initialState = kAllIn_InitialState; |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
break; |
} |
@@ -189,12 +58,12 @@ void reduced_stack_walker(const SkClipStack& stack, |
if (element->contains(queryBounds)) { |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} |
} else { |
if (element->contains(queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
skippable = true; |
@@ -210,7 +79,7 @@ void reduced_stack_walker(const SkClipStack& stack, |
// empty. |
if (element->isInverseFilled()) { |
if (element->contains(queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
skippable = true; |
@@ -219,7 +88,7 @@ void reduced_stack_walker(const SkClipStack& stack, |
if (element->contains(queryBounds)) { |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} |
} |
@@ -235,12 +104,12 @@ void reduced_stack_walker(const SkClipStack& stack, |
if (element->contains(queryBounds)) { |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
- *initialState = kAllIn_InitialState; |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
skippable = true; |
} |
} else { |
if (element->contains(queryBounds)) { |
- *initialState = kAllIn_InitialState; |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
skippable = true; |
@@ -279,7 +148,7 @@ void reduced_stack_walker(const SkClipStack& stack, |
// all outside the current clip.B |
if (element->isInverseFilled()) { |
if (element->contains(queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
isFlip = true; |
@@ -288,7 +157,7 @@ void reduced_stack_walker(const SkClipStack& stack, |
if (element->contains(queryBounds)) { |
isFlip = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} |
} |
@@ -303,23 +172,23 @@ void reduced_stack_walker(const SkClipStack& stack, |
// setting the correct value for initialState. |
if (element->isInverseFilled()) { |
if (element->contains(queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
- *initialState = kAllIn_InitialState; |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
skippable = true; |
} |
} else { |
if (element->contains(queryBounds)) { |
- *initialState = kAllIn_InitialState; |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
skippable = true; |
} else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
skippable = true; |
} |
} |
if (!skippable) { |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
embiggens = emsmallens = true; |
} |
break; |
@@ -354,16 +223,16 @@ void reduced_stack_walker(const SkClipStack& stack, |
newElement->invertShapeFillType(); |
newElement->setOp(SkRegion::kDifference_Op); |
if (isReplace) { |
- SkASSERT(kAllOut_InitialState == *initialState); |
- *initialState = kAllIn_InitialState; |
+ SkASSERT(GrReducedClip::kAllOut_InitialState == *initialState); |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
} |
} |
} |
} |
} |
- if ((kAllOut_InitialState == *initialState && !embiggens) || |
- (kAllIn_InitialState == *initialState && !emsmallens)) { |
+ if ((GrReducedClip::kAllOut_InitialState == *initialState && !embiggens) || |
+ (GrReducedClip::kAllIn_InitialState == *initialState && !emsmallens)) { |
result->reset(); |
} else { |
Element* element = result->headIter().get(); |
@@ -372,20 +241,20 @@ void reduced_stack_walker(const SkClipStack& stack, |
switch (element->getOp()) { |
case SkRegion::kDifference_Op: |
// subtracting from the empty set yields the empty set. |
- skippable = kAllOut_InitialState == *initialState; |
+ skippable = GrReducedClip::kAllOut_InitialState == *initialState; |
break; |
case SkRegion::kIntersect_Op: |
// intersecting with the empty set yields the empty set |
- if (kAllOut_InitialState == *initialState) { |
+ if (GrReducedClip::kAllOut_InitialState == *initialState) { |
skippable = true; |
} else { |
// We can clear to zero and then simply draw the clip element. |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
element->setOp(SkRegion::kReplace_Op); |
} |
break; |
case SkRegion::kUnion_Op: |
- if (kAllIn_InitialState == *initialState) { |
+ if (GrReducedClip::kAllIn_InitialState == *initialState) { |
// unioning the infinite plane with anything is a no-op. |
skippable = true; |
} else { |
@@ -394,23 +263,23 @@ void reduced_stack_walker(const SkClipStack& stack, |
} |
break; |
case SkRegion::kXOR_Op: |
- if (kAllOut_InitialState == *initialState) { |
+ if (GrReducedClip::kAllOut_InitialState == *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 (kAllIn_InitialState == *initialState) { |
+ if (GrReducedClip::kAllIn_InitialState == *initialState) { |
// subtracting the whole plane will yield the empty set. |
skippable = true; |
- *initialState = kAllOut_InitialState; |
+ *initialState = GrReducedClip::kAllOut_InitialState; |
} else { |
// this picks up flips inserted in the backwards pass. |
skippable = element->isInverseFilled() ? |
!SkRect::Intersects(element->getBounds(), queryBounds) : |
element->contains(queryBounds); |
if (skippable) { |
- *initialState = kAllIn_InitialState; |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
} else { |
element->setOp(SkRegion::kReplace_Op); |
} |
@@ -440,11 +309,130 @@ void reduced_stack_walker(const SkClipStack& stack, |
} |
if (0 == result->count()) { |
- if (*initialState == kAllIn_InitialState) { |
+ if (*initialState == GrReducedClip::kAllIn_InitialState) { |
*resultGenID = SkClipStack::kWideOpenGenID; |
} else { |
*resultGenID = SkClipStack::kEmptyGenID; |
} |
} |
} |
-} // namespace GrReducedClip |
+ |
+/* |
+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. |
+*/ |
+void GrReducedClip::ReduceClipStack(const SkClipStack& stack, |
+ const SkIRect& queryBounds, |
+ ElementList* result, |
+ int32_t* resultGenID, |
+ InitialState* initialState, |
+ SkIRect* tighterBounds, |
+ bool* requiresAA) { |
+ result->reset(); |
+ |
+ // The clip established by the element list might be cached based on the last |
+ // generation id. When we make early returns, we do not know what was the generation |
+ // id that lead to the state. Make a conservative guess. |
+ *resultGenID = stack.getTopmostGenID(); |
+ |
+ if (stack.isWideOpen()) { |
+ *initialState = kAllIn_InitialState; |
+ return; |
+ } |
+ |
+ |
+ // We initially look at whether the bounds alone is sufficient. We also use the stack bounds to |
+ // attempt to compute the tighterBounds. |
+ |
+ SkClipStack::BoundsType stackBoundsType; |
+ SkRect stackBounds; |
+ bool iior; |
+ stack.getBounds(&stackBounds, &stackBoundsType, &iior); |
+ |
+ const SkIRect* bounds = &queryBounds; |
+ |
+ SkRect scalarQueryBounds = SkRect::Make(queryBounds); |
+ |
+ if (iior) { |
+ SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType); |
+ SkRect isectRect; |
+ if (stackBounds.contains(scalarQueryBounds)) { |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
+ if (tighterBounds) { |
+ *tighterBounds = queryBounds; |
+ } |
+ if (requiresAA) { |
+ *requiresAA = false; |
+ } |
+ } else if (isectRect.intersect(stackBounds, scalarQueryBounds)) { |
+ // If the caller asked for tighter integer bounds we may be able to |
+ // return kAllIn and give the bounds with no elements |
+ if (tighterBounds) { |
+ isectRect.roundOut(tighterBounds); |
+ SkRect scalarTighterBounds = SkRect::Make(*tighterBounds); |
+ if (scalarTighterBounds == isectRect) { |
+ // the round-out didn't add any area outside the clip rect. |
+ if (requiresAA) { |
+ *requiresAA = false; |
+ } |
+ *initialState = GrReducedClip::kAllIn_InitialState; |
+ return; |
+ } |
+ } |
+ *initialState = kAllOut_InitialState; |
+ // iior should only be true if aa/non-aa status matches among all elements. |
+ SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); |
+ bool doAA = iter.prev()->isAA(); |
+ SkNEW_INSERT_AT_LLIST_HEAD(result, Element, (isectRect, SkRegion::kReplace_Op, doAA)); |
+ if (requiresAA) { |
+ *requiresAA = doAA; |
+ } |
+ } else { |
+ *initialState = kAllOut_InitialState; |
+ if (requiresAA) { |
+ *requiresAA = false; |
+ } |
+ } |
+ return; |
+ } else { |
+ if (SkClipStack::kNormal_BoundsType == stackBoundsType) { |
+ if (!SkRect::Intersects(stackBounds, scalarQueryBounds)) { |
+ *initialState = kAllOut_InitialState; |
+ if (requiresAA) { |
+ *requiresAA = false; |
+ } |
+ return; |
+ } |
+ if (tighterBounds) { |
+ SkIRect stackIBounds; |
+ stackBounds.roundOut(&stackIBounds); |
+ tighterBounds->intersect(queryBounds, stackIBounds); |
+ bounds = tighterBounds; |
+ } |
+ } else { |
+ if (stackBounds.contains(scalarQueryBounds)) { |
+ *initialState = kAllOut_InitialState; |
+ if (requiresAA) { |
+ *requiresAA = false; |
+ } |
+ return; |
+ } |
+ if (tighterBounds) { |
+ *tighterBounds = queryBounds; |
+ } |
+ } |
+ } |
+ |
+ SkRect scalarBounds = SkRect::Make(*bounds); |
+ |
+ // Now that we have determined the bounds to use and filtered out the trivial cases, call the |
+ // helper that actually walks the stack. |
+ reduced_stack_walker(stack, scalarBounds, result, resultGenID, initialState, requiresAA); |
+ |
+ // The list that was computed in this function may be cached based on the gen id of the last |
+ // element. |
+ SkASSERT(SkClipStack::kInvalidGenID != *resultGenID); |
+} |