OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 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 "GrClipMaskManager.h" | 8 #include "GrClipMaskManager.h" |
9 #include "GrCaps.h" | 9 #include "GrCaps.h" |
10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
(...skipping 28 matching lines...) Expand all Loading... |
39 | 39 |
40 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); | 40 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); |
41 return GrTextureDomainEffect::Create(result, | 41 return GrTextureDomainEffect::Create(result, |
42 mat, | 42 mat, |
43 GrTextureDomain::MakeTexelDomain(result
, domainTexels), | 43 GrTextureDomain::MakeTexelDomain(result
, domainTexels), |
44 GrTextureDomain::kDecal_Mode, | 44 GrTextureDomain::kDecal_Mode, |
45 GrTextureParams::kNone_FilterMode, | 45 GrTextureParams::kNone_FilterMode, |
46 kDevice_GrCoordSet); | 46 kDevice_GrCoordSet); |
47 } | 47 } |
48 | 48 |
49 // Does the path in 'element' require SW rendering? If so, return true (and, | |
50 // optionally, set 'prOut' to NULL. If not, return false (and, optionally, set | |
51 // 'prOut' to the non-SW path renderer that will do the job). | |
52 static bool path_needs_SW_renderer(GrContext* context, | 49 static bool path_needs_SW_renderer(GrContext* context, |
53 const GrPipelineBuilder& pipelineBuilder, | 50 const GrPipelineBuilder& pipelineBuilder, |
54 const SkMatrix& viewMatrix, | 51 const SkMatrix& viewMatrix, |
55 const Element* element, | 52 const SkPath& origPath, |
56 GrPathRenderer** prOut, | 53 const GrStrokeInfo& stroke, |
57 bool needsStencil) { | 54 bool doAA) { |
58 if (Element::kRect_Type == element->getType()) { | 55 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp b
uffer |
59 // rects can always be drawn directly w/o using the software path | 56 SkTCopyOnFirstWrite<SkPath> path(origPath); |
60 // TODO: skip rrects once we're drawing them directly. | 57 if (path->isInverseFillType()) { |
61 return false; | 58 path.writable()->toggleInverseFillType(); |
62 } else { | 59 } |
63 // We shouldn't get here with an empty clip element. | 60 // last (false) parameter disallows use of the SW path renderer |
64 SkASSERT(Element::kEmpty_Type != element->getType()); | 61 GrPathRendererChain::DrawType type = doAA ? |
| 62 GrPathRendererChain::kColorAntiAlias_Dr
awType : |
| 63 GrPathRendererChain::kColor_DrawType; |
65 | 64 |
66 // the gpu alpha mask will draw the inverse paths as non-inverse to a te
mp buffer | 65 return nullptr == context->getPathRenderer(&pipelineBuilder, viewMatrix, *pa
th, stroke, |
67 SkPath path; | 66 false, type); |
68 element->asPath(&path); | |
69 if (path.isInverseFillType()) { | |
70 path.toggleInverseFillType(); | |
71 } | |
72 GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); | |
73 | |
74 GrPathRendererChain::DrawType type; | |
75 | |
76 if (needsStencil) { | |
77 type = element->isAA() | |
78 ? GrPathRendererChain::kStencilAndColorAntiAlias_Dra
wType | |
79 : GrPathRendererChain::kStencilAndColor_DrawType; | |
80 } else { | |
81 type = element->isAA() | |
82 ? GrPathRendererChain::kColorAntiAlias_DrawType | |
83 : GrPathRendererChain::kColor_DrawType; | |
84 } | |
85 | |
86 // the 'false' parameter disallows use of the SW path renderer | |
87 GrPathRenderer* pr = context->getPathRenderer(pipelineBuilder, viewMatri
x, path, | |
88 stroke, false, type); | |
89 if (prOut) { | |
90 *prOut = pr; | |
91 } | |
92 return SkToBool(!pr); | |
93 } | |
94 } | |
95 | |
96 // Determines whether it is possible to draw the element to both the stencil buf
fer and the | |
97 // alpha mask simultaneously. If so and the element is a path a compatible path
renderer is | |
98 // also returned. | |
99 static bool can_stencil_and_draw_element(GrContext* context, | |
100 GrPipelineBuilder* pipelineBuilder, | |
101 GrTexture* texture, | |
102 const SkMatrix& viewMatrix, | |
103 const SkClipStack::Element* element, | |
104 GrPathRenderer** pr) { | |
105 pipelineBuilder->setRenderTarget(texture->asRenderTarget()); | |
106 | |
107 static const bool kNeedsStencil = true; | |
108 return !path_needs_SW_renderer(context, | |
109 *pipelineBuilder, | |
110 viewMatrix, | |
111 element, | |
112 pr, | |
113 kNeedsStencil); | |
114 } | 67 } |
115 | 68 |
116 GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) | 69 GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) |
117 : fDrawTarget(drawTarget) | 70 : fDrawTarget(drawTarget) |
118 , fClipMode(kIgnoreClip_StencilClipMode) { | 71 , fClipMode(kIgnoreClip_StencilClipMode) { |
119 } | 72 } |
120 | 73 |
121 GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().con
text(); } | 74 GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().con
text(); } |
122 | 75 |
123 /* | 76 /* |
124 * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 77 * This method traverses the clip stack to see if the GrSoftwarePathRenderer |
125 * will be used on any element. If so, it returns true to indicate that the | 78 * will be used on any element. If so, it returns true to indicate that the |
126 * entire clip should be rendered in SW and then uploaded en masse to the gpu. | 79 * entire clip should be rendered in SW and then uploaded en masse to the gpu. |
127 */ | 80 */ |
128 bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder, | 81 bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder, |
129 const SkVector& clipToMaskOffset, | 82 const SkVector& clipToMaskOffset, |
130 const GrReducedClip::ElementList& elements
) { | 83 const GrReducedClip::ElementList& elements
) { |
131 // TODO: generalize this function so that when | 84 // TODO: generalize this function so that when |
132 // a clip gets complex enough it can just be done in SW regardless | 85 // a clip gets complex enough it can just be done in SW regardless |
133 // of whether it would invoke the GrSoftwarePathRenderer. | 86 // of whether it would invoke the GrSoftwarePathRenderer. |
| 87 GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); |
134 | 88 |
135 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 89 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
136 // space. | 90 // space. |
137 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 91 SkMatrix translate; |
| 92 translate.setTranslate(clipToMaskOffset); |
138 | 93 |
139 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { | 94 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { |
140 const Element* element = iter.get(); | 95 const Element* element = iter.get(); |
141 | 96 // rects can always be drawn directly w/o using the software path |
142 SkRegion::Op op = element->getOp(); | 97 // Skip rrects once we're drawing them directly. |
143 bool invert = element->isInverseFilled(); | 98 if (Element::kRect_Type != element->getType()) { |
144 bool needsStencil = invert || | 99 SkPath path; |
145 SkRegion::kIntersect_Op == op || SkRegion::kReverseD
ifference_Op == op; | 100 element->asPath(&path); |
146 | 101 if (path_needs_SW_renderer(this->getContext(), pipelineBuilder, tran
slate, |
147 if (path_needs_SW_renderer(this->getContext(), pipelineBuilder, translat
e, | 102 path, stroke, element->isAA())) { |
148 element, nullptr, needsStencil)) { | 103 return true; |
149 return true; | 104 } |
150 } | 105 } |
151 } | 106 } |
152 return false; | 107 return false; |
153 } | 108 } |
154 | 109 |
155 bool GrClipMaskManager::getAnalyticClipProcessor(const GrReducedClip::ElementLis
t& elements, | 110 bool GrClipMaskManager::getAnalyticClipProcessor(const GrReducedClip::ElementLis
t& elements, |
156 bool abortIfAA, | 111 bool abortIfAA, |
157 SkVector& clipToRTOffset, | 112 SkVector& clipToRTOffset, |
158 const SkRect* drawBounds, | 113 const SkRect* drawBounds, |
159 const GrFragmentProcessor** res
ultFP) { | 114 const GrFragmentProcessor** res
ultFP) { |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 element->asPath(&path); | 405 element->asPath(&path); |
451 path.setIsVolatile(true); | 406 path.setIsVolatile(true); |
452 if (path.isInverseFillType()) { | 407 if (path.isInverseFillType()) { |
453 path.toggleInverseFillType(); | 408 path.toggleInverseFillType(); |
454 } | 409 } |
455 GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); | 410 GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); |
456 if (nullptr == pr) { | 411 if (nullptr == pr) { |
457 GrPathRendererChain::DrawType type; | 412 GrPathRendererChain::DrawType type; |
458 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : | 413 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : |
459 GrPathRendererChain::kColor_DrawType; | 414 GrPathRendererChain::kColor_DrawType; |
460 pr = this->getContext()->getPathRenderer(*pipelineBuilder, viewM
atrix, | 415 pr = this->getContext()->getPathRenderer(pipelineBuilder, viewMa
trix, |
461 path, stroke, false, ty
pe); | 416 path, stroke, false, ty
pe); |
462 } | 417 } |
463 if (nullptr == pr) { | 418 if (nullptr == pr) { |
464 return false; | 419 return false; |
465 } | 420 } |
466 GrPathRenderer::DrawPathArgs args; | 421 GrPathRenderer::DrawPathArgs args; |
467 args.fTarget = fDrawTarget; | 422 args.fTarget = fDrawTarget; |
468 args.fResourceProvider = this->getContext()->resourceProvider(); | 423 args.fResourceProvider = this->getContext()->resourceProvider(); |
469 args.fPipelineBuilder = pipelineBuilder; | 424 args.fPipelineBuilder = pipelineBuilder; |
470 args.fColor = color; | 425 args.fColor = color; |
471 args.fViewMatrix = &viewMatrix; | 426 args.fViewMatrix = &viewMatrix; |
472 args.fPath = &path; | 427 args.fPath = &path; |
473 args.fStroke = &stroke; | 428 args.fStroke = &stroke; |
474 args.fAntiAlias = element->isAA(); | 429 args.fAntiAlias = element->isAA(); |
475 pr->drawPath(args); | 430 pr->drawPath(args); |
476 break; | 431 break; |
477 } | 432 } |
478 } | 433 } |
479 return true; | 434 return true; |
480 } | 435 } |
481 | 436 |
| 437 bool GrClipMaskManager::canStencilAndDrawElement(GrPipelineBuilder* pipelineBuil
der, |
| 438 GrTexture* target, |
| 439 GrPathRenderer** pr, |
| 440 const SkClipStack::Element* ele
ment) { |
| 441 pipelineBuilder->setRenderTarget(target->asRenderTarget()); |
| 442 |
| 443 if (Element::kRect_Type == element->getType()) { |
| 444 return true; |
| 445 } else { |
| 446 // We shouldn't get here with an empty clip element. |
| 447 SkASSERT(Element::kEmpty_Type != element->getType()); |
| 448 SkPath path; |
| 449 element->asPath(&path); |
| 450 if (path.isInverseFillType()) { |
| 451 path.toggleInverseFillType(); |
| 452 } |
| 453 GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); |
| 454 GrPathRendererChain::DrawType type = element->isAA() ? |
| 455 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : |
| 456 GrPathRendererChain::kStencilAndColor_DrawType; |
| 457 *pr = this->getContext()->getPathRenderer(pipelineBuilder, SkMatrix::I()
, path, |
| 458 stroke, false, type); |
| 459 return SkToBool(*pr); |
| 460 } |
| 461 } |
| 462 |
482 void GrClipMaskManager::mergeMask(GrPipelineBuilder* pipelineBuilder, | 463 void GrClipMaskManager::mergeMask(GrPipelineBuilder* pipelineBuilder, |
483 GrTexture* dstMask, | 464 GrTexture* dstMask, |
484 GrTexture* srcMask, | 465 GrTexture* srcMask, |
485 SkRegion::Op op, | 466 SkRegion::Op op, |
486 const SkIRect& dstBound, | 467 const SkIRect& dstBound, |
487 const SkIRect& srcBound) { | 468 const SkIRect& srcBound) { |
488 pipelineBuilder->setRenderTarget(dstMask->asRenderTarget()); | 469 pipelineBuilder->setRenderTarget(dstMask->asRenderTarget()); |
489 | 470 |
490 // We want to invert the coverage here | 471 // We want to invert the coverage here |
491 set_coverage_drawing_xpf(op, false, pipelineBuilder); | 472 set_coverage_drawing_xpf(op, false, pipelineBuilder); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 SkAutoTUnref<GrTexture> texture(this->createCachedMask( | 548 SkAutoTUnref<GrTexture> texture(this->createCachedMask( |
568 clipSpaceIBounds.width(), clipSpaceIBounds.height(), key, true)); | 549 clipSpaceIBounds.width(), clipSpaceIBounds.height(), key, true)); |
569 | 550 |
570 // There's no texture in the cache. Let's try to allocate it then. | 551 // There's no texture in the cache. Let's try to allocate it then. |
571 if (!texture) { | 552 if (!texture) { |
572 return nullptr; | 553 return nullptr; |
573 } | 554 } |
574 | 555 |
575 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 556 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
576 // space. | 557 // space. |
577 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 558 SkMatrix translate; |
| 559 translate.setTranslate(clipToMaskOffset); |
578 | 560 |
579 // The texture may be larger than necessary, this rect represents the part o
f the texture | 561 // The texture may be larger than necessary, this rect represents the part o
f the texture |
580 // we populate with a rasterization of the clip. | 562 // we populate with a rasterization of the clip. |
581 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 563 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); |
582 | 564 |
583 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 565 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
584 // clear the part that we care about. | 566 // clear the part that we care about. |
585 fDrawTarget->clear(&maskSpaceIBounds, | 567 fDrawTarget->clear(&maskSpaceIBounds, |
586 GrReducedClip::kAllIn_InitialState == initialState ? 0xff
ffffff : 0x00000000, | 568 GrReducedClip::kAllIn_InitialState == initialState ? 0xff
ffffff : 0x00000000, |
587 true, | 569 true, |
588 texture->asRenderTarget()); | 570 texture->asRenderTarget()); |
589 | 571 |
590 // When we use the stencil in the below loop it is important to have this cl
ip installed. | 572 // When we use the stencil in the below loop it is important to have this cl
ip installed. |
591 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first | 573 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first |
592 // pass must not set values outside of this bounds or stencil values outside
the rect won't be | 574 // pass must not set values outside of this bounds or stencil values outside
the rect won't be |
593 // cleared. | 575 // cleared. |
594 GrClip clip(maskSpaceIBounds); | 576 GrClip clip(maskSpaceIBounds); |
595 SkAutoTUnref<GrTexture> temp; | 577 SkAutoTUnref<GrTexture> temp; |
596 | 578 |
597 // walk through each clip element and perform its set op | 579 // walk through each clip element and perform its set op |
598 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { | 580 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { |
599 const Element* element = iter.get(); | 581 const Element* element = iter.get(); |
600 SkRegion::Op op = element->getOp(); | 582 SkRegion::Op op = element->getOp(); |
601 bool invert = element->isInverseFilled(); | 583 bool invert = element->isInverseFilled(); |
602 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | 584 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { |
603 GrPipelineBuilder pipelineBuilder; | 585 GrPipelineBuilder pipelineBuilder; |
604 | 586 |
605 pipelineBuilder.setClip(clip); | 587 pipelineBuilder.setClip(clip); |
606 GrPathRenderer* pr = nullptr; | 588 GrPathRenderer* pr = nullptr; |
607 bool useTemp = !can_stencil_and_draw_element(this->getContext(), &pi
pelineBuilder, | 589 bool useTemp = !this->canStencilAndDrawElement(&pipelineBuilder, tex
ture, &pr, element); |
608 texture, translate, ele
ment, &pr); | |
609 GrTexture* dst; | 590 GrTexture* dst; |
610 // This is the bounds of the clip element in the space of the alpha-
mask. The temporary | 591 // This is the bounds of the clip element in the space of the alpha-
mask. The temporary |
611 // mask buffer can be substantially larger than the actually clip st
ack element. We | 592 // mask buffer can be substantially larger than the actually clip st
ack element. We |
612 // touch the minimum number of pixels necessary and use decal mode t
o combine it with | 593 // touch the minimum number of pixels necessary and use decal mode t
o combine it with |
613 // the accumulator. | 594 // the accumulator. |
614 SkIRect maskSpaceElementIBounds; | 595 SkIRect maskSpaceElementIBounds; |
615 | 596 |
616 SkASSERT(!useTemp); | |
617 | |
618 if (useTemp) { | 597 if (useTemp) { |
619 if (invert) { | 598 if (invert) { |
620 maskSpaceElementIBounds = maskSpaceIBounds; | 599 maskSpaceElementIBounds = maskSpaceIBounds; |
621 } else { | 600 } else { |
622 SkRect elementBounds = element->getBounds(); | 601 SkRect elementBounds = element->getBounds(); |
623 elementBounds.offset(clipToMaskOffset); | 602 elementBounds.offset(clipToMaskOffset); |
624 elementBounds.roundOut(&maskSpaceElementIBounds); | 603 elementBounds.roundOut(&maskSpaceElementIBounds); |
625 } | 604 } |
626 | 605 |
627 if (!temp) { | 606 if (!temp) { |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 SkPath clipPath; | 752 SkPath clipPath; |
774 if (Element::kRect_Type == element->getType()) { | 753 if (Element::kRect_Type == element->getType()) { |
775 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; | 754 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; |
776 fillInverted = false; | 755 fillInverted = false; |
777 } else { | 756 } else { |
778 element->asPath(&clipPath); | 757 element->asPath(&clipPath); |
779 fillInverted = clipPath.isInverseFillType(); | 758 fillInverted = clipPath.isInverseFillType(); |
780 if (fillInverted) { | 759 if (fillInverted) { |
781 clipPath.toggleInverseFillType(); | 760 clipPath.toggleInverseFillType(); |
782 } | 761 } |
783 pr = this->getContext()->getPathRenderer(pipelineBuilder, | 762 pr = this->getContext()->getPathRenderer(&pipelineBuilder, |
784 viewMatrix, | 763 viewMatrix, |
785 clipPath, | 764 clipPath, |
786 stroke, | 765 stroke, |
787 false, | 766 false, |
788 GrPathRendererChain::kS
tencilOnly_DrawType, | 767 GrPathRendererChain::kS
tencilOnly_DrawType, |
789 &stencilSupport); | 768 &stencilSupport); |
790 if (nullptr == pr) { | 769 if (nullptr == pr) { |
791 return false; | 770 return false; |
792 } | 771 } |
793 } | 772 } |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1136 | 1115 |
1137 //////////////////////////////////////////////////////////////////////////////// | 1116 //////////////////////////////////////////////////////////////////////////////// |
1138 | 1117 |
1139 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc
ilAttachment, | 1118 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc
ilAttachment, |
1140 GrStencilSettings* settings) { | 1119 GrStencilSettings* settings) { |
1141 if (stencilAttachment) { | 1120 if (stencilAttachment) { |
1142 int stencilBits = stencilAttachment->bits(); | 1121 int stencilBits = stencilAttachment->bits(); |
1143 this->adjustStencilParams(settings, fClipMode, stencilBits); | 1122 this->adjustStencilParams(settings, fClipMode, stencilBits); |
1144 } | 1123 } |
1145 } | 1124 } |
OLD | NEW |