/* * This method traverses the clip stack to see if the GrSoftwarePathRenderer * will be used on any element. If so, it returns true to indicate that the * entire clip should be rendered in SW and then uploaded en masse to the gpu. */ bool GrClipMaskManager::UseSWOnlyPath(GrContext* context, const GrPipelineBuilder& pipelineBuilder, const GrRenderTarget* rt, const SkVector& clipToMaskOffset, const GrReducedClip::ElementList& elements) { // TODO: generalize this function so that when // a clip gets complex enough it can just be done in SW regardless // of whether it would invoke the GrSoftwarePathRenderer. // Set the matrix so that rendered clip elements are transformed to mask space from clip // space. const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY); for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) { const Element* element = iter.get(); SkRegion::Op op = element->getOp(); bool invert = element->isInverseFilled(); bool needsStencil = invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op; if (PathNeedsSWRenderer(context, pipelineBuilder.getStencil().isDisabled(), rt, translate, element, nullptr, needsStencil)) { return true; } } return false; }
void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipelineBuilder, GrPipelineBuilder::AutoRestoreStencil* ars) { // We make two copies of the StencilSettings here (except in the early // exit scenario. One copy from draw state to the stack var. Then another // from the stack var to the gpu. We could make this class hold a ptr to // GrGpu's fStencilSettings and eliminate the stack copy here. // use stencil for clipping if clipping is enabled and the clip // has been written into the stencil. GrStencilSettings settings; // The GrGpu client may not be using the stencil buffer but we may need to // enable it in order to respect a stencil clip. if (pipelineBuilder.getStencil().isDisabled()) { if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) { settings = basic_apply_stencil_clip_settings(); } else { return; } } else { settings = pipelineBuilder.getStencil(); } int stencilBits = 0; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); GrStencilAttachment* stencilAttachment = fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt); if (stencilAttachment) { stencilBits = stencilAttachment->bits(); } SkASSERT(fDrawTarget->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp()); SkASSERT(fDrawTarget->caps()->twoSidedStencilSupport() || !settings.isTwoSided()); this->adjustStencilParams(&settings, fClipMode, stencilBits); ars->set(&pipelineBuilder); ars->setStencil(settings); }
GrPipeline::GrPipeline(const GrPipelineBuilder& pipelineBuilder, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDrawTargetCaps& caps, const GrScissorState& scissorState, const GrDeviceCoordTexture* dstCopy) { // Create XferProcessor from DS's XPFactory SkAutoTUnref<GrXferProcessor> xferProcessor( pipelineBuilder.getXPFactory()->createXferProcessor(colorPOI, coveragePOI, dstCopy, caps)); GrColor overrideColor = GrColor_ILLEGAL; if (colorPOI.firstEffectiveStageIndex() != 0) { overrideColor = colorPOI.inputColorToEffectiveStage(); } GrXferProcessor::OptFlags optFlags; if (xferProcessor) { fXferProcessor.reset(xferProcessor.get()); optFlags = xferProcessor->getOptimizations(colorPOI, coveragePOI, pipelineBuilder.getStencil().doesWrite(), &overrideColor, caps); } // When path rendering the stencil settings are not always set on the GrPipelineBuilder // so we must check the draw type. In cases where we will skip drawing we simply return a // null GrPipeline. if (!xferProcessor || (GrXferProcessor::kSkipDraw_OptFlag & optFlags)) { // Set the fields that don't default init and return. The lack of a render target will // indicate that this can be skipped. fFlags = 0; fDrawFace = GrPipelineBuilder::kInvalid_DrawFace; return; } fRenderTarget.reset(pipelineBuilder.fRenderTarget.get()); SkASSERT(fRenderTarget); fScissorState = scissorState; fStencilSettings = pipelineBuilder.getStencil(); fDrawFace = pipelineBuilder.getDrawFace(); fFlags = 0; if (pipelineBuilder.isHWAntialias()) { fFlags |= kHWAA_Flag; } if (pipelineBuilder.isDither()) { fFlags |= kDither_Flag; } if (pipelineBuilder.snapVerticesToPixelCenters()) { fFlags |= kSnapVertices_Flag; } int firstColorStageIdx = colorPOI.firstEffectiveStageIndex(); // TODO: Once we can handle single or four channel input into coverage stages then we can use // GrPipelineBuilder's coverageProcInfo (like color above) to set this initial information. int firstCoverageStageIdx = 0; this->adjustProgramFromOptimizations(pipelineBuilder, optFlags, colorPOI, coveragePOI, &firstColorStageIdx, &firstCoverageStageIdx); bool usesLocalCoords = false; // Copy Stages from PipelineBuilder to Pipeline for (int i = firstColorStageIdx; i < pipelineBuilder.numColorFragmentStages(); ++i) { SkNEW_APPEND_TO_TARRAY(&fFragmentStages, GrPendingFragmentStage, (pipelineBuilder.fColorStages[i])); usesLocalCoords = usesLocalCoords || pipelineBuilder.fColorStages[i].processor()->usesLocalCoords(); } fNumColorStages = fFragmentStages.count(); for (int i = firstCoverageStageIdx; i < pipelineBuilder.numCoverageFragmentStages(); ++i) { SkNEW_APPEND_TO_TARRAY(&fFragmentStages, GrPendingFragmentStage, (pipelineBuilder.fCoverageStages[i])); usesLocalCoords = usesLocalCoords || pipelineBuilder.fCoverageStages[i].processor()->usesLocalCoords(); } // let the GP init the batch tracker fInitBT.fColorIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag); fInitBT.fOverrideColor = fInitBT.fColorIgnored ? GrColor_ILLEGAL : overrideColor; fInitBT.fCoverageIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag); fInitBT.fUsesLocalCoords = usesLocalCoords; fInitBT.fCanTweakAlphaForCoverage = SkToBool(optFlags & GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag); }
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { SkASSERT(!args.fStroke->isHairlineStyle()); const SkPath& path = *args.fPath; GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder; const SkMatrix& viewMatrix = *args.fViewMatrix; SkASSERT(pipelineBuilder->getStencil().isDisabled()); if (args.fAntiAlias) { SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled()); pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag); } SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke)); if (path.isInverseFillType()) { GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, kKeep_StencilOp, kZero_StencilOp, // We know our rect will hit pixels outside the clip and the user bits will be 0 // outside the clip. So we can't just fill where the user bits are 0. We also need to // check that the clip bit is set. kEqualIfInClip_StencilFunc, 0xffff, 0x0000, 0xffff); pipelineBuilder->setStencil(kInvertedStencilPass); // fake inverse with a stencil and cover SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix)); args.fTarget->stencilPath(*pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); SkMatrix invert = SkMatrix::I(); SkRect bounds = SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()), SkIntToScalar(pipelineBuilder->getRenderTarget()->height())); SkMatrix vmi; // mapRect through persp matrix may not be correct if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { vmi.mapRect(&bounds); // theoretically could set bloat = 0, instead leave it because of matrix inversion // precision. SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf; bounds.outset(bloat, bloat); } else { if (!viewMatrix.invert(&invert)) { return false; } } const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix; args.fTarget->drawNonAARect(*pipelineBuilder, args.fColor, viewM, bounds, invert); } else { GR_STATIC_CONST_SAME_STENCIL(kStencilPass, kZero_StencilOp, kKeep_StencilOp, kNotEqual_StencilFunc, 0xffff, 0x0000, 0xffff); pipelineBuilder->setStencil(kStencilPass); SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(args.fColor, viewMatrix)); args.fTarget->drawPath(*pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); } pipelineBuilder->stencil()->setDisabled(); return true; }