bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations) { if (caps.shaderCaps()->dstReadInShaderSupport() || caps.shaderCaps()->dualSourceBlendingSupport()) { return false; } // When we have four channel coverage we always need to read the dst in order to correctly // blend. The one exception is when we are using srcover mode and we know the input color // into the XP. if (optimizations.fCoveragePOI.isFourChannelOutput()) { if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && !caps.shaderCaps()->dstReadInShaderSupport()) { return false; } return get_lcd_blend_formula(optimizations.fCoveragePOI, SkBlendMode::kSrcOver).hasSecondaryOutput(); } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. static const bool kHasMixedSamples = false; SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending. return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, kHasMixedSamples, SkBlendMode::kSrcOver).hasSecondaryOutput(); }
bool GrXPFactory::willNeedDstTexture(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, bool hasMixedSamples) const { return (this->willReadDstColor(caps, colorPOI, coveragePOI, hasMixedSamples) && !caps.shaderCaps()->dstReadInShaderSupport()); }
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const { if (coveragePOI.isFourChannelOutput()) { return false; // The LCD XP never does a dst read. } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. return !caps.shaderCaps()->dualSourceBlendingSupport() && get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput(); }
sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory, const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage, bool hasMixedSamples, const GrCaps& caps) { SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport()); if (factory) { return factory->makeXferProcessor(color, coverage, hasMixedSamples, caps); } else { return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, hasMixedSamples, caps); } }
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, bool hasMixedSamples) const { if (caps.shaderCaps()->dualSourceBlendingSupport()) { return false; } if (covPOI.isFourChannelOutput()) { return false; // The LCD XP will abort rather than doing a dst read. } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput(); }
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, bool hasMixedSamples) const { if (caps.shaderCaps()->dualSourceBlendingSupport()) { return false; } // When we have four channel coverage we always need to read the dst in order to correctly // blend. The one exception is when we are using srcover mode and we know the input color into // the XP. if (covPOI.isFourChannelOutput()) { if (SkXfermode::kSrcOver_Mode == fXfermode && kRGBA_GrColorComponentFlags == colorPOI.validFlags() && !caps.shaderCaps()->dstReadInShaderSupport()) { return false; } return get_lcd_blend_formula(covPOI, fXfermode).hasSecondaryOutput(); } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput(); }
GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties( const GrXPFactory* factory, const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage, const GrCaps& caps) { AnalysisProperties result; if (factory) { result = factory->analysisProperties(color, coverage, caps); } else { result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps); } SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture)); if ((result & AnalysisProperties::kReadsDstInShader) && !caps.shaderCaps()->dstReadInShaderSupport()) { result |= AnalysisProperties::kRequiresDstTexture; if (caps.textureBarrierSupport()) { result |= AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws; } } return result; }
bool GrXPFactory::willNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations, bool hasMixedSamples) const { return (this->willReadDstColor(caps, optimizations, hasMixedSamples) && !caps.shaderCaps()->dstReadInShaderSupport()); }
std::unique_ptr<GrFillRRectOp> GrFillRRectOp::Make( GrRecordingContext* ctx, GrAAType aaType, const SkMatrix& viewMatrix, const SkRRect& rrect, const GrCaps& caps, GrPaint&& paint) { if (!caps.instanceAttribSupport()) { return nullptr; } Flags flags = Flags::kNone; if (GrAAType::kCoverage == aaType) { // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we // already use HW derivatives. The only trick will be adjusting the AA outset to account for // perspective. (i.e., outset = 0.5 * z.) if (viewMatrix.hasPerspective()) { return nullptr; } if (can_use_hw_derivatives_with_coverage(*caps.shaderCaps(), viewMatrix, rrect)) { // HW derivatives (more specifically, fwidth()) are consistently faster on all platforms // in coverage mode. We use them as long as the approximation will be accurate enough. flags |= Flags::kUseHWDerivatives; } } else { if (GrAAType::kMSAA == aaType) { if (!caps.sampleLocationsSupport() || !caps.shaderCaps()->sampleVariablesSupport()) { return nullptr; } } if (viewMatrix.hasPerspective()) { // HW derivatives are consistently slower on all platforms in sample mask mode. We // therefore only use them when there is perspective, since then we can't interpolate // the symbolic screen-space gradient. flags |= Flags::kUseHWDerivatives | Flags::kHasPerspective; } } // Produce a matrix that draws the round rect from normalized [-1, -1, +1, +1] space. float l = rrect.rect().left(), r = rrect.rect().right(), t = rrect.rect().top(), b = rrect.rect().bottom(); SkMatrix m; // Unmap the normalized rect [-1, -1, +1, +1] back to [l, t, r, b]. m.setScaleTranslate((r - l)/2, (b - t)/2, (l + r)/2, (t + b)/2); // Map to device space. m.postConcat(viewMatrix); SkRect devBounds; if (!(flags & Flags::kHasPerspective)) { // Since m is an affine matrix that maps the rect [-1, -1, +1, +1] into the shape's // device-space quad, it's quite simple to find the bounding rectangle: devBounds = SkRect::MakeXYWH(m.getTranslateX(), m.getTranslateY(), 0, 0); devBounds.outset(SkScalarAbs(m.getScaleX()) + SkScalarAbs(m.getSkewX()), SkScalarAbs(m.getSkewY()) + SkScalarAbs(m.getScaleY())); } else { viewMatrix.mapRect(&devBounds, rrect.rect()); } if (GrAAType::kMSAA == aaType && caps.preferTrianglesOverSampleMask()) { // We are on a platform that prefers fine triangles instead of using the sample mask. See if // the round rect is large enough that it will be faster for us to send it off to the // default path renderer instead. The 200x200 threshold was arrived at using the // "shapes_rrect" benchmark on an ARM Galaxy S9. if (devBounds.height() * devBounds.width() > 200 * 200) { return nullptr; } } GrOpMemoryPool* pool = ctx->priv().opMemoryPool(); return pool->allocate<GrFillRRectOp>(aaType, rrect, flags, m, std::move(paint), devBounds); }