| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrReducedClip.h" | 8 #include "GrReducedClip.h" |
| 9 | 9 |
| 10 #include "GrAppliedClip.h" | 10 #include "GrAppliedClip.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 typedef SkClipStack::Element Element; | 22 typedef SkClipStack::Element Element; |
| 23 | 23 |
| 24 /** | 24 /** |
| 25 * There are plenty of optimizations that could be added here. Maybe flips could
be folded into | 25 * There are plenty of optimizations that could be added here. Maybe flips could
be folded into |
| 26 * earlier operations. Or would inserting flips and reversing earlier ops ever b
e a win? Perhaps | 26 * earlier operations. Or would inserting flips and reversing earlier ops ever b
e a win? Perhaps |
| 27 * for the case where the bounds are kInsideOut_BoundsType. We could restrict ea
rlier operations | 27 * for the case where the bounds are kInsideOut_BoundsType. We could restrict ea
rlier operations |
| 28 * based on later intersect operations, and perhaps remove intersect-rects. We c
ould optionally | 28 * based on later intersect operations, and perhaps remove intersect-rects. We c
ould optionally |
| 29 * take a rect in case the caller knows a bound on what is to be drawn through t
his clip. | 29 * take a rect in case the caller knows a bound on what is to be drawn through t
his clip. |
| 30 */ | 30 */ |
| 31 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
) { | 31 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
, |
| 32 int maxWindowRectangles) { |
| 32 SkASSERT(!queryBounds.isEmpty()); | 33 SkASSERT(!queryBounds.isEmpty()); |
| 33 fHasIBounds = false; | 34 fHasIBounds = false; |
| 34 | 35 |
| 35 if (stack.isWideOpen()) { | 36 if (stack.isWideOpen()) { |
| 36 fInitialState = InitialState::kAllIn; | 37 fInitialState = InitialState::kAllIn; |
| 37 return; | 38 return; |
| 38 } | 39 } |
| 39 | 40 |
| 40 SkClipStack::BoundsType stackBoundsType; | 41 SkClipStack::BoundsType stackBoundsType; |
| 41 SkRect stackBounds; | 42 SkRect stackBounds; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 // clip will be enforced by the scissor through fIBounds.) | 88 // clip will be enforced by the scissor through fIBounds.) |
| 88 SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds
))); | 89 SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds
))); |
| 89 } | 90 } |
| 90 | 91 |
| 91 fIBounds = GrClip::GetPixelIBounds(tighterQuery); | 92 fIBounds = GrClip::GetPixelIBounds(tighterQuery); |
| 92 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid
eClip above. | 93 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid
eClip above. |
| 93 fHasIBounds = true; | 94 fHasIBounds = true; |
| 94 | 95 |
| 95 // Now that we have determined the bounds to use and filtered out the trivia
l cases, call the | 96 // Now that we have determined the bounds to use and filtered out the trivia
l cases, call the |
| 96 // helper that actually walks the stack. | 97 // helper that actually walks the stack. |
| 97 this->walkStack(stack, tighterQuery); | 98 this->walkStack(stack, tighterQuery, maxWindowRectangles); |
| 99 |
| 100 if (fWindowRects.count() < maxWindowRectangles) { |
| 101 this->addInteriorWindowRectangles(maxWindowRectangles); |
| 102 } |
| 98 } | 103 } |
| 99 | 104 |
| 100 void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
s) { | 105 void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
s, |
| 106 int maxWindowRectangles) { |
| 101 // walk backwards until we get to: | 107 // walk backwards until we get to: |
| 102 // a) the beginning | 108 // a) the beginning |
| 103 // b) an operation that is known to make the bounds all inside/outside | 109 // b) an operation that is known to make the bounds all inside/outside |
| 104 // c) a replace operation | 110 // c) a replace operation |
| 105 | 111 |
| 106 enum class InitialTriState { | 112 enum class InitialTriState { |
| 107 kUnknown = -1, | 113 kUnknown = -1, |
| 108 kAllIn = (int)GrReducedClip::InitialState::kAllIn, | 114 kAllIn = (int)GrReducedClip::InitialState::kAllIn, |
| 109 kAllOut = (int)GrReducedClip::InitialState::kAllOut | 115 kAllOut = (int)GrReducedClip::InitialState::kAllOut |
| 110 } initialTriState = InitialTriState::kUnknown; | 116 } initialTriState = InitialTriState::kUnknown; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { | 155 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { |
| 150 initialTriState = InitialTriState::kAllOut; | 156 initialTriState = InitialTriState::kAllOut; |
| 151 skippable = true; | 157 skippable = true; |
| 152 } | 158 } |
| 153 } else { | 159 } else { |
| 154 if (element->contains(relaxedQueryBounds)) { | 160 if (element->contains(relaxedQueryBounds)) { |
| 155 initialTriState = InitialTriState::kAllOut; | 161 initialTriState = InitialTriState::kAllOut; |
| 156 skippable = true; | 162 skippable = true; |
| 157 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { | 163 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { |
| 158 skippable = true; | 164 skippable = true; |
| 165 } else if (fWindowRects.count() < maxWindowRectangles && !em
biggens && |
| 166 !element->isAA() && Element::kRect_Type == elemen
t->getType()) { |
| 167 this->addWindowRectangle(element->getRect(), false); |
| 168 skippable = true; |
| 159 } | 169 } |
| 160 } | 170 } |
| 161 if (!skippable) { | 171 if (!skippable) { |
| 162 emsmallens = true; | 172 emsmallens = true; |
| 163 } | 173 } |
| 164 break; | 174 break; |
| 165 case SkRegion::kIntersect_Op: | 175 case SkRegion::kIntersect_Op: |
| 166 // check if the shape intersected contains the entire bounds and
therefore can | 176 // check if the shape intersected contains the entire bounds and
therefore can |
| 167 // be skipped or it is outside the entire bounds and therefore m
akes the clip | 177 // be skipped or it is outside the entire bounds and therefore m
akes the clip |
| 168 // empty. | 178 // empty. |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 element = fElements.headIter().get(); | 423 element = fElements.headIter().get(); |
| 414 } | 424 } |
| 415 } | 425 } |
| 416 } | 426 } |
| 417 fRequiresAA = numAAElements > 0; | 427 fRequiresAA = numAAElements > 0; |
| 418 | 428 |
| 419 SkASSERT(InitialTriState::kUnknown != initialTriState); | 429 SkASSERT(InitialTriState::kUnknown != initialTriState); |
| 420 fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState); | 430 fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState); |
| 421 } | 431 } |
| 422 | 432 |
| 433 static bool element_is_pure_subtract(SkRegion::Op op) { |
| 434 SkASSERT(op >= 0); |
| 435 return op <= SkRegion::kIntersect_Op; |
| 436 |
| 437 GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op); |
| 438 GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op); |
| 439 } |
| 440 |
| 441 void GrReducedClip::addInteriorWindowRectangles(int maxWindowRectangles) { |
| 442 SkASSERT(fWindowRects.count() < maxWindowRectangles); |
| 443 // Walk backwards through the element list and add window rectangles to the
interiors of |
| 444 // "difference" elements. Quit if we encounter an element that may grow the
clip. |
| 445 ElementList::Iter iter(fElements, ElementList::Iter::kTail_IterStart); |
| 446 for (; iter.get() && element_is_pure_subtract(iter.get()->getOp()); iter.pre
v()) { |
| 447 const Element* element = iter.get(); |
| 448 if (SkRegion::kDifference_Op != element->getOp()) { |
| 449 continue; |
| 450 } |
| 451 |
| 452 if (Element::kRect_Type == element->getType()) { |
| 453 SkASSERT(element->isAA()); |
| 454 this->addWindowRectangle(element->getRect(), true); |
| 455 if (fWindowRects.count() >= maxWindowRectangles) { |
| 456 return; |
| 457 } |
| 458 continue; |
| 459 } |
| 460 |
| 461 if (Element::kRRect_Type == element->getType()) { |
| 462 // For round rects we add two overlapping windows in the shape of a
plus. |
| 463 const SkRRect& clipRRect = element->getRRect(); |
| 464 SkVector insetTL = clipRRect.radii(SkRRect::kUpperLeft_Corner); |
| 465 SkVector insetBR = clipRRect.radii(SkRRect::kLowerRight_Corner); |
| 466 if (SkRRect::kComplex_Type == clipRRect.getType()) { |
| 467 const SkVector& insetTR = clipRRect.radii(SkRRect::kUpperRight_C
orner); |
| 468 const SkVector& insetBL = clipRRect.radii(SkRRect::kLowerLeft_Co
rner); |
| 469 insetTL.fX = SkTMax(insetTL.x(), insetBL.x()); |
| 470 insetTL.fY = SkTMax(insetTL.y(), insetTR.y()); |
| 471 insetBR.fX = SkTMax(insetBR.x(), insetTR.x()); |
| 472 insetBR.fY = SkTMax(insetBR.y(), insetBL.y()); |
| 473 } |
| 474 const SkRect& bounds = clipRRect.getBounds(); |
| 475 if (insetTL.x() + insetBR.x() >= bounds.width() || |
| 476 insetTL.y() + insetBR.y() >= bounds.height()) { |
| 477 continue; // The interior "plus" is empty. |
| 478 } |
| 479 |
| 480 SkRect horzRect = SkRect::MakeLTRB(bounds.left(), bounds.top() + ins
etTL.y(), |
| 481 bounds.right(), bounds.bottom() -
insetBR.y()); |
| 482 this->addWindowRectangle(horzRect, element->isAA()); |
| 483 if (fWindowRects.count() >= maxWindowRectangles) { |
| 484 return; |
| 485 } |
| 486 |
| 487 SkRect vertRect = SkRect::MakeLTRB(bounds.left() + insetTL.x(), boun
ds.top(), |
| 488 bounds.right() - insetBR.x(), bou
nds.bottom()); |
| 489 this->addWindowRectangle(vertRect, element->isAA()); |
| 490 if (fWindowRects.count() >= maxWindowRectangles) { |
| 491 return; |
| 492 } |
| 493 continue; |
| 494 } |
| 495 } |
| 496 } |
| 497 |
| 498 inline void GrReducedClip::addWindowRectangle(const SkRect& elementInteriorRect,
bool elementIsAA) { |
| 499 SkIRect* window = &fWindowRects.addWindow(); |
| 500 if (!elementIsAA) { |
| 501 elementInteriorRect.round(window); |
| 502 } else { |
| 503 elementInteriorRect.roundIn(window); |
| 504 } |
| 505 } |
| 506 |
| 423 inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) { | 507 inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) { |
| 424 SkASSERT(fHasIBounds); | 508 SkASSERT(fHasIBounds); |
| 425 if (!fIBounds.intersect(irect)) { | 509 if (!fIBounds.intersect(irect)) { |
| 426 fHasIBounds = false; | 510 fHasIBounds = false; |
| 511 fWindowRects.reset(); |
| 427 fElements.reset(); | 512 fElements.reset(); |
| 428 fRequiresAA = false; | 513 fRequiresAA = false; |
| 429 fInitialState = InitialState::kAllOut; | 514 fInitialState = InitialState::kAllOut; |
| 430 return false; | 515 return false; |
| 431 } | 516 } |
| 432 return true; | 517 return true; |
| 433 } | 518 } |
| 434 | 519 |
| 435 //////////////////////////////////////////////////////////////////////////////// | 520 //////////////////////////////////////////////////////////////////////////////// |
| 436 // Create a 8-bit clip mask in alpha | 521 // Create a 8-bit clip mask in alpha |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 break; | 581 break; |
| 497 } | 582 } |
| 498 } | 583 } |
| 499 } | 584 } |
| 500 | 585 |
| 501 bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { | 586 bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { |
| 502 // The texture may be larger than necessary, this rect represents the part o
f the texture | 587 // The texture may be larger than necessary, this rect represents the part o
f the texture |
| 503 // we populate with a rasterization of the clip. | 588 // we populate with a rasterization of the clip. |
| 504 GrFixedClip clip(SkIRect::MakeWH(fIBounds.width(), fIBounds.height())); | 589 GrFixedClip clip(SkIRect::MakeWH(fIBounds.width(), fIBounds.height())); |
| 505 | 590 |
| 591 if (!fWindowRects.empty()) { |
| 592 clip.windowRectsState().setExclusive(fWindowRects, {fIBounds.left(), fIB
ounds.top()}); |
| 593 } |
| 594 |
| 506 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 595 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
| 507 // clear the part that we care about. | 596 // clear the part that we care about. |
| 508 GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1
: 0; | 597 GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1
: 0; |
| 509 dc->drawContextPriv().clear(clip, initialCoverage, true); | 598 dc->drawContextPriv().clear(clip, initialCoverage, true); |
| 510 | 599 |
| 511 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip space. | 600 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip space. |
| 512 SkMatrix translate; | 601 SkMatrix translate; |
| 513 translate.setTranslate(SkIntToScalar(-fIBounds.left()), SkIntToScalar(-fIBou
nds.top())); | 602 translate.setTranslate(SkIntToScalar(-fIBounds.left()), SkIntToScalar(-fIBou
nds.top())); |
| 514 | 603 |
| 515 // walk through each clip element and perform its set op | 604 // walk through each clip element and perform its set op |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 return true; | 651 return true; |
| 563 } | 652 } |
| 564 | 653 |
| 565 //////////////////////////////////////////////////////////////////////////////// | 654 //////////////////////////////////////////////////////////////////////////////// |
| 566 // Create a 1-bit clip mask in the stencil buffer. | 655 // Create a 1-bit clip mask in the stencil buffer. |
| 567 | 656 |
| 568 class StencilClip final : public GrClip { | 657 class StencilClip final : public GrClip { |
| 569 public: | 658 public: |
| 570 StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} | 659 StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} |
| 571 const GrFixedClip& fixedClip() const { return fFixedClip; } | 660 const GrFixedClip& fixedClip() const { return fFixedClip; } |
| 661 GrWindowRectsState& windowRectsState() { return fFixedClip.windowRectsState(
); } |
| 572 | 662 |
| 573 private: | 663 private: |
| 574 bool quickContains(const SkRect&) const final { | 664 bool quickContains(const SkRect&) const override { |
| 575 return false; | 665 return false; |
| 576 } | 666 } |
| 577 void getConservativeBounds(int width, int height, SkIRect* devResult, bool*
iior) const final { | 667 void getConservativeBounds(int width, int height, SkIRect* bounds, bool* iio
r) const override { |
| 578 fFixedClip.getConservativeBounds(width, height, devResult, iior); | 668 fFixedClip.getConservativeBounds(width, height, bounds, iior); |
| 579 } | 669 } |
| 580 bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const final { | 670 bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override { |
| 581 return false; | 671 return false; |
| 582 } | 672 } |
| 583 bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, | 673 bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, |
| 584 bool hasUserStencilSettings, GrAppliedClip* out) const final { | 674 bool hasUserStencilSettings, GrAppliedClip* out) const override { |
| 585 if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSetti
ngs, out)) { | 675 if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSetti
ngs, out)) { |
| 586 return false; | 676 return false; |
| 587 } | 677 } |
| 588 out->addStencilClip(); | 678 out->addStencilClip(); |
| 589 return true; | 679 return true; |
| 590 } | 680 } |
| 591 | 681 |
| 592 GrFixedClip fFixedClip; | 682 GrFixedClip fFixedClip; |
| 593 | 683 |
| 594 typedef GrClip INHERITED; | 684 typedef GrClip INHERITED; |
| 595 }; | 685 }; |
| 596 | 686 |
| 597 bool GrReducedClip::drawStencilClipMask(GrContext* context, | 687 bool GrReducedClip::drawStencilClipMask(GrContext* context, |
| 598 GrDrawContext* drawContext, | 688 GrDrawContext* drawContext, |
| 599 const SkIPoint& clipOrigin) const { | 689 const SkIPoint& clipOrigin) const { |
| 600 // We set the current clip to the bounds so that our recursive draws are sci
ssored to them. | 690 // We set the current clip to the bounds so that our recursive draws are sci
ssored to them. |
| 601 StencilClip stencilClip(fIBounds.makeOffset(-clipOrigin.x(), -clipOrigin.y()
)); | 691 StencilClip stencilClip(fIBounds.makeOffset(-clipOrigin.x(), -clipOrigin.y()
)); |
| 602 | 692 |
| 693 if (!fWindowRects.empty()) { |
| 694 stencilClip.windowRectsState().setExclusive(fWindowRects, clipOrigin); |
| 695 } |
| 696 |
| 603 bool initialState = InitialState::kAllIn == this->initialState(); | 697 bool initialState = InitialState::kAllIn == this->initialState(); |
| 604 drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), ini
tialState); | 698 drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), ini
tialState); |
| 605 | 699 |
| 606 // Set the matrix so that rendered clip elements are transformed from clip t
o stencil space. | 700 // Set the matrix so that rendered clip elements are transformed from clip t
o stencil space. |
| 607 SkMatrix viewMatrix; | 701 SkMatrix viewMatrix; |
| 608 viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipO
rigin.y())); | 702 viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipO
rigin.y())); |
| 609 | 703 |
| 610 // walk through each clip element and perform its set op | 704 // walk through each clip element and perform its set op |
| 611 // with the existing clip. | 705 // with the existing clip. |
| 612 for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { | 706 for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 // The view matrix is setup to do clip space -> stencil space tr
anslation, so | 831 // The view matrix is setup to do clip space -> stencil space tr
anslation, so |
| 738 // draw rect in clip space. | 832 // draw rect in clip space. |
| 739 drawContext->drawContextPriv().stencilRect(stencilClip, *pass, | 833 drawContext->drawContextPriv().stencilRect(stencilClip, *pass, |
| 740 false, viewMatrix, | 834 false, viewMatrix, |
| 741 SkRect::Make(fIBounds
)); | 835 SkRect::Make(fIBounds
)); |
| 742 } | 836 } |
| 743 } | 837 } |
| 744 } | 838 } |
| 745 return true; | 839 return true; |
| 746 } | 840 } |
| OLD | NEW |