Chromium Code Reviews| Index: src/gpu/GrReducedClip.cpp |
| diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp |
| index 2083af907ecc18a806fecfc0b6cf85ca18d80dc5..a1e537e42d2ec6f01a76d50949762a577c066880 100644 |
| --- a/src/gpu/GrReducedClip.cpp |
| +++ b/src/gpu/GrReducedClip.cpp |
| @@ -1,4 +1,3 @@ |
| - |
| /* |
| * Copyright 2012 Google Inc. |
| * |
| @@ -9,151 +8,20 @@ |
| #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 |
|
robertphillips
2014/10/23 12:24:17
overlength ?
tfarina
2014/10/24 00:38:57
Done.
|
| - 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 +34,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 +57,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 +78,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 +87,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 +103,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 +147,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 +156,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 +171,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 +222,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 +240,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 +262,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 +308,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, |
|
tfarina
2014/10/23 04:03:08
Sorry for this big diff. I can revert if you want.
|
| + 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); |
| +} |