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