bool GrClipMaskManager::installClipEffects(GrPipelineBuilder* pipelineBuilder, GrPipelineBuilder::AutoRestoreFragmentProcessors* arfp, const GrReducedClip::ElementList& elements, const SkVector& clipToRTOffset, const SkRect* drawBounds) { SkRect boundsInClipSpace; if (drawBounds) { boundsInClipSpace = *drawBounds; boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); } arfp->set(pipelineBuilder); GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); GrReducedClip::ElementList::Iter iter(elements); bool failed = false; while (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 (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) { GrPrimitiveEdgeType edgeType; if (iter.get()->isAA()) { if (rt->isMultisampled()) { // Coverage based AA clips don't place nicely with MSAA. failed = true; break; } edgeType = invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType; } else { edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType; } SkAutoTUnref<GrFragmentProcessor> fp; switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: fp.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); fp.reset(GrRRectEffect::Create(edgeType, rrect)); break; } case SkClipStack::Element::kRect_Type: { SkRect rect = iter.get()->getRect(); rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); break; } default: break; } if (fp) { pipelineBuilder->addCoverageProcessor(fp); } else { failed = true; break; } } iter.next(); } if (failed) { arfp->set(NULL); } return !failed; }
static bool get_analytic_clip_processor(const GrReducedClip::ElementList& elements, bool abortIfAA, SkVector& clipToRTOffset, const SkRect* drawBounds, sk_sp<GrFragmentProcessor>* resultFP) { SkRect boundsInClipSpace; if (drawBounds) { boundsInClipSpace = *drawBounds; boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); } SkASSERT(elements.count() <= kMaxAnalyticElements); SkSTArray<kMaxAnalyticElements, sk_sp<GrFragmentProcessor>> fps; GrReducedClip::ElementList::Iter iter(elements); while (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 (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: return false; } if (!skip) { GrPrimitiveEdgeType edgeType; if (iter.get()->isAA()) { if (abortIfAA) { return false; } edgeType = invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType; } else { edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType; } switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getPath(), &clipToRTOffset)); break; case SkClipStack::Element::kRRect_Type: { SkRRect rrect = iter.get()->getRRect(); rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps.emplace_back(GrRRectEffect::Make(edgeType, rrect)); break; } case SkClipStack::Element::kRect_Type: { SkRect rect = iter.get()->getRect(); rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps.emplace_back(GrConvexPolyEffect::Make(edgeType, rect)); break; } default: break; } if (!fps.back()) { return false; } } iter.next(); } *resultFP = nullptr; if (fps.count()) { *resultFP = GrFragmentProcessor::RunInSeries(fps.begin(), fps.count()); } return true; }
bool GrClipMaskManager::getAnalyticClipProcessor(const GrReducedClip::ElementList& elements, bool abortIfAA, SkVector& clipToRTOffset, const SkRect* drawBounds, const GrFragmentProcessor** resultFP) { SkRect boundsInClipSpace; if (drawBounds) { boundsInClipSpace = *drawBounds; boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); } SkASSERT(elements.count() <= kMaxAnalyticElements); const GrFragmentProcessor* fps[kMaxAnalyticElements]; for (int i = 0; i < kMaxAnalyticElements; ++i) { fps[i] = nullptr; } int fpCnt = 0; GrReducedClip::ElementList::Iter iter(elements); bool failed = false; while (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 (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) { GrPrimitiveEdgeType edgeType; if (iter.get()->isAA()) { if (abortIfAA) { failed = true; break; } edgeType = invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType; } else { edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType; } switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(), &clipToRTOffset); break; case SkClipStack::Element::kRRect_Type: { SkRRect rrect = iter.get()->getRRect(); rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps[fpCnt] = GrRRectEffect::Create(edgeType, rrect); break; } case SkClipStack::Element::kRect_Type: { SkRect rect = iter.get()->getRect(); rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, rect); break; } default: break; } if (!fps[fpCnt]) { failed = true; break; } fpCnt++; } iter.next(); } *resultFP = nullptr; if (!failed && fpCnt) { *resultFP = GrFragmentProcessor::RunInSeries(fps, fpCnt); } for (int i = 0; i < fpCnt; ++i) { fps[i]->unref(); } return !failed; }