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); }