void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, InvariantBlendedColor* blendedColor) const { // Find the blended color info based on the formula that does not have coverage. BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode]; if (colorFormula.usesDstColor()) { blendedColor->fWillBlendWithDst = true; blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; return; } blendedColor->fWillBlendWithDst = false; SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation); switch (colorFormula.fSrcCoeff) { case kZero_GrBlendCoeff: blendedColor->fKnownColor = 0; blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags; return; case kOne_GrBlendCoeff: blendedColor->fKnownColor = colorPOI.color(); blendedColor->fKnownColorFlags = colorPOI.validFlags(); return; default: blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; return; } }
GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, const GrPipelineOptimizations& optimizations, bool hasMixedSamples, const DstTexture* dstTexture) const { if (optimizations.fOverrides.fUsePLSDstRead) { return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode); } BlendFormula blendFormula; if (optimizations.fCoveragePOI.isFourChannelOutput()) { if (SkBlendMode::kSrcOver == fXfermode && kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && !caps.shaderCaps()->dualSourceBlendingSupport() && !caps.shaderCaps()->dstReadInShaderSupport()) { // If we don't have dual source blending or in shader dst reads, we fall back to this // trick for rendering SrcOver LCD text instead of doing a dst copy. SkASSERT(!dstTexture || !dstTexture->texture()); return PDLCDXferProcessor::Create(fXfermode, optimizations.fColorPOI); } blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode); } else { blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, hasMixedSamples, fXfermode); } if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode); } SkASSERT(!dstTexture || !dstTexture->texture()); return new PorterDuffXferProcessor(blendFormula); }
GrXferProcessor::OptFlags PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, bool doesStencilWrite, GrColor* overrideColor, const GrCaps& caps) { GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags; if (!fBlendFormula.modifiesDst()) { if (!doesStencilWrite) { optFlags |= GrXferProcessor::kSkipDraw_OptFlag; } optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag | GrXferProcessor::kIgnoreCoverage_OptFlag | GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag); } else { if (!fBlendFormula.usesInputColor()) { optFlags |= GrXferProcessor::kIgnoreColor_OptFlag; } if (coveragePOI.isSolidWhite()) { optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag; } if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) { optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; } } return optFlags; }
GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, bool hasMixedSamples, const DstTexture* dstTexture) const { BlendFormula blendFormula; if (covPOI.isFourChannelOutput()) { if (SkXfermode::kSrcOver_Mode == fXfermode && kRGBA_GrColorComponentFlags == colorPOI.validFlags()) { SkASSERT(!dstTexture || !dstTexture->texture()); return PDLCDXferProcessor::Create(fXfermode, colorPOI); } blendFormula = get_lcd_blend_formula(covPOI, fXfermode); } else { blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode); } if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode); } SkASSERT(!dstTexture || !dstTexture->texture()); return new PorterDuffXferProcessor(blendFormula); }
void emitOutputsForBlendState(const EmitArgs& args) override { const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>(); GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); BlendFormula blendFormula = xp.getBlendFormula(); if (blendFormula.hasSecondaryOutput()) { append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType, args.fOutputSecondary, args.fInputColor, args.fInputCoverage); } append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType, args.fOutputPrimary, args.fInputColor, args.fInputCoverage); }
GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, const DstTexture* dstTexture) const { if (covPOI.isFourChannelOutput()) { SkASSERT(!dstTexture || !dstTexture->texture()); return PDLCDXferProcessor::Create(fXfermode, colorPOI); } BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI); if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { return ShaderPDXferProcessor::Create(fXfermode, dstTexture); } SkASSERT(!dstTexture || !dstTexture->texture()); return PorterDuffXferProcessor::Create(blendFormula); }
GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor( const GrCaps& caps, const GrPipelineOptimizations& optimizations, bool hasMixedSamples, const GrXferProcessor::DstTexture* dstTexture) { if (optimizations.fOverrides.fUsePLSDstRead) { return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkBlendMode::kSrcOver); } // We want to not make an xfer processor if possible. Thus for the simple case where we are not // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from // the general case where we convert a src-over blend that has solid coverage and an opaque // color to src-mode, which allows disabling of blending. if (!optimizations.fCoveragePOI.isFourChannelOutput()) { // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP". // We don't simply return the address of that XP here because our caller would have to unref // it and since it is a global object and GrProgramElement's ref-cnting system is not thread // safe. return nullptr; } if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && !caps.shaderCaps()->dualSourceBlendingSupport() && !caps.shaderCaps()->dstReadInShaderSupport()) { // If we don't have dual source blending or in shader dst reads, we fall // back to this trick for rendering SrcOver LCD text instead of doing a // dst copy. SkASSERT(!dstTexture || !dstTexture->texture()); return PDLCDXferProcessor::Create(SkBlendMode::kSrcOver, optimizations.fColorPOI); } BlendFormula blendFormula; blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, SkBlendMode::kSrcOver); if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkBlendMode::kSrcOver); } SkASSERT(!dstTexture || !dstTexture->texture()); return new PorterDuffXferProcessor(blendFormula); }
bool operator==(const BlendFormula& other) const { SkDEBUGCODE(this->validatePreoptimized()); SkDEBUGCODE(other.validatePreoptimized()); return fData == other.fData; }