Esempio n. 1
0
////////////////////////////////////////////////////////////////////////////////
// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
// (as opposed to canvas) coordinates
bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
                                              int32_t elementsGenID,
                                              GrReducedClip::InitialState initialState,
                                              const GrReducedClip::ElementList& elements,
                                              const SkIRect& clipSpaceIBounds,
                                              const SkIPoint& clipSpaceToStencilOffset) {
    SkASSERT(rt);

    GrStencilAttachment* stencilAttachment =
        fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt);
    if (nullptr == stencilAttachment) {
        return false;
    }

    if (stencilAttachment->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset)) {
        stencilAttachment->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset);
        // Set the matrix so that rendered clip elements are transformed from clip to stencil space.
        SkVector translate = {
            SkIntToScalar(clipSpaceToStencilOffset.fX),
            SkIntToScalar(clipSpaceToStencilOffset.fY)
        };
        SkMatrix viewMatrix;
        viewMatrix.setTranslate(translate);

        // We set the current clip to the bounds so that our recursive draws are scissored to them.
        SkIRect stencilSpaceIBounds(clipSpaceIBounds);
        stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
        GrClip clip(stencilSpaceIBounds);

        int clipBit = stencilAttachment->bits();
        SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
        clipBit = (1 << (clipBit-1));

        fDrawTarget->cmmAccess().clearStencilClip(stencilSpaceIBounds,
            GrReducedClip::kAllIn_InitialState == initialState, rt);

        // walk through each clip element and perform its set op
        // with the existing clip.
        for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
            const Element* element = iter.get();

            GrPipelineBuilder pipelineBuilder;
            pipelineBuilder.setClip(clip);
            pipelineBuilder.setRenderTarget(rt);

            pipelineBuilder.setDisableColorXPFactory();

            // if the target is MSAA then we want MSAA enabled when the clip is soft
            if (rt->isStencilBufferMultisampled()) {
                pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, element->isAA());
            }

            bool fillInverted = false;
            // enabled at bottom of loop
            fClipMode = kIgnoreClip_StencilClipMode;

            // This will be used to determine whether the clip shape can be rendered into the
            // stencil with arbitrary stencil settings.
            GrPathRenderer::StencilSupport stencilSupport;

            GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
            SkRegion::Op op = element->getOp();

            GrPathRenderer* pr = nullptr;
            SkPath clipPath;
            if (Element::kRect_Type == element->getType()) {
                stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
                fillInverted = false;
            } else {
                element->asPath(&clipPath);
                fillInverted = clipPath.isInverseFillType();
                if (fillInverted) {
                    clipPath.toggleInverseFillType();
                }
                pr = this->getContext()->getPathRenderer(fDrawTarget,
                                                         &pipelineBuilder,
                                                         viewMatrix,
                                                         clipPath,
                                                         stroke,
                                                         false,
                                                         GrPathRendererChain::kStencilOnly_DrawType,
                                                         &stencilSupport);
                if (nullptr == pr) {
                    return false;
                }
            }

            int passes;
            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];

            bool canRenderDirectToStencil =
                GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
            bool canDrawDirectToClip; // Given the renderer, the element,
                                      // fill rule, and set operation can
                                      // we render the element directly to
                                      // stencil bit used for clipping.
            canDrawDirectToClip = GrStencilSettings::GetClipPasses(op,
                                                                   canRenderDirectToStencil,
                                                                   clipBit,
                                                                   fillInverted,
                                                                   &passes,
                                                                   stencilSettings);

            // draw the element to the client stencil bits if necessary
            if (!canDrawDirectToClip) {
                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
                                             kIncClamp_StencilOp,
                                             kIncClamp_StencilOp,
                                             kAlways_StencilFunc,
                                             0xffff,
                                             0x0000,
                                             0xffff);
                if (Element::kRect_Type == element->getType()) {
                    *pipelineBuilder.stencil() = gDrawToStencil;

                    // We need this AGP until everything is in GrBatch
                    fDrawTarget->drawNonAARect(pipelineBuilder,
                                               GrColor_WHITE,
                                               viewMatrix,
                                               element->getRect());
                } else {
                    if (!clipPath.isEmpty()) {
                        if (canRenderDirectToStencil) {
                            *pipelineBuilder.stencil() = gDrawToStencil;

                            GrPathRenderer::DrawPathArgs args;
                            args.fTarget = fDrawTarget;
                            args.fResourceProvider = this->getContext()->resourceProvider();
                            args.fPipelineBuilder = &pipelineBuilder;
                            args.fColor = GrColor_WHITE;
                            args.fViewMatrix = &viewMatrix;
                            args.fPath = &clipPath;
                            args.fStroke = &stroke;
                            args.fAntiAlias = false;
                            pr->drawPath(args);
                        } else {
                            GrPathRenderer::StencilPathArgs args;
                            args.fTarget = fDrawTarget;
                            args.fResourceProvider = this->getContext()->resourceProvider();
                            args.fPipelineBuilder = &pipelineBuilder;
                            args.fViewMatrix = &viewMatrix;
                            args.fPath = &clipPath;
                            args.fStroke = &stroke;
                            pr->stencilPath(args);
                        }
                    }
                }
            }

            // now we modify the clip bit by rendering either the clip
            // element directly or a bounding rect of the entire clip.
            fClipMode = kModifyClip_StencilClipMode;
            for (int p = 0; p < passes; ++p) {
                *pipelineBuilder.stencil() = stencilSettings[p];

                if (canDrawDirectToClip) {
                    if (Element::kRect_Type == element->getType()) {
                        // We need this AGP until everything is in GrBatch
                        fDrawTarget->drawNonAARect(pipelineBuilder,
                                                   GrColor_WHITE,
                                                   viewMatrix,
                                                   element->getRect());
                    } else {
                        GrPathRenderer::DrawPathArgs args;
                        args.fTarget = fDrawTarget;
                        args.fResourceProvider = this->getContext()->resourceProvider();
                        args.fPipelineBuilder = &pipelineBuilder;
                        args.fColor = GrColor_WHITE;
                        args.fViewMatrix = &viewMatrix;
                        args.fPath = &clipPath;
                        args.fStroke = &stroke;
                        args.fAntiAlias = false;
                        pr->drawPath(args);
                    }
                } else {
                    // The view matrix is setup to do clip space -> stencil space translation, so
                    // draw rect in clip space.
                    fDrawTarget->drawNonAARect(pipelineBuilder,
                                               GrColor_WHITE,
                                               viewMatrix,
                                               SkRect::Make(clipSpaceIBounds));
                }
            }
        }
    }
    fClipMode = kRespectClip_StencilClipMode;
    return true;
}