| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2012 Google Inc. | 3 * Copyright 2012 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "GrClipMaskManager.h" | 9 #include "GrClipMaskManager.h" |
| 10 #include "GrAAConvexPathRenderer.h" | 10 #include "GrAAConvexPathRenderer.h" |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 bool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) { | 87 bool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) { |
| 88 | 88 |
| 89 // TODO: generalize this function so that when | 89 // TODO: generalize this function so that when |
| 90 // a clip gets complex enough it can just be done in SW regardless | 90 // a clip gets complex enough it can just be done in SW regardless |
| 91 // of whether it would invoke the GrSoftwarePathRenderer. | 91 // of whether it would invoke the GrSoftwarePathRenderer. |
| 92 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 92 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 93 | 93 |
| 94 for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { | 94 for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { |
| 95 const Element* element = iter.get(); | 95 const Element* element = iter.get(); |
| 96 // rects can always be drawn directly w/o using the software path | 96 // rects can always be drawn directly w/o using the software path |
| 97 // so only paths need to be checked | 97 // Skip rrects once we're drawing them directly. |
| 98 if (Element::kPath_Type == element->getType() && | 98 if (Element::kRect_Type != element->getType()) { |
| 99 path_needs_SW_renderer(this->getContext(), fGpu, | 99 SkPath path; |
| 100 element->getPath(), | 100 element->asPath(&path); |
| 101 stroke, | 101 if (path_needs_SW_renderer(this->getContext(), fGpu, path, stroke, e
lement->isAA())) { |
| 102 element->isAA())) { | 102 return true; |
| 103 return true; | 103 } |
| 104 } | 104 } |
| 105 } | 105 } |
| 106 return false; | 106 return false; |
| 107 } | 107 } |
| 108 | 108 |
| 109 //////////////////////////////////////////////////////////////////////////////// | 109 //////////////////////////////////////////////////////////////////////////////// |
| 110 // sort out what kind of clip mask needs to be created: alpha, stencil, | 110 // sort out what kind of clip mask needs to be created: alpha, stencil, |
| 111 // scissor, or entirely software | 111 // scissor, or entirely software |
| 112 bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, | 112 bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, |
| 113 GrDrawState::AutoRestoreEffects* are, | 113 GrDrawState::AutoRestoreEffects* are, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 if (NULL != devBounds) { | 162 if (NULL != devBounds) { |
| 163 SkRect boundsInClipSpace = *devBounds; | 163 SkRect boundsInClipSpace = *devBounds; |
| 164 boundsInClipSpace.offset(SkIntToScalar(clipDataIn->fOrigin.fX), | 164 boundsInClipSpace.offset(SkIntToScalar(clipDataIn->fOrigin.fX), |
| 165 SkIntToScalar(clipDataIn->fOrigin.fY)); | 165 SkIntToScalar(clipDataIn->fOrigin.fY)); |
| 166 if (elements.tail()->contains(boundsInClipSpace)) { | 166 if (elements.tail()->contains(boundsInClipSpace)) { |
| 167 fGpu->disableScissor(); | 167 fGpu->disableScissor(); |
| 168 this->setGpuStencil(); | 168 this->setGpuStencil(); |
| 169 return true; | 169 return true; |
| 170 } | 170 } |
| 171 } | 171 } |
| 172 Element::Type type = elements.tail()->getType(); |
| 173 bool isAA = GR_AA_CLIP && elements.tail()->isAA(); |
| 172 SkAutoTUnref<GrEffectRef> effect; | 174 SkAutoTUnref<GrEffectRef> effect; |
| 173 if (SkClipStack::Element::kPath_Type == elements.tail()->getType()) { | 175 if (SkClipStack::Element::kPath_Type == type) { |
| 174 const SkPath& path = elements.tail()->getPath(); | 176 const SkPath& path = elements.tail()->getPath(); |
| 175 bool isAA = GR_AA_CLIP && elements.tail()->isAA(); | |
| 176 if (rt->isMultisampled()) { | 177 if (rt->isMultisampled()) { |
| 177 // A coverage effect for AA clipping won't play nicely with MSAA
. | 178 // A coverage effect for AA clipping won't play nicely with MSAA
. |
| 178 if (!isAA) { | 179 if (!isAA) { |
| 179 SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), | 180 SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
| 180 SkIntToScalar(-clipDataIn->fOrigin.fY) }
; | 181 SkIntToScalar(-clipDataIn->fOrigin.fY) }
; |
| 181 effect.reset(GrConvexPolyEffect::Create(GrConvexPolyEffect::
kFillNoAA_EdgeType, | 182 effect.reset(GrConvexPolyEffect::Create(GrConvexPolyEffect::
kFillNoAA_EdgeType, |
| 182 path, &offset)); | 183 path, &offset)); |
| 183 } | 184 } |
| 184 } else { | 185 } else { |
| 185 SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), | 186 SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
| 186 SkIntToScalar(-clipDataIn->fOrigin.fY) }; | 187 SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
| 187 GrConvexPolyEffect::EdgeType type = isAA ? GrConvexPolyEffect::k
FillAA_EdgeType : | 188 GrConvexPolyEffect::EdgeType type = isAA ? GrConvexPolyEffect::k
FillAA_EdgeType : |
| 188 GrConvexPolyEffect::k
FillNoAA_EdgeType; | 189 GrConvexPolyEffect::k
FillNoAA_EdgeType; |
| 189 effect.reset(GrConvexPolyEffect::Create(type, path, &offset)); | 190 effect.reset(GrConvexPolyEffect::Create(type, path, &offset)); |
| 190 } | 191 } |
| 191 } else if (GR_AA_CLIP && elements.tail()->isAA() && !rt->isMultisampled(
)) { | 192 } else if (isAA && SkClipStack::Element::kRect_Type == type && !rt->isMu
ltisampled()) { |
| 192 // We only handle AA/non-MSAA rects here. Coverage effect AA isn't M
SAA friendly and | 193 // We only handle AA/non-MSAA rects here. Coverage effect AA isn't M
SAA friendly and |
| 193 // non-AA rect clips are handled by the scissor. | 194 // non-AA rect clips are handled by the scissor. |
| 194 SkASSERT(SkClipStack::Element::kRect_Type == elements.tail()->getTyp
e()); | |
| 195 SkRect rect = elements.tail()->getRect(); | 195 SkRect rect = elements.tail()->getRect(); |
| 196 SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), | 196 SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
| 197 SkIntToScalar(-clipDataIn->fOrigin.fY) }; | 197 SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
| 198 rect.offset(offset); | 198 rect.offset(offset); |
| 199 effect.reset(GrConvexPolyEffect::CreateForAAFillRect(rect)); | 199 effect.reset(GrConvexPolyEffect::CreateForAAFillRect(rect)); |
| 200 // This should never fail. | 200 // This should never fail. |
| 201 SkASSERT(effect); | 201 SkASSERT(effect); |
| 202 } | 202 } |
| 203 if (effect) { | 203 if (effect) { |
| 204 are->set(fGpu->drawState()); | 204 are->set(fGpu->drawState()); |
| 205 fGpu->drawState()->addCoverageEffect(effect); | 205 fGpu->drawState()->addCoverageEffect(effect); |
| 206 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 206 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 207 scissorSpaceIBounds.offset(-clipDataIn->fOrigin); | 207 scissorSpaceIBounds.offset(-clipDataIn->fOrigin); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 } | 325 } |
| 326 | 326 |
| 327 //////////////////////////////////////////////////////////////////////////////// | 327 //////////////////////////////////////////////////////////////////////////////// |
| 328 bool GrClipMaskManager::drawElement(GrTexture* target, | 328 bool GrClipMaskManager::drawElement(GrTexture* target, |
| 329 const SkClipStack::Element* element, | 329 const SkClipStack::Element* element, |
| 330 GrPathRenderer* pr) { | 330 GrPathRenderer* pr) { |
| 331 GrDrawState* drawState = fGpu->drawState(); | 331 GrDrawState* drawState = fGpu->drawState(); |
| 332 | 332 |
| 333 drawState->setRenderTarget(target->asRenderTarget()); | 333 drawState->setRenderTarget(target->asRenderTarget()); |
| 334 | 334 |
| 335 // TODO: Draw rrects directly here. |
| 335 switch (element->getType()) { | 336 switch (element->getType()) { |
| 337 case Element::kEmpty_Type: |
| 338 SkDEBUGFAIL("Should never get here with an empty element."); |
| 339 break; |
| 336 case Element::kRect_Type: | 340 case Element::kRect_Type: |
| 337 // TODO: Do rects directly to the accumulator using a aa-rect GrEffe
ct that covers the | 341 // TODO: Do rects directly to the accumulator using a aa-rect GrEffe
ct that covers the |
| 338 // entire mask bounds and writes 0 outside the rect. | 342 // entire mask bounds and writes 0 outside the rect. |
| 339 if (element->isAA()) { | 343 if (element->isAA()) { |
| 340 getContext()->getAARectRenderer()->fillAARect(fGpu, | 344 getContext()->getAARectRenderer()->fillAARect(fGpu, |
| 341 fGpu, | 345 fGpu, |
| 342 element->getRect()
, | 346 element->getRect()
, |
| 343 SkMatrix::I(), | 347 SkMatrix::I(), |
| 344 element->getRect()
, | 348 element->getRect()
, |
| 345 false); | 349 false); |
| 346 } else { | 350 } else { |
| 347 fGpu->drawSimpleRect(element->getRect(), NULL); | 351 fGpu->drawSimpleRect(element->getRect(), NULL); |
| 348 } | 352 } |
| 349 return true; | 353 return true; |
| 350 case Element::kPath_Type: { | 354 default: { |
| 351 SkTCopyOnFirstWrite<SkPath> path(element->getPath()); | 355 SkPath path; |
| 352 if (path->isInverseFillType()) { | 356 element->asPath(&path); |
| 353 path.writable()->toggleInverseFillType(); | 357 if (path.isInverseFillType()) { |
| 358 path.toggleInverseFillType(); |
| 354 } | 359 } |
| 355 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 360 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 356 if (NULL == pr) { | 361 if (NULL == pr) { |
| 357 GrPathRendererChain::DrawType type; | 362 GrPathRendererChain::DrawType type; |
| 358 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : | 363 type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_Dr
awType : |
| 359 GrPathRendererChain::kColor_DrawType; | 364 GrPathRendererChain::kColor_DrawType; |
| 360 pr = this->getContext()->getPathRenderer(*path, stroke, fGpu, fa
lse, type); | 365 pr = this->getContext()->getPathRenderer(path, stroke, fGpu, fal
se, type); |
| 361 } | 366 } |
| 362 if (NULL == pr) { | 367 if (NULL == pr) { |
| 363 return false; | 368 return false; |
| 364 } | 369 } |
| 365 pr->drawPath(element->getPath(), stroke, fGpu, element->isAA()); | 370 pr->drawPath(path, stroke, fGpu, element->isAA()); |
| 366 break; | 371 break; |
| 367 } | 372 } |
| 368 default: | |
| 369 // something is wrong if we're trying to draw an empty element. | |
| 370 GrCrash("Unexpected element type"); | |
| 371 return false; | |
| 372 } | 373 } |
| 373 return true; | 374 return true; |
| 374 } | 375 } |
| 375 | 376 |
| 376 bool GrClipMaskManager::canStencilAndDrawElement(GrTexture* target, | 377 bool GrClipMaskManager::canStencilAndDrawElement(GrTexture* target, |
| 377 const SkClipStack::Element* ele
ment, | 378 const SkClipStack::Element* ele
ment, |
| 378 GrPathRenderer** pr) { | 379 GrPathRenderer** pr) { |
| 379 GrDrawState* drawState = fGpu->drawState(); | 380 GrDrawState* drawState = fGpu->drawState(); |
| 380 drawState->setRenderTarget(target->asRenderTarget()); | 381 drawState->setRenderTarget(target->asRenderTarget()); |
| 381 | 382 |
| 382 switch (element->getType()) { | 383 if (Element::kRect_Type == element->getType()) { |
| 383 case Element::kRect_Type: | 384 return true; |
| 384 return true; | 385 } else { |
| 385 case Element::kPath_Type: { | 386 // We shouldn't get here with an empty clip element. |
| 386 SkTCopyOnFirstWrite<SkPath> path(element->getPath()); | 387 SkASSERT(Element::kEmpty_Type != element->getType()); |
| 387 if (path->isInverseFillType()) { | 388 SkPath path; |
| 388 path.writable()->toggleInverseFillType(); | 389 element->asPath(&path); |
| 389 } | 390 if (path.isInverseFillType()) { |
| 390 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 391 path.toggleInverseFillType(); |
| 391 GrPathRendererChain::DrawType type = element->isAA() ? | |
| 392 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : | |
| 393 GrPathRendererChain::kStencilAndColor_DrawType; | |
| 394 *pr = this->getContext()->getPathRenderer(*path, stroke, fGpu, false
, type); | |
| 395 return NULL != *pr; | |
| 396 } | 392 } |
| 397 default: | 393 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 398 // something is wrong if we're trying to draw an empty element. | 394 GrPathRendererChain::DrawType type = element->isAA() ? |
| 399 GrCrash("Unexpected element type"); | 395 GrPathRendererChain::kStencilAndColorAntiAlias_DrawType : |
| 400 return false; | 396 GrPathRendererChain::kStencilAndColor_DrawType; |
| 397 *pr = this->getContext()->getPathRenderer(path, stroke, fGpu, false, typ
e); |
| 398 return NULL != *pr; |
| 401 } | 399 } |
| 402 } | 400 } |
| 403 | 401 |
| 404 void GrClipMaskManager::mergeMask(GrTexture* dstMask, | 402 void GrClipMaskManager::mergeMask(GrTexture* dstMask, |
| 405 GrTexture* srcMask, | 403 GrTexture* srcMask, |
| 406 SkRegion::Op op, | 404 SkRegion::Op op, |
| 407 const SkIRect& dstBound, | 405 const SkIRect& dstBound, |
| 408 const SkIRect& srcBound) { | 406 const SkIRect& srcBound) { |
| 409 GrDrawState::AutoViewMatrixRestore avmr; | 407 GrDrawState::AutoViewMatrixRestore avmr; |
| 410 GrDrawState* drawState = fGpu->drawState(); | 408 GrDrawState* drawState = fGpu->drawState(); |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 | 691 |
| 694 // This will be used to determine whether the clip shape can be rend
ered into the | 692 // This will be used to determine whether the clip shape can be rend
ered into the |
| 695 // stencil with arbitrary stencil settings. | 693 // stencil with arbitrary stencil settings. |
| 696 GrPathRenderer::StencilSupport stencilSupport; | 694 GrPathRenderer::StencilSupport stencilSupport; |
| 697 | 695 |
| 698 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | 696 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); |
| 699 | 697 |
| 700 SkRegion::Op op = element->getOp(); | 698 SkRegion::Op op = element->getOp(); |
| 701 | 699 |
| 702 GrPathRenderer* pr = NULL; | 700 GrPathRenderer* pr = NULL; |
| 703 SkTCopyOnFirstWrite<SkPath> clipPath; | 701 SkPath clipPath; |
| 704 if (Element::kRect_Type == element->getType()) { | 702 if (Element::kRect_Type == element->getType()) { |
| 705 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; | 703 stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; |
| 706 fillInverted = false; | 704 fillInverted = false; |
| 707 } else { | 705 } else { |
| 708 SkASSERT(Element::kPath_Type == element->getType()); | 706 element->asPath(&clipPath); |
| 709 clipPath.init(element->getPath()); | 707 fillInverted = clipPath.isInverseFillType(); |
| 710 fillInverted = clipPath->isInverseFillType(); | |
| 711 if (fillInverted) { | 708 if (fillInverted) { |
| 712 clipPath.writable()->toggleInverseFillType(); | 709 clipPath.toggleInverseFillType(); |
| 713 } | 710 } |
| 714 pr = this->getContext()->getPathRenderer(*clipPath, | 711 pr = this->getContext()->getPathRenderer(clipPath, |
| 715 stroke, | 712 stroke, |
| 716 fGpu, | 713 fGpu, |
| 717 false, | 714 false, |
| 718 GrPathRendererChain::kS
tencilOnly_DrawType, | 715 GrPathRendererChain::kS
tencilOnly_DrawType, |
| 719 &stencilSupport); | 716 &stencilSupport); |
| 720 if (NULL == pr) { | 717 if (NULL == pr) { |
| 721 return false; | 718 return false; |
| 722 } | 719 } |
| 723 } | 720 } |
| 724 | 721 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 745 kIncClamp_StencilOp, | 742 kIncClamp_StencilOp, |
| 746 kAlways_StencilFunc, | 743 kAlways_StencilFunc, |
| 747 0xffff, | 744 0xffff, |
| 748 0x0000, | 745 0x0000, |
| 749 0xffff); | 746 0xffff); |
| 750 SET_RANDOM_COLOR | 747 SET_RANDOM_COLOR |
| 751 if (Element::kRect_Type == element->getType()) { | 748 if (Element::kRect_Type == element->getType()) { |
| 752 *drawState->stencil() = gDrawToStencil; | 749 *drawState->stencil() = gDrawToStencil; |
| 753 fGpu->drawSimpleRect(element->getRect(), NULL); | 750 fGpu->drawSimpleRect(element->getRect(), NULL); |
| 754 } else { | 751 } else { |
| 755 SkASSERT(Element::kPath_Type == element->getType()); | 752 if (!clipPath.isEmpty()) { |
| 756 if (!clipPath->isEmpty()) { | |
| 757 if (canRenderDirectToStencil) { | 753 if (canRenderDirectToStencil) { |
| 758 *drawState->stencil() = gDrawToStencil; | 754 *drawState->stencil() = gDrawToStencil; |
| 759 pr->drawPath(*clipPath, stroke, fGpu, false); | 755 pr->drawPath(clipPath, stroke, fGpu, false); |
| 760 } else { | 756 } else { |
| 761 pr->stencilPath(*clipPath, stroke, fGpu); | 757 pr->stencilPath(clipPath, stroke, fGpu); |
| 762 } | 758 } |
| 763 } | 759 } |
| 764 } | 760 } |
| 765 } | 761 } |
| 766 | 762 |
| 767 // now we modify the clip bit by rendering either the clip | 763 // now we modify the clip bit by rendering either the clip |
| 768 // element directly or a bounding rect of the entire clip. | 764 // element directly or a bounding rect of the entire clip. |
| 769 drawState->enableState(GrGpu::kModifyStencilClip_StateBit); | 765 drawState->enableState(GrGpu::kModifyStencilClip_StateBit); |
| 770 for (int p = 0; p < passes; ++p) { | 766 for (int p = 0; p < passes; ++p) { |
| 771 *drawState->stencil() = stencilSettings[p]; | 767 *drawState->stencil() = stencilSettings[p]; |
| 772 if (canDrawDirectToClip) { | 768 if (canDrawDirectToClip) { |
| 773 if (Element::kRect_Type == element->getType()) { | 769 if (Element::kRect_Type == element->getType()) { |
| 774 SET_RANDOM_COLOR | 770 SET_RANDOM_COLOR |
| 775 fGpu->drawSimpleRect(element->getRect(), NULL); | 771 fGpu->drawSimpleRect(element->getRect(), NULL); |
| 776 } else { | 772 } else { |
| 777 SkASSERT(Element::kPath_Type == element->getType()); | |
| 778 SET_RANDOM_COLOR | 773 SET_RANDOM_COLOR |
| 779 pr->drawPath(*clipPath, stroke, fGpu, false); | 774 pr->drawPath(clipPath, stroke, fGpu, false); |
| 780 } | 775 } |
| 781 } else { | 776 } else { |
| 782 SET_RANDOM_COLOR | 777 SET_RANDOM_COLOR |
| 783 // The view matrix is setup to do clip space -> stencil spac
e translation, so | 778 // The view matrix is setup to do clip space -> stencil spac
e translation, so |
| 784 // draw rect in clip space. | 779 // draw rect in clip space. |
| 785 fGpu->drawSimpleRect(SkRect::Make(clipSpaceIBounds), NULL); | 780 fGpu->drawSimpleRect(SkRect::Make(clipSpaceIBounds), NULL); |
| 786 } | 781 } |
| 787 } | 782 } |
| 788 } | 783 } |
| 789 } | 784 } |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1091 | 1086 |
| 1092 // TODO: dynamically attach a stencil buffer | 1087 // TODO: dynamically attach a stencil buffer |
| 1093 int stencilBits = 0; | 1088 int stencilBits = 0; |
| 1094 GrStencilBuffer* stencilBuffer = | 1089 GrStencilBuffer* stencilBuffer = |
| 1095 drawState.getRenderTarget()->getStencilBuffer(); | 1090 drawState.getRenderTarget()->getStencilBuffer(); |
| 1096 if (NULL != stencilBuffer) { | 1091 if (NULL != stencilBuffer) { |
| 1097 stencilBits = stencilBuffer->bits(); | 1092 stencilBits = stencilBuffer->bits(); |
| 1098 this->adjustStencilParams(settings, clipMode, stencilBits); | 1093 this->adjustStencilParams(settings, clipMode, stencilBits); |
| 1099 } | 1094 } |
| 1100 } | 1095 } |
| OLD | NEW |