Esempio n. 1
0
void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
                               const SkMatrix& viewMatrix,
                               const GrPath* path,
                               GrPathRendering::FillType fill) {
    // TODO: extract portions of checkDraw that are relevant to path stenciling.
    SkASSERT(path);
    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());

    // Setup clip
    GrPipelineBuilder::AutoRestoreStencil ars;
    GrAppliedClip clip;
    if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, nullptr, &clip)) {
        return;
    }

    GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    if (clip.clipCoverageFragmentProcessor()) {
        arfps.set(&pipelineBuilder);
        arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
    }

    // set stencil settings for path
    GrStencilSettings stencilSettings;
    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);

    GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
                                                pipelineBuilder.isHWAntialias(),
                                                stencilSettings, clip.scissorState(),
                                                pipelineBuilder.getRenderTarget(),
                                                path);
    this->recordBatch(batch);
    batch->unref();
}
Esempio n. 2
0
void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
                                 GrDrawPathBatchBase* batch) {
    // This looks like drawBatch() but there is an added wrinkle that stencil settings get inserted
    // after setting up clipping but before onDrawBatch(). TODO: Figure out a better model for
    // handling stencil settings WRT interactions between pipeline(builder), clipmaskmanager, and
    // batches.
    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());

    GrPipelineBuilder::AutoRestoreStencil ars;
    GrAppliedClip clip;
    if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
        return;
    }

    GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    if (clip.clipCoverageFragmentProcessor()) {
        arfps.set(&pipelineBuilder);
        arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
    }

    // Ensure the render target has a stencil buffer and get the stencil settings.
    GrStencilSettings stencilSettings;
    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
    this->getPathStencilSettingsForFilltype(batch->fillType(), sb, &stencilSettings);
    batch->setStencilSettings(stencilSettings);

    GrPipeline::CreateArgs args;
    if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
        return;
    }

    this->recordBatch(batch);
}
bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
                                         GrPipelineBuilder::AutoRestoreStencil* ars,
                                         const SkIRect& clipScissor,
                                         const SkRect* devBounds,
                                         GrAppliedClip* out) {
    if (kRespectClip_StencilClipMode == fClipMode) {
        fClipMode = kIgnoreClip_StencilClipMode;
    }

    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();

    SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
    SkIRect devBoundsScissor;
    const SkIRect* scissor = &clipScissor;
    bool doDevBoundsClip = fDebugClipBatchToBounds && devBounds;
    if (doDevBoundsClip) {
        devBounds->roundOut(&devBoundsScissor);
        if (devBoundsScissor.intersect(clipScissor)) {
            scissor = &devBoundsScissor;
        }
    }

    if (scissor->contains(clipSpaceRTIBounds)) {
        // This counts as wide open
        this->setPipelineBuilderStencil(pipelineBuilder, ars);
        return true;
    }

    if (clipSpaceRTIBounds.intersect(*scissor)) {
        out->fScissorState.set(clipSpaceRTIBounds);
        this->setPipelineBuilderStencil(pipelineBuilder, ars);
        return true;
    }
    return false;
}
Esempio n. 4
0
void GrDrawTarget::drawPath(const GrPipelineBuilder& pipelineBuilder,
                            const GrPathProcessor* pathProc,
                            const GrPath* path,
                            GrPathRendering::FillType fill) {
    // TODO: extract portions of checkDraw that are relevant to path rendering.
    SkASSERT(path);
    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());

    SkRect devBounds = path->getBounds();
    pathProc->viewMatrix().mapRect(&devBounds);

    // Setup clip
    GrScissorState scissorState;
    GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    GrPipelineBuilder::AutoRestoreStencil ars;
    if (!this->setupClip(pipelineBuilder, &arfps, &ars, &scissorState, &devBounds)) {
       return;
    }

    // set stencil settings for path
    GrStencilSettings stencilSettings;
    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);

    GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, pathProc, &devBounds,
                                            this);
    if (pipelineInfo.mustSkipDraw()) {
        return;
    }

    this->onDrawPath(pathProc, path, stencilSettings, pipelineInfo);
}
Esempio n. 5
0
void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
                               GrDrawContext* drawContext,
                               const GrClip& clip,
                               const SkMatrix& viewMatrix,
                               const GrPath* path,
                               GrPathRendering::FillType fill) {
    // TODO: extract portions of checkDraw that are relevant to path stenciling.
    SkASSERT(path);
    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());

    // Setup clip
    GrAppliedClip appliedClip;
    if (!clip.apply(fContext, pipelineBuilder, drawContext, nullptr, &appliedClip)) {
        return;
    }
    // TODO: respect fClipBatchToBounds if we ever start computing bounds here.

    // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
    // attempt this in a situation that would require coverage AA.
    SkASSERT(!appliedClip.clipCoverageFragmentProcessor());

    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    GrStencilAttachment* stencilAttachment = fResourceProvider->attachStencilAttachment(rt);
    if (!stencilAttachment) {
        SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
        return;
    }

    GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
                                                pipelineBuilder.isHWAntialias(),
                                                fill,
                                                appliedClip.hasStencilClip(),
                                                stencilAttachment->bits(),
                                                appliedClip.scissorState(),
                                                pipelineBuilder.getRenderTarget(),
                                                path);
    this->recordBatch(batch);
    batch->unref();
}
Esempio n. 6
0
bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
                                           const GrProcOptInfo& colorPOI,
                                           const GrProcOptInfo& coveragePOI,
                                           GrDeviceCoordTexture* dstCopy,
                                           const SkRect* drawBounds) {
    if (!pipelineBuilder.willXPNeedDstCopy(*this->caps(), colorPOI, coveragePOI)) {
        return true;
    }
    SkIRect copyRect;
    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    pipelineBuilder.clip().getConservativeBounds(rt, &copyRect);

    if (drawBounds) {
        SkIRect drawIBounds;
        drawBounds->roundOut(&drawIBounds);
        if (!copyRect.intersect(drawIBounds)) {
#ifdef SK_DEBUG
            SkDebugf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n");
#endif
            return false;
        }
    } else {
#ifdef SK_DEBUG
        //SkDebugf("No dev bounds when dst copy is made.\n");
#endif
    }

    // MSAA consideration: When there is support for reading MSAA samples in the shader we could
    // have per-sample dst values by making the copy multisampled.
    GrSurfaceDesc desc;
    this->initCopySurfaceDstDesc(rt, &desc);
    desc.fWidth = copyRect.width();
    desc.fHeight = copyRect.height();

    SkAutoTUnref<GrTexture> copy(
        fContext->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));

    if (!copy) {
        SkDebugf("Failed to create temporary copy of destination texture.\n");
        return false;
    }
    SkIPoint dstPoint = {0, 0};
    if (this->copySurface(copy, rt, copyRect, dstPoint)) {
        dstCopy->setTexture(copy);
        dstCopy->setOffset(copyRect.fLeft, copyRect.fTop);
        return true;
    } else {
        return false;
    }
}
Esempio n. 7
0
void GrDrawTarget::drawPaths(const GrPipelineBuilder& pipelineBuilder,
                             const GrPathProcessor* pathProc,
                             const GrPathRange* pathRange,
                             const void* indices,
                             PathIndexType indexType,
                             const float transformValues[],
                             PathTransformType transformType,
                             int count,
                             GrPathRendering::FillType fill) {
    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
    SkASSERT(pathRange);
    SkASSERT(indices);
    SkASSERT(0 == reinterpret_cast<intptr_t>(indices) %
             GrPathRange::PathIndexSizeInBytes(indexType));
    SkASSERT(transformValues);

    // Setup clip
    GrScissorState scissorState;
    GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    GrPipelineBuilder::AutoRestoreStencil ars;
    if (!this->setupClip(pipelineBuilder, &arfps, &ars, &scissorState, NULL)) {
        return;
    }

    // set stencil settings for path
    GrStencilSettings stencilSettings;
    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);

    // Don't compute a bounding box for dst copy texture, we'll opt
    // instead for it to just copy the entire dst. Realistically this is a moot
    // point, because any context that supports NV_path_rendering will also
    // support NV_blend_equation_advanced.
    GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, pathProc, NULL, this);
    if (pipelineInfo.mustSkipDraw()) {
        return;
    }

    this->onDrawPaths(pathProc, pathRange, indices, indexType, transformValues,
                      transformType, count, stencilSettings, pipelineInfo);
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
                               const GrPathProcessor* pathProc,
                               const GrPath* path,
                               GrPathRendering::FillType fill) {
    // TODO: extract portions of checkDraw that are relevant to path stenciling.
    SkASSERT(path);
    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());

    // Setup clip
    GrScissorState scissorState;
    GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    GrPipelineBuilder::AutoRestoreStencil ars;
    if (!this->setupClip(pipelineBuilder, &arfps, &ars, &scissorState, NULL)) {
        return;
    }

    // set stencil settings for path
    GrStencilSettings stencilSettings;
    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);

    this->onStencilPath(pipelineBuilder, pathProc, path, scissorState, stencilSettings);
}
Esempio n. 10
0
bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
                                           const GrPipelineOptimizations& optimizations,
                                           GrXferProcessor::DstTexture* dstTexture,
                                           const SkRect& batchBounds) {
    SkRect bounds = batchBounds;
    bounds.outset(0.5f, 0.5f);

    if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) {
        return true;
    }

    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();

    if (this->caps()->textureBarrierSupport()) {
        if (GrTexture* rtTex = rt->asTexture()) {
            // The render target is a texture, so we can read from it directly in the shader. The XP
            // will be responsible to detect this situation and request a texture barrier.
            dstTexture->setTexture(rtTex);
            dstTexture->setOffset(0, 0);
            return true;
        }
    }

    SkIRect copyRect;
    pipelineBuilder.clip().getConservativeBounds(rt->width(), rt->height(), &copyRect);

    SkIRect drawIBounds;
    bounds.roundOut(&drawIBounds);
    if (!copyRect.intersect(drawIBounds)) {
#ifdef SK_DEBUG
        GrCapsDebugf(this->caps(), "Missed an early reject. "
                                   "Bailing on draw from setupDstReadIfNecessary.\n");
#endif
        return false;
    }

    // MSAA consideration: When there is support for reading MSAA samples in the shader we could
    // have per-sample dst values by making the copy multisampled.
    GrSurfaceDesc desc;
    if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) {
        desc.fOrigin = kDefault_GrSurfaceOrigin;
        desc.fFlags = kRenderTarget_GrSurfaceFlag;
        desc.fConfig = rt->config();
    }

    desc.fWidth = copyRect.width();
    desc.fHeight = copyRect.height();

    static const uint32_t kFlags = 0;
    SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));

    if (!copy) {
        SkDebugf("Failed to create temporary copy of destination texture.\n");
        return false;
    }
    SkIPoint dstPoint = {0, 0};
    this->copySurface(copy, rt, copyRect, dstPoint);
    dstTexture->setTexture(copy);
    dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
    return true;
}
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
    GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
                              "GrStencilAndCoverPathRenderer::onDrawPath");
    SkASSERT(!args.fStyle->strokeRec().isHairlineStyle());
    const SkPath& path = *args.fPath;
    GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
    const SkMatrix& viewMatrix = *args.fViewMatrix;

    SkASSERT(!pipelineBuilder->hasUserStencilSettings());

    if (args.fAntiAlias) {
        SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled());
        pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
    }

    SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStyle));

    if (path.isInverseFillType()) {
        static constexpr GrUserStencilSettings kInvertedCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                // 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.
                GrUserStencilTest::kEqualIfInClip,
                0xffff,
                GrUserStencilOp::kKeep,
                GrUserStencilOp::kZero,
                0xffff>()
        );


        pipelineBuilder->setUserStencil(&kInvertedCoverPass);

        // fake inverse with a stencil and cover
        args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->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;
        if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) {
            pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag);
        }

        SkAutoTUnref<GrDrawBatch> batch(
                GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr,
                                                    &invert));
        args.fTarget->drawBatch(*pipelineBuilder, batch);
    } else {
        static constexpr GrUserStencilSettings kCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                GrUserStencilTest::kNotEqual,
                0xffff,
                GrUserStencilOp::kZero,
                GrUserStencilOp::kKeep,
                0xffff>()
        );

        pipelineBuilder->setUserStencil(&kCoverPass);
        SkAutoTUnref<GrDrawPathBatchBase> batch(
                GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
        args.fTarget->drawPathBatch(*pipelineBuilder, batch);
    }

    pipelineBuilder->disableUserStencil();
    return true;
}
Esempio n. 12
0
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
                                      GrPipelineBuilder::AutoRestoreStencil* ars,
                                      GrScissorState* scissorState,
                                      const SkRect* devBounds,
                                      GrAppliedClip* out) {
    if (kRespectClip_StencilClipMode == fClipMode) {
        fClipMode = kIgnoreClip_StencilClipMode;
    }

    GrReducedClip::ElementList elements(16);
    int32_t genID = 0;
    GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialState;
    SkIRect clipSpaceIBounds;
    bool requiresAA = false;
    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();

    // GrDrawTarget should have filtered this for us
    SkASSERT(rt);

    SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
    const GrClip& clip = pipelineBuilder.clip();
    if (clip.isWideOpen(clipSpaceRTIBounds)) {
        this->setPipelineBuilderStencil(pipelineBuilder, ars);
        return true;
    }

    // The clip mask manager always draws with a single IRect so we special case that logic here
    // Image filters just use a rect, so we also special case that logic
    switch (clip.clipType()) {
        case GrClip::kWideOpen_ClipType:
            SkFAIL("Should have caught this with clip.isWideOpen()");
            return true;
        case GrClip::kIRect_ClipType: {
            SkIRect scissor = clip.irect();
            if (scissor.intersect(clipSpaceRTIBounds)) {
                scissorState->set(scissor);
                this->setPipelineBuilderStencil(pipelineBuilder, ars);
                return true;
            }
            return false;
        }
        case GrClip::kClipStack_ClipType: {
            clipSpaceRTIBounds.offset(clip.origin());
            GrReducedClip::ReduceClipStack(*clip.clipStack(),
                                            clipSpaceRTIBounds,
                                            &elements,
                                            &genID,
                                            &initialState,
                                            &clipSpaceIBounds,
                                            &requiresAA);
            if (elements.isEmpty()) {
                if (GrReducedClip::kAllIn_InitialState == initialState) {
                    if (clipSpaceIBounds == clipSpaceRTIBounds) {
                        this->setPipelineBuilderStencil(pipelineBuilder, ars);
                        return true;
                    }
                } else {
                    return false;
                }
            }
        } break;
    }

    // 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() <= kMaxAnalyticElements) {
        SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX),
                                    SkIntToScalar(-clip.origin().fY) };
        // When there are multiple color samples we want to do per-sample clipping, not compute
        // a fractional pixel coverage.
        bool disallowAnalyticAA = pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
        const GrFragmentProcessor* clipFP = nullptr;
        if (elements.isEmpty() ||
            (requiresAA && !disallowAnalyticAA &&
             SkToBool(clipFP = this->getAnalyticClipProcessor(elements, clipToRTOffset, devBounds)))) {
            SkIRect scissorSpaceIBounds(clipSpaceIBounds);
            scissorSpaceIBounds.offset(-clip.origin());
            if (nullptr == devBounds ||
                !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) {
                scissorState->set(scissorSpaceIBounds);
            }
            this->setPipelineBuilderStencil(pipelineBuilder, ars);
            out->fClipCoverageFP.reset(clipFP);
            return true;
        }
    }

    // If MSAA is enabled we can do everything in the stencil buffer.
    if (0 == rt->numStencilSamples() && requiresAA) {
        SkAutoTUnref<GrTexture> result;

        // The top-left of the mask corresponds to the top-left corner of the bounds.
        SkVector clipToMaskOffset = {
            SkIntToScalar(-clipSpaceIBounds.fLeft),
            SkIntToScalar(-clipSpaceIBounds.fTop)
        };

        if (this->useSWOnlyPath(pipelineBuilder, clipToMaskOffset, elements)) {
            // The clip geometry is complex enough that it will be more efficient to create it
            // entirely in software
            result.reset(this->createSoftwareClipMask(genID,
                                                      initialState,
                                                      elements,
                                                      clipToMaskOffset,
                                                      clipSpaceIBounds));
        } else {
            result.reset(this->createAlphaClipMask(genID,
                                                   initialState,
                                                   elements,
                                                   clipToMaskOffset,
                                                   clipSpaceIBounds));
        }

        if (result) {
            // The mask's top left coord should be pinned to the rounded-out top left corner of
            // clipSpace bounds. We determine the mask's position WRT to the render target here.
            SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
            rtSpaceMaskBounds.offset(-clip.origin());
            out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBounds));
            this->setPipelineBuilderStencil(pipelineBuilder, ars);
            return true;
        }
        // if alpha clip mask creation fails fall through to the non-AA code paths
    }

    // use the stencil clip if we can't represent the clip as a rectangle.
    SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin();
    this->createStencilClipMask(rt,
                                genID,
                                initialState,
                                elements,
                                clipSpaceIBounds,
                                clipSpaceToStencilSpaceOffset);

    // This must occur after createStencilClipMask. That function may change the scissor. Also, it
    // only guarantees that the stencil mask is correct within the bounds it was passed, so we must
    // use both stencil and scissor test to the bounds for the final draw.
    SkIRect scissorSpaceIBounds(clipSpaceIBounds);
    scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
    scissorState->set(scissorSpaceIBounds);
    this->setPipelineBuilderStencil(pipelineBuilder, ars);
    return true;
}
Esempio n. 13
0
void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
                             const GrClip& clip,
                             GrDrawBatch* batch) {
    // Setup clip
    GrAppliedClip appliedClip;
    if (!clip.apply(fClipMaskManager, pipelineBuilder, &batch->bounds(), &appliedClip)) {
        return;
    }

    GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    if (appliedClip.clipCoverageFragmentProcessor()) {
        arfps.set(&pipelineBuilder);
        arfps.addCoverageFragmentProcessor(appliedClip.clipCoverageFragmentProcessor());
    }

    GrPipeline::CreateArgs args;
    args.fPipelineBuilder = &pipelineBuilder;
    args.fCaps = this->caps();
    args.fScissor = &appliedClip.scissorState();
    args.fHasStencilClip = appliedClip.hasStencilClip();
    if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
        if (!fResourceProvider->attachStencilAttachment(pipelineBuilder.getRenderTarget())) {
            SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
            return;
        }
    }
    batch->getPipelineOptimizations(&args.fOpts);
    GrScissorState finalScissor;
    if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) {
        GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
        GrGLIRect viewport;
        viewport.fLeft = 0;
        viewport.fBottom = 0;
        viewport.fWidth = rt->width();
        viewport.fHeight = rt->height();
        SkIRect ibounds;
        ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft,
                              viewport.fWidth);
        ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom,
                             viewport.fHeight);
        ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft,
                               viewport.fWidth);
        ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
                                viewport.fHeight);
        if (appliedClip.scissorState().enabled()) {
            const SkIRect& scissorRect = appliedClip.scissorState().rect();
            if (!ibounds.intersect(scissorRect)) {
                return;
            }
        }
        finalScissor.set(ibounds);
        args.fScissor = &finalScissor;
    }
    args.fOpts.fColorPOI.completeCalculations(pipelineBuilder.fColorFragmentProcessors.begin(),
                                              pipelineBuilder.numColorFragmentProcessors());
    args.fOpts.fCoveragePOI.completeCalculations(
                                               pipelineBuilder.fCoverageFragmentProcessors.begin(),
                                               pipelineBuilder.numCoverageFragmentProcessors());
    if (!this->setupDstReadIfNecessary(pipelineBuilder, clip, args.fOpts, &args.fDstTexture,
                                       batch->bounds())) {
        return;
    }

    if (!batch->installPipeline(args)) {
        return;
    }

#ifdef ENABLE_MDB
    SkASSERT(fRenderTarget);
    batch->pipeline()->addDependenciesTo(fRenderTarget);
#endif

    this->recordBatch(batch);
}
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;
}
Esempio n. 15
0
bool GrDrawTarget::checkDraw(const GrPipelineBuilder& pipelineBuilder,
                             const GrGeometryProcessor* gp,
                             GrPrimitiveType type,
                             int startVertex,
                             int startIndex,
                             int vertexCount,
                             int indexCount) const {
#ifdef SK_DEBUG
    const GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
    int maxVertex = startVertex + vertexCount;
    int maxValidVertex;
    switch (geoSrc.fVertexSrc) {
        case kNone_GeometrySrcType:
            SkFAIL("Attempting to draw without vertex src.");
        case kReserved_GeometrySrcType: // fallthrough
            maxValidVertex = geoSrc.fVertexCount;
            break;
        case kBuffer_GeometrySrcType:
            maxValidVertex = static_cast<int>(geoSrc.fVertexBuffer->gpuMemorySize() /
                                              geoSrc.fVertexSize);
            break;
    }
    if (maxVertex > maxValidVertex) {
        SkFAIL("Drawing outside valid vertex range.");
    }
    if (indexCount > 0) {
        int maxIndex = startIndex + indexCount;
        int maxValidIndex;
        switch (geoSrc.fIndexSrc) {
            case kNone_GeometrySrcType:
                SkFAIL("Attempting to draw indexed geom without index src.");
            case kReserved_GeometrySrcType: // fallthrough
                maxValidIndex = geoSrc.fIndexCount;
                break;
            case kBuffer_GeometrySrcType:
                maxValidIndex = static_cast<int>(geoSrc.fIndexBuffer->gpuMemorySize() /
                                                 sizeof(uint16_t));
                break;
        }
        if (maxIndex > maxValidIndex) {
            SkFAIL("Index reads outside valid index range.");
        }
    }

    SkASSERT(pipelineBuilder.getRenderTarget());

    if (gp) {
        int numTextures = gp->numTextures();
        for (int t = 0; t < numTextures; ++t) {
            GrTexture* texture = gp->texture(t);
            SkASSERT(texture->asRenderTarget() != pipelineBuilder.getRenderTarget());
        }
    }

    for (int s = 0; s < pipelineBuilder.numColorFragmentStages(); ++s) {
        const GrProcessor* effect = pipelineBuilder.getColorFragmentStage(s).processor();
        int numTextures = effect->numTextures();
        for (int t = 0; t < numTextures; ++t) {
            GrTexture* texture = effect->texture(t);
            SkASSERT(texture->asRenderTarget() != pipelineBuilder.getRenderTarget());
        }
    }
    for (int s = 0; s < pipelineBuilder.numCoverageFragmentStages(); ++s) {
        const GrProcessor* effect = pipelineBuilder.getCoverageFragmentStage(s).processor();
        int numTextures = effect->numTextures();
        for (int t = 0; t < numTextures; ++t) {
            GrTexture* texture = effect->texture(t);
            SkASSERT(texture->asRenderTarget() != pipelineBuilder.getRenderTarget());
        }
    }

#endif
    if (NULL == pipelineBuilder.getRenderTarget()) {
        return false;
    }
    return true;
}