| 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) { | |
| 33 SkASSERT(!queryBounds.isEmpty()); | 32 SkASSERT(!queryBounds.isEmpty()); |
| 34 fHasIBounds = false; | 33 fHasIBounds = false; |
| 35 | 34 |
| 36 if (stack.isWideOpen()) { | 35 if (stack.isWideOpen()) { |
| 37 fInitialState = InitialState::kAllIn; | 36 fInitialState = InitialState::kAllIn; |
| 38 return; | 37 return; |
| 39 } | 38 } |
| 40 | 39 |
| 41 SkClipStack::BoundsType stackBoundsType; | 40 SkClipStack::BoundsType stackBoundsType; |
| 42 SkRect stackBounds; | 41 SkRect stackBounds; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 // clip will be enforced by the scissor through fIBounds.) | 87 // clip will be enforced by the scissor through fIBounds.) |
| 89 SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds
))); | 88 SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds
))); |
| 90 } | 89 } |
| 91 | 90 |
| 92 fIBounds = GrClip::GetPixelIBounds(tighterQuery); | 91 fIBounds = GrClip::GetPixelIBounds(tighterQuery); |
| 93 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid
eClip above. | 92 SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid
eClip above. |
| 94 fHasIBounds = true; | 93 fHasIBounds = true; |
| 95 | 94 |
| 96 // Now that we have determined the bounds to use and filtered out the trivia
l cases, call the | 95 // Now that we have determined the bounds to use and filtered out the trivia
l cases, call the |
| 97 // helper that actually walks the stack. | 96 // helper that actually walks the stack. |
| 98 this->walkStack(stack, tighterQuery, maxWindowRectangles); | 97 this->walkStack(stack, tighterQuery); |
| 99 | |
| 100 if (fWindowRects.count() < maxWindowRectangles) { | |
| 101 this->addInteriorWindowRectangles(maxWindowRectangles); | |
| 102 } | |
| 103 } | 98 } |
| 104 | 99 |
| 105 void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
s, | 100 void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
s) { |
| 106 int maxWindowRectangles) { | |
| 107 // walk backwards until we get to: | 101 // walk backwards until we get to: |
| 108 // a) the beginning | 102 // a) the beginning |
| 109 // b) an operation that is known to make the bounds all inside/outside | 103 // b) an operation that is known to make the bounds all inside/outside |
| 110 // c) a replace operation | 104 // c) a replace operation |
| 111 | 105 |
| 112 enum class InitialTriState { | 106 enum class InitialTriState { |
| 113 kUnknown = -1, | 107 kUnknown = -1, |
| 114 kAllIn = (int)GrReducedClip::InitialState::kAllIn, | 108 kAllIn = (int)GrReducedClip::InitialState::kAllIn, |
| 115 kAllOut = (int)GrReducedClip::InitialState::kAllOut | 109 kAllOut = (int)GrReducedClip::InitialState::kAllOut |
| 116 } initialTriState = InitialTriState::kUnknown; | 110 } initialTriState = InitialTriState::kUnknown; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { | 149 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { |
| 156 initialTriState = InitialTriState::kAllOut; | 150 initialTriState = InitialTriState::kAllOut; |
| 157 skippable = true; | 151 skippable = true; |
| 158 } | 152 } |
| 159 } else { | 153 } else { |
| 160 if (element->contains(relaxedQueryBounds)) { | 154 if (element->contains(relaxedQueryBounds)) { |
| 161 initialTriState = InitialTriState::kAllOut; | 155 initialTriState = InitialTriState::kAllOut; |
| 162 skippable = true; | 156 skippable = true; |
| 163 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { | 157 } else if (GrClip::IsOutsideClip(element->getBounds(), query
Bounds)) { |
| 164 skippable = true; | 158 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; | |
| 169 } | 159 } |
| 170 } | 160 } |
| 171 if (!skippable) { | 161 if (!skippable) { |
| 172 emsmallens = true; | 162 emsmallens = true; |
| 173 } | 163 } |
| 174 break; | 164 break; |
| 175 case SkRegion::kIntersect_Op: | 165 case SkRegion::kIntersect_Op: |
| 176 // check if the shape intersected contains the entire bounds and
therefore can | 166 // check if the shape intersected contains the entire bounds and
therefore can |
| 177 // be skipped or it is outside the entire bounds and therefore m
akes the clip | 167 // be skipped or it is outside the entire bounds and therefore m
akes the clip |
| 178 // empty. | 168 // empty. |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 element = fElements.headIter().get(); | 413 element = fElements.headIter().get(); |
| 424 } | 414 } |
| 425 } | 415 } |
| 426 } | 416 } |
| 427 fRequiresAA = numAAElements > 0; | 417 fRequiresAA = numAAElements > 0; |
| 428 | 418 |
| 429 SkASSERT(InitialTriState::kUnknown != initialTriState); | 419 SkASSERT(InitialTriState::kUnknown != initialTriState); |
| 430 fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState); | 420 fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState); |
| 431 } | 421 } |
| 432 | 422 |
| 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 | |
| 507 inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) { | 423 inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) { |
| 508 SkASSERT(fHasIBounds); | 424 SkASSERT(fHasIBounds); |
| 509 if (!fIBounds.intersect(irect)) { | 425 if (!fIBounds.intersect(irect)) { |
| 510 fHasIBounds = false; | 426 fHasIBounds = false; |
| 511 fWindowRects.reset(); | |
| 512 fElements.reset(); | 427 fElements.reset(); |
| 513 fRequiresAA = false; | 428 fRequiresAA = false; |
| 514 fInitialState = InitialState::kAllOut; | 429 fInitialState = InitialState::kAllOut; |
| 515 return false; | 430 return false; |
| 516 } | 431 } |
| 517 return true; | 432 return true; |
| 518 } | 433 } |
| 519 | 434 |
| 520 //////////////////////////////////////////////////////////////////////////////// | 435 //////////////////////////////////////////////////////////////////////////////// |
| 521 // Create a 8-bit clip mask in alpha | 436 // Create a 8-bit clip mask in alpha |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 break; | 496 break; |
| 582 } | 497 } |
| 583 } | 498 } |
| 584 } | 499 } |
| 585 | 500 |
| 586 bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { | 501 bool GrReducedClip::drawAlphaClipMask(GrDrawContext* dc) const { |
| 587 // The texture may be larger than necessary, this rect represents the part o
f the texture | 502 // The texture may be larger than necessary, this rect represents the part o
f the texture |
| 588 // we populate with a rasterization of the clip. | 503 // we populate with a rasterization of the clip. |
| 589 GrFixedClip clip(SkIRect::MakeWH(fIBounds.width(), fIBounds.height())); | 504 GrFixedClip clip(SkIRect::MakeWH(fIBounds.width(), fIBounds.height())); |
| 590 | 505 |
| 591 if (!fWindowRects.empty()) { | |
| 592 clip.setWindowRectangles(fWindowRects, {fIBounds.left(), fIBounds.top()}
, | |
| 593 GrWindowRectsState::Mode::kExclusive); | |
| 594 } | |
| 595 | |
| 596 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 506 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
| 597 // clear the part that we care about. | 507 // clear the part that we care about. |
| 598 GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1
: 0; | 508 GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1
: 0; |
| 599 dc->drawContextPriv().clear(clip, initialCoverage, true); | 509 dc->drawContextPriv().clear(clip, initialCoverage, true); |
| 600 | 510 |
| 601 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip space. | 511 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip space. |
| 602 SkMatrix translate; | 512 SkMatrix translate; |
| 603 translate.setTranslate(SkIntToScalar(-fIBounds.left()), SkIntToScalar(-fIBou
nds.top())); | 513 translate.setTranslate(SkIntToScalar(-fIBounds.left()), SkIntToScalar(-fIBou
nds.top())); |
| 604 | 514 |
| 605 // walk through each clip element and perform its set op | 515 // walk through each clip element and perform its set op |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 } | 563 } |
| 654 | 564 |
| 655 //////////////////////////////////////////////////////////////////////////////// | 565 //////////////////////////////////////////////////////////////////////////////// |
| 656 // Create a 1-bit clip mask in the stencil buffer. | 566 // Create a 1-bit clip mask in the stencil buffer. |
| 657 | 567 |
| 658 class StencilClip final : public GrClip { | 568 class StencilClip final : public GrClip { |
| 659 public: | 569 public: |
| 660 StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} | 570 StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {} |
| 661 const GrFixedClip& fixedClip() const { return fFixedClip; } | 571 const GrFixedClip& fixedClip() const { return fFixedClip; } |
| 662 | 572 |
| 663 void setWindowRectangles(const GrWindowRectangles& windows, const SkIPoint&
origin, | |
| 664 GrWindowRectsState::Mode mode) { | |
| 665 fFixedClip.setWindowRectangles(windows, origin, mode); | |
| 666 } | |
| 667 | |
| 668 private: | 573 private: |
| 669 bool quickContains(const SkRect&) const override { | 574 bool quickContains(const SkRect&) const final { |
| 670 return false; | 575 return false; |
| 671 } | 576 } |
| 672 void getConservativeBounds(int width, int height, SkIRect* bounds, bool* iio
r) const override { | 577 void getConservativeBounds(int width, int height, SkIRect* devResult, bool*
iior) const final { |
| 673 fFixedClip.getConservativeBounds(width, height, bounds, iior); | 578 fFixedClip.getConservativeBounds(width, height, devResult, iior); |
| 674 } | 579 } |
| 675 bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override { | 580 bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const final { |
| 676 return false; | 581 return false; |
| 677 } | 582 } |
| 678 bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, | 583 bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA, |
| 679 bool hasUserStencilSettings, GrAppliedClip* out) const override { | 584 bool hasUserStencilSettings, GrAppliedClip* out) const final { |
| 680 if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSetti
ngs, out)) { | 585 if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSetti
ngs, out)) { |
| 681 return false; | 586 return false; |
| 682 } | 587 } |
| 683 out->addStencilClip(); | 588 out->addStencilClip(); |
| 684 return true; | 589 return true; |
| 685 } | 590 } |
| 686 | 591 |
| 687 GrFixedClip fFixedClip; | 592 GrFixedClip fFixedClip; |
| 688 | 593 |
| 689 typedef GrClip INHERITED; | 594 typedef GrClip INHERITED; |
| 690 }; | 595 }; |
| 691 | 596 |
| 692 bool GrReducedClip::drawStencilClipMask(GrContext* context, | 597 bool GrReducedClip::drawStencilClipMask(GrContext* context, |
| 693 GrDrawContext* drawContext, | 598 GrDrawContext* drawContext, |
| 694 const SkIPoint& clipOrigin) const { | 599 const SkIPoint& clipOrigin) const { |
| 695 // We set the current clip to the bounds so that our recursive draws are sci
ssored to them. | 600 // We set the current clip to the bounds so that our recursive draws are sci
ssored to them. |
| 696 StencilClip stencilClip(fIBounds.makeOffset(-clipOrigin.x(), -clipOrigin.y()
)); | 601 StencilClip stencilClip(fIBounds.makeOffset(-clipOrigin.x(), -clipOrigin.y()
)); |
| 697 | 602 |
| 698 if (!fWindowRects.empty()) { | |
| 699 stencilClip.setWindowRectangles(fWindowRects, clipOrigin, | |
| 700 GrWindowRectsState::Mode::kExclusive); | |
| 701 } | |
| 702 | |
| 703 bool initialState = InitialState::kAllIn == this->initialState(); | 603 bool initialState = InitialState::kAllIn == this->initialState(); |
| 704 drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), ini
tialState); | 604 drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), ini
tialState); |
| 705 | 605 |
| 706 // Set the matrix so that rendered clip elements are transformed from clip t
o stencil space. | 606 // Set the matrix so that rendered clip elements are transformed from clip t
o stencil space. |
| 707 SkMatrix viewMatrix; | 607 SkMatrix viewMatrix; |
| 708 viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipO
rigin.y())); | 608 viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipO
rigin.y())); |
| 709 | 609 |
| 710 // walk through each clip element and perform its set op | 610 // walk through each clip element and perform its set op |
| 711 // with the existing clip. | 611 // with the existing clip. |
| 712 for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { | 612 for (ElementList::Iter iter(fElements); iter.get(); iter.next()) { |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 // The view matrix is setup to do clip space -> stencil space tr
anslation, so | 737 // The view matrix is setup to do clip space -> stencil space tr
anslation, so |
| 838 // draw rect in clip space. | 738 // draw rect in clip space. |
| 839 drawContext->drawContextPriv().stencilRect(stencilClip, *pass, | 739 drawContext->drawContextPriv().stencilRect(stencilClip, *pass, |
| 840 false, viewMatrix, | 740 false, viewMatrix, |
| 841 SkRect::Make(fIBounds
)); | 741 SkRect::Make(fIBounds
)); |
| 842 } | 742 } |
| 843 } | 743 } |
| 844 } | 744 } |
| 845 return true; | 745 return true; |
| 846 } | 746 } |
| OLD | NEW |