From a444430281ea35cb76fb42516978b4a93221c2c7 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Tue, 4 Dec 2012 15:22:12 +0000 Subject: [PATCH] Make GrReduceClipStack use a caller provided query rect rather than return a bounds. R=robertphillips@google.com Review URL: https://codereview.appspot.com/6865059 git-svn-id: http://skia.googlecode.com/svn/trunk@6665 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/gpu/GrClipMaskManager.cpp | 244 +++++++++++++++++++++--------------------- src/gpu/GrClipMaskManager.h | 17 ++- tests/ClipStackTest.cpp | 19 ++-- 3 files changed, 137 insertions(+), 143 deletions(-) diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 64ead1a..1b8bcd4 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -39,33 +39,49 @@ based on later intersect operations, and perhaps remove intersect-rects. We coul take a rect in case the caller knows a bound on what is to be drawn through this clip. */ void GrReduceClipStack(const SkClipStack& stack, + const SkRect& queryBounds, ElementList* result, - SkRect* resultBounds, - bool* resultsAreBounded, InitialState* initialState) { result->reset(); if (stack.isWideOpen()) { *initialState = kAllIn_InitialState; - *resultsAreBounded = false; return; } - SkClipStack::BoundsType type; + SkClipStack::BoundsType stackBoundsType; + SkRect stackBounds; bool iior; - stack.getBounds(resultBounds, &type, &iior); + stack.getBounds(&stackBounds, &stackBoundsType, &iior); + if (iior) { - *resultsAreBounded = true; - *initialState = kAllOut_InitialState; - SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); - // iior should only be true if aa/non-aa status matches among all elements. - bool doAA = iter.prev()->isAA(); - SkNEW_INSERT_AT_LLIST_TAIL(result, Element, (*resultBounds, SkRegion::kReplace_Op, doAA)); + SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType); + SkRect isectRect; + if (stackBounds.contains(queryBounds)) { + *initialState = kAllIn_InitialState; + } else if (isectRect.intersect(stackBounds, queryBounds)) { + // 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)); + } else { + *initialState = kAllOut_InitialState; + } return; + } else { + if (SkClipStack::kNormal_BoundsType == stackBoundsType) { + if (!SkRect::Intersects(stackBounds, queryBounds)) { + *initialState = kAllOut_InitialState; + return; + } + } else { + if (stackBounds.contains(queryBounds)) { + *initialState = kAllOut_InitialState; + return; + } + } } - *resultsAreBounded = SkClipStack::kNormal_BoundsType == type && !resultBounds->isEmpty(); - // walk backwards until we get to: // a) the beginning // b) an operation that is known to make the bounds all inside/outside @@ -100,23 +116,21 @@ void GrReduceClipStack(const SkClipStack& stack, switch (element->getOp()) { case SkRegion::kDifference_Op: - if (*resultsAreBounded) { - // 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(*resultBounds)) { - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } - } else { - if (element->contains(*resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - skippable = true; - } + // 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(queryBounds)) { + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; + } + } else { + if (element->contains(queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + skippable = true; } } if (!skippable) { @@ -124,24 +138,22 @@ void GrReduceClipStack(const SkClipStack& stack, } break; case SkRegion::kIntersect_Op: - if (*resultsAreBounded) { - // 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(*resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - skippable = true; - } - } else { - if (element->contains(*resultBounds)) { - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } + // 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(queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + skippable = true; + } + } else { + if (element->contains(queryBounds)) { + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; } } if (!skippable) { @@ -149,24 +161,22 @@ void GrReduceClipStack(const SkClipStack& stack, } break; case SkRegion::kUnion_Op: - if (*resultsAreBounded) { - // 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(*resultBounds)) { - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - *initialState = kAllIn_InitialState; - skippable = true; - } - } else { - if (element->contains(*resultBounds)) { - *initialState = kAllIn_InitialState; - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - skippable = true; - } + // 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(queryBounds)) { + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + *initialState = kAllIn_InitialState; + skippable = true; + } + } else { + if (element->contains(queryBounds)) { + *initialState = kAllIn_InitialState; + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + skippable = true; } } if (!skippable) { @@ -174,23 +184,21 @@ void GrReduceClipStack(const SkClipStack& stack, } break; case SkRegion::kXOR_Op: - if (*resultsAreBounded) { - // 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(*resultBounds)) { - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - isFlip = true; - } - } else { - if (element->contains(*resultBounds)) { - isFlip = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - skippable = true; - } + // 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(queryBounds)) { + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + isFlip = true; + } + } else { + if (element->contains(queryBounds)) { + isFlip = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + skippable = true; } } if (!skippable) { @@ -202,21 +210,19 @@ void GrReduceClipStack(const SkClipStack& stack, // 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 (*resultsAreBounded) { - if (element->isInverseFilled()) { - if (element->contains(*resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - isFlip = true; - } - } else { - if (element->contains(*resultBounds)) { - isFlip = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } + if (element->isInverseFilled()) { + if (element->contains(queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + isFlip = true; + } + } else { + if (element->contains(queryBounds)) { + isFlip = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; } } if (!skippable) { @@ -228,23 +234,21 @@ void GrReduceClipStack(const SkClipStack& stack, // 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 (*resultsAreBounded) { - if (element->isInverseFilled()) { - if (element->contains(*resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - *initialState = kAllIn_InitialState; - skippable = true; - } - } else { - if (element->contains(*resultBounds)) { - *initialState = kAllIn_InitialState; - skippable = true; - } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) { - *initialState = kAllOut_InitialState; - skippable = true; - } + if (element->isInverseFilled()) { + if (element->contains(queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + *initialState = kAllIn_InitialState; + skippable = true; + } + } else { + if (element->contains(queryBounds)) { + *initialState = kAllIn_InitialState; + skippable = true; + } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) { + *initialState = kAllOut_InitialState; + skippable = true; } } if (!skippable) { @@ -263,7 +267,7 @@ void GrReduceClipStack(const SkClipStack& stack, SkRegion::kReverseDifference_Op == element->getOp()); SkNEW_INSERT_AT_LLIST_HEAD(result, Element, - (*resultBounds, SkRegion::kReverseDifference_Op, false)); + (queryBounds, SkRegion::kReverseDifference_Op, false)); } else { result->addToHead(*element); } @@ -309,11 +313,9 @@ void GrReduceClipStack(const SkClipStack& stack, *initialState = kAllOut_InitialState; } else { // this picks up flips inserted in the backwards pass. - if (*resultsAreBounded) { - skippable = element->isInverseFilled() ? - !SkRect::Intersects(element->getBounds(), *resultBounds) : - element->contains(*resultBounds); - } + skippable = element->isInverseFilled() ? + !SkRect::Intersects(element->getBounds(), queryBounds) : + element->contains(queryBounds); if (skippable) { *initialState = kAllIn_InitialState; } else { diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index c3a1b5e..0c8484a 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -167,19 +167,16 @@ enum InitialState { kAllOut_InitialState, }; -/** This function takes a clip stack and produces a reduced set of SkClipStack::Iter::Clip elements - * in param clips that are equivalent to the full stack. If a finite bound for the area inside the - * clip can be determined resultsAreBounds will be true and resultBounds will be those bounds. When - * the results are bounded it is assumed that the caller will restrict the effect of each operation - * to the bounds or intersect with the bounds as a final step. The initial state of the bounds (or - * the unbounded plane when resultsArBounded is false) before the first element of clips is applied - * is returned via initialState. This function is declared here so that it can be unit-tested. It - * may become a member function of SkClipStack when its interface is determined to be stable. +/** + * This function takes a clip stack and a query rectangle and it produces a reduced set of + * SkClipStack::Elements that are equivalent to applying the full stack to the rectangle. The + * initial state of the query rectangle before the first clip element is applied is returned via + * initialState. This function is declared here so that it can be unit-tested. It may become a + * member function of SkClipStack when its interface is determined to be stable. */ void GrReduceClipStack(const SkClipStack& stack, + const SkRect& queryBounds, ElementList* result, - SkRect* resultBounds, - bool* resultsAreBounded, InitialState* initialState); } // namespace GrReducedClip diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp index bbd833b..aba5334 100644 --- a/tests/ClipStackTest.cpp +++ b/tests/ClipStackTest.cpp @@ -659,13 +659,17 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) { } } + SkRect inflatedBounds = kBounds; + inflatedBounds.outset(kBounds.width() / 2, kBounds.height() / 2); + SkIRect inflatedIBounds; + inflatedBounds.roundOut(&inflatedIBounds); + typedef GrReducedClip::ElementList ElementList; // Get the reduced version of the stack. ElementList reducedClips; - SkRect resultBounds; - bool bounded; + GrReducedClip::InitialState initial; - GrReducedClip::GrReduceClipStack(stack, &reducedClips, &resultBounds, &bounded, &initial); + GrReducedClip::GrReduceClipStack(stack, inflatedBounds, &reducedClips, &initial); // Build a new clip stack based on the reduced clip elements SkClipStack reducedStack; @@ -676,17 +680,8 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) { for (ElementList::Iter iter = reducedClips.headIter(); NULL != iter.get(); iter.next()) { add_elem_to_stack(*iter.get(), &reducedStack); } - if (bounded) { - // GrReduceClipStack() assumes that there is an implicit clip to the bounds - reducedStack.clipDevRect(resultBounds, SkRegion::kIntersect_Op, true); - } // convert both the original stack and reduced stack to SkRegions and see if they're equal - SkRect inflatedBounds = kBounds; - inflatedBounds.outset(kBounds.width() / 2, kBounds.height() / 2); - SkIRect inflatedIBounds; - inflatedBounds.roundOut(&inflatedIBounds); - SkRegion region; SkRegion reducedRegion; -- 2.7.4