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 |