Index: src/gpu/GrClipMaskManager.cpp |
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp |
index e24c759688ef2672af7528aa84a2355aac672a1f..96f4b209e385944584f1339d87bc5bdd57e6b82b 100644 |
--- a/src/gpu/GrClipMaskManager.cpp |
+++ b/src/gpu/GrClipMaskManager.cpp |
@@ -107,6 +107,106 @@ bool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) { |
return false; |
} |
+bool GrClipMaskManager::installClipEffects(const ElementList& elements, |
+ GrDrawState::AutoRestoreEffects* are, |
+ const SkVector& clipToRTOffset, |
+ const SkRect* drawBounds) { |
+ |
+ GrDrawState* drawState = fGpu->drawState(); |
+ SkRect boundsInClipSpace; |
+ if (NULL != drawBounds) { |
+ boundsInClipSpace = *drawBounds; |
+ boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); |
+ } |
+ |
+ are->set(drawState); |
+ GrRenderTarget* rt = drawState->getRenderTarget(); |
+ ElementList::Iter iter(elements); |
+ |
+ bool setARE = false; |
+ bool failed = false; |
+ |
+ while (NULL != iter.get()) { |
+ SkRegion::Op op = iter.get()->getOp(); |
+ bool invert; |
+ bool skip = false; |
+ switch (op) { |
+ case SkRegion::kReplace_Op: |
+ SkASSERT(iter.get() == elements.head()); |
+ // Fallthrough, handled same as intersect. |
+ case SkRegion::kIntersect_Op: |
+ invert = false; |
+ if (NULL != drawBounds && iter.get()->contains(boundsInClipSpace)) { |
+ skip = true; |
+ } |
+ break; |
+ case SkRegion::kDifference_Op: |
+ invert = true; |
+ // We don't currently have a cheap test for whether a rect is fully outside an |
+ // element's primitive, so don't attempt to set skip. |
+ break; |
+ default: |
+ failed = true; |
+ break; |
+ } |
+ if (failed) { |
+ break; |
+ } |
+ |
+ if (!skip) { |
+ GrEffectEdgeType edgeType; |
+ if (GR_AA_CLIP && iter.get()->isAA()) { |
+ if (rt->isMultisampled()) { |
+ // Coverage based AA clips don't place nicely with MSAA. |
+ failed = true; |
+ break; |
+ } |
+ edgeType = invert ? kInverseFillAA_GrEffectEdgeType : kFillAA_GrEffectEdgeType; |
+ } else { |
+ edgeType = invert ? kInverseFillBW_GrEffectEdgeType : kFillBW_GrEffectEdgeType; |
+ } |
+ SkAutoTUnref<GrEffectRef> effect; |
+ switch (iter.get()->getType()) { |
+ case SkClipStack::Element::kPath_Type: |
+ effect.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(), |
+ &clipToRTOffset)); |
+ break; |
+ case SkClipStack::Element::kRRect_Type: { |
+ SkRRect rrect = iter.get()->getRRect(); |
+ rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
+ effect.reset(GrRRectEffect::Create(edgeType, rrect)); |
+ break; |
+ } |
+ case SkClipStack::Element::kRect_Type: { |
+ SkRect rect = iter.get()->getRect(); |
+ rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
+ effect.reset(GrConvexPolyEffect::Create(edgeType, rect)); |
+ break; |
+ } |
+ default: |
+ break; |
+ } |
+ if (effect) { |
+ if (!setARE) { |
+ are->set(fGpu->drawState()); |
+ setARE = true; |
+ } |
+ fGpu->drawState()->addCoverageEffect(effect); |
+ } else { |
+ failed = true; |
+ break; |
+ } |
+ } |
+ iter.next(); |
+ } |
+ |
+ if (failed) { |
+ are->set(NULL); |
+ } |
+ |
+ return !failed; |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// sort out what kind of clip mask needs to be created: alpha, stencil, |
// scissor, or entirely software |
@@ -156,59 +256,27 @@ bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, |
return true; |
} |
- // If there is only one clip element we check whether the draw's bounds are contained |
- // fully within the clip. If not, we install an effect that handles the clip for some |
- // cases. |
- if (1 == elements.count() && SkRegion::kReplace_Op == elements.tail()->getOp()) { |
- if (NULL != devBounds) { |
- SkRect boundsInClipSpace = *devBounds; |
- boundsInClipSpace.offset(SkIntToScalar(clipDataIn->fOrigin.fX), |
- SkIntToScalar(clipDataIn->fOrigin.fY)); |
- if (elements.tail()->contains(boundsInClipSpace)) { |
- fGpu->disableScissor(); |
- this->setGpuStencil(); |
- return true; |
- } |
- } |
- Element::Type type = elements.tail()->getType(); |
- bool isAA = GR_AA_CLIP && elements.tail()->isAA(); |
- SkAutoTUnref<GrEffectRef> effect; |
- if (SkClipStack::Element::kPath_Type == type) { |
- const SkPath& path = elements.tail()->getPath(); |
- if (rt->isMultisampled()) { |
- // A coverage effect for AA clipping won't play nicely with MSAA. |
- if (!isAA) { |
- SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
- SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
- effect.reset(GrConvexPolyEffect::Create(kFillBW_GrEffectEdgeType, |
- path, &offset)); |
- } |
- } else { |
- SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
+ // An element count of 4 was chosen because of the common pattern in Blink of: |
+ // isect RR |
+ // diff RR |
+ // isect convex_poly |
+ // isect convex_poly |
+ // when drawing rounded div borders. This could probably be tuned based on a |
+ // configuration's relative costs of switching RTs to generate a mask vs |
+ // longer shaders. |
+ if (elements.count() <= 4) { |
+ SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
- GrEffectEdgeType type = isAA ? kFillAA_GrEffectEdgeType : kFillBW_GrEffectEdgeType; |
- effect.reset(GrConvexPolyEffect::Create(type, path, &offset)); |
- } |
- } else if (isAA && SkClipStack::Element::kRRect_Type == type && !rt->isMultisampled()) { |
- const SkRRect& rrect = elements.tail()->getRRect(); |
- effect.reset(GrRRectEffect::Create(kFillAA_GrEffectEdgeType, rrect)); |
- } else if (isAA && SkClipStack::Element::kRect_Type == type && !rt->isMultisampled()) { |
- // We only handle AA/non-MSAA rects here. Coverage effect AA isn't MSAA friendly and |
- // non-AA rect clips are handled by the scissor. |
- SkRect rect = elements.tail()->getRect(); |
- SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), |
- SkIntToScalar(-clipDataIn->fOrigin.fY) }; |
- rect.offset(offset); |
- effect.reset(GrConvexPolyEffect::Create(kFillAA_GrEffectEdgeType, rect)); |
- // This should never fail. |
- SkASSERT(effect); |
- } |
- if (effect) { |
- are->set(fGpu->drawState()); |
- fGpu->drawState()->addCoverageEffect(effect); |
+ if (elements.isEmpty() || |
+ this->installClipEffects(elements, are, clipToRTOffset, devBounds)) { |
SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
scissorSpaceIBounds.offset(-clipDataIn->fOrigin); |
- fGpu->enableScissor(scissorSpaceIBounds); |
+ if (NULL == devBounds || |
+ !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { |
+ fGpu->enableScissor(scissorSpaceIBounds); |
+ } else { |
+ fGpu->disableScissor(); |
+ } |
this->setGpuStencil(); |
return true; |
} |