Example #1
0
void SkDeferredCanvas::flush_check(SkRect* bounds, const SkPaint* paint, unsigned flags) {
    if (paint) {
        if (paint->getShader() || paint->getImageFilter()) {
            flags |= kNoTranslate_Flag | kNoScale_Flag;
        }
        // TODO: replace these with code to enlarge the bounds conservatively?
        if (paint->getStyle() != SkPaint::kFill_Style || paint->getMaskFilter() ||
            paint->getImageFilter() || paint->getPathEffect())
        {
            flags |= kNoCull_Flag | kNoScale_Flag | kNoClip_Flag;
        }
        if (paint->getLooper()) {
            // to be conservative, we disable both, since embedded layers could have shaders
            // or strokes etc.
            flags |= kNoTranslate_Flag | kNoCull_Flag | kNoScale_Flag;
        }
    }
    bool canClip = !(flags & kNoClip_Flag);
    bool canTranslate = !(flags & kNoTranslate_Flag);
    bool canCull = !(flags & kNoCull_Flag);
    bool canScale = !(flags & kNoScale_Flag);

    int i;
    for (i = fRecs.count() - 1; i >= 0; --i) {
        const Rec& rec = fRecs[i];
        switch (rec.fType) {
            case kSave_Type:
                // continue to the next rec
                break;
            case kClipRect_Type:
                if (!canCull) {
                    goto STOP;
                }
                if (canClip) {
                    if (!bounds->intersect(rec.fData.fBounds)) {
                        bounds->setEmpty();
                        return;
                    }
                    // continue to the next rec
                } else {
                    if (!rec.fData.fBounds.contains(*bounds)) {
                        goto STOP;
                    }
                    // continue to the next rec
                }
                break;
            case kTrans_Type:
                if (canTranslate) {
                    bounds->offset(rec.fData.fTranslate.x(), rec.fData.fTranslate.y());
                    // continue to the next rec
                } else {
                    goto STOP;
                }
                break;
            case kScaleTrans_Type:
                if (canScale) {
                    SkMatrix m;
                    rec.getConcat(&m);
                    m.mapRectScaleTranslate(bounds, *bounds);
                } else {
                    goto STOP;
                }
                break;
        }
    }
STOP:
    this->flush_le(i);
}
void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer,
                                          const SkRect& clippedSrcRect,
                                          const SkRect& clippedDstRect,
                                          SkCanvas::SrcRectConstraint constraint,
                                          const SkMatrix& viewMatrix,
                                          const SkMatrix& srcToDstMatrix,
                                          const GrClip& clip,
                                          const SkPaint& paint) {
    // Specifying the texture coords as local coordinates is an attempt to enable more GrDrawOp
    // combining by not baking anything about the srcRect, dstRect, or viewMatrix, into the texture
    // FP. In the future this should be an opaque optimization enabled by the combination of
    // GrDrawOp/GP and FP.
    const SkMaskFilter* mf = paint.getMaskFilter();
    // The shader expects proper local coords, so we can't replace local coords with texture coords
    // if the shader will be used. If we have a mask filter we will change the underlying geometry
    // that is rendered.
    bool canUseTextureCoordsAsLocalCoords = !use_shader(producer->isAlphaOnly(), paint) && !mf;

    bool doBicubic;
    GrSamplerParams::FilterMode fm =
        GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, srcToDstMatrix,
                                        &doBicubic);
    const GrSamplerParams::FilterMode* filterMode = doBicubic ? nullptr : &fm;

    GrTextureProducer::FilterConstraint constraintMode;
    if (SkCanvas::kFast_SrcRectConstraint == constraint) {
        constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
    } else {
        constraintMode = GrTextureAdjuster::kYes_FilterConstraint;
    }

    // If we have to outset for AA then we will generate texture coords outside the src rect. The
    // same happens for any mask filter that extends the bounds rendered in the dst.
    // This is conservative as a mask filter does not have to expand the bounds rendered.
    bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf;

    // Check for optimization to drop the src rect constraint when on bilerp.
    if (filterMode && GrSamplerParams::kBilerp_FilterMode == *filterMode &&
        GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) {
        SkMatrix combinedMatrix;
        combinedMatrix.setConcat(viewMatrix, srcToDstMatrix);
        if (can_ignore_bilerp_constraint(*producer, clippedSrcRect, combinedMatrix,
                                         fRenderTargetContext->isUnifiedMultisampled())) {
            constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
        }
    }

    const SkMatrix* textureMatrix;
    SkMatrix tempMatrix;
    if (canUseTextureCoordsAsLocalCoords) {
        textureMatrix = &SkMatrix::I();
    } else {
        if (!srcToDstMatrix.invert(&tempMatrix)) {
            return;
        }
        textureMatrix = &tempMatrix;
    }
    sk_sp<GrFragmentProcessor> fp(producer->createFragmentProcessor(
        *textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode,
        fRenderTargetContext->getColorSpace()));
    if (!fp) {
        return;
    }

    GrPaint grPaint;
    if (!SkPaintToGrPaintWithTexture(fContext.get(), fRenderTargetContext.get(), paint, viewMatrix,
                                     fp, producer->isAlphaOnly(), &grPaint)) {
        return;
    }
    GrAA aa = GrBoolToAA(paint.isAntiAlias());
    if (canUseTextureCoordsAsLocalCoords) {
        fRenderTargetContext->fillRectToRect(clip, std::move(grPaint), aa, viewMatrix,
                                             clippedDstRect, clippedSrcRect);
        return;
    }

    if (!mf) {
        fRenderTargetContext->drawRect(clip, std::move(grPaint), aa, viewMatrix, clippedDstRect);
        return;
    }

    // First see if we can do the draw + mask filter direct to the dst.
    if (viewMatrix.isScaleTranslate()) {
        SkRect devClippedDstRect;
        viewMatrix.mapRectScaleTranslate(&devClippedDstRect, clippedDstRect);

        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
        if (mf->directFilterRRectMaskGPU(fContext.get(),
                                         fRenderTargetContext.get(),
                                         std::move(grPaint),
                                         clip,
                                         viewMatrix,
                                         rec,
                                         SkRRect::MakeRect(clippedDstRect),
                                         SkRRect::MakeRect(devClippedDstRect))) {
            return;
        }
    }

    SkPath rectPath;
    rectPath.addRect(clippedDstRect);
    rectPath.setIsVolatile(true);
    GrBlurUtils::drawPathWithMaskFilter(this->context(), fRenderTargetContext.get(), this->clip(),
                                        rectPath, std::move(grPaint), aa, viewMatrix, mf,
                                        GrStyle::SimpleFill(), true);
}