| 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);
|
| +}
|
|
|