diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h index b9adb66a1c..8cb5cb1769 100644 --- a/include/gpu/GrXferProcessor.h +++ b/include/gpu/GrXferProcessor.h @@ -293,14 +293,16 @@ protected: uint32_t fClassID; private: - virtual GrXferProcessor* onCreateXferProcessor(const GrProcOptInfo& colorPOI, + virtual GrXferProcessor* onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const = 0; /** * Returns true if the XP generated by this factory will explicitly read dst in the fragment * shader. */ - virtual bool willReadDstColor(const GrProcOptInfo& colorPOI, + virtual bool willReadDstColor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const = 0; virtual bool onIsEqual(const GrXPFactory&) const = 0; diff --git a/include/gpu/effects/GrCoverageSetOpXP.h b/include/gpu/effects/GrCoverageSetOpXP.h index e781999a1d..a95326f484 100644 --- a/include/gpu/effects/GrCoverageSetOpXP.h +++ b/include/gpu/effects/GrCoverageSetOpXP.h @@ -41,11 +41,13 @@ public: private: GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage); - GrXferProcessor* onCreateXferProcessor(const GrProcOptInfo& colorPOI, + GrXferProcessor* onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const SK_OVERRIDE; - bool willReadDstColor(const GrProcOptInfo& /*colorPOI*/, + bool willReadDstColor(const GrDrawTargetCaps& /*caps*/, + const GrProcOptInfo& /*colorPOI*/, const GrProcOptInfo& /*coveragePOI*/) const SK_OVERRIDE { return false; } diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h index 0d3b01ff4d..2bfcff2842 100644 --- a/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -20,8 +20,10 @@ public: bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE; - bool canApplyCoverage(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI) const SK_OVERRIDE; + bool canApplyCoverage(const GrProcOptInfo& /*colorPOI*/, + const GrProcOptInfo& /*coveragePOI*/) const SK_OVERRIDE { + return true; + } bool canTweakAlphaForCoverage() const SK_OVERRIDE; @@ -31,11 +33,13 @@ public: private: GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst); - GrXferProcessor* onCreateXferProcessor(const GrProcOptInfo& colorPOI, + GrXferProcessor* onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const SK_OVERRIDE; - bool willReadDstColor(const GrProcOptInfo& colorPOI, + bool willReadDstColor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const SK_OVERRIDE; bool onIsEqual(const GrXPFactory& xpfBase) const SK_OVERRIDE { diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp index 469f5b1adb..e068c9dc37 100644 --- a/src/effects/SkArithmeticMode_gpu.cpp +++ b/src/effects/SkArithmeticMode_gpu.cpp @@ -304,11 +304,12 @@ GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float } GrXferProcessor* -GrArithmeticXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI, +GrArithmeticXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const { return ArithmeticXP::Create(fK1, fK2, fK3, fK4, fEnforcePMColor, dstCopy, - this->willReadDstColor(colorPOI, coveragePOI)); + this->willReadDstColor(caps, colorPOI, coveragePOI)); } diff --git a/src/effects/SkArithmeticMode_gpu.h b/src/effects/SkArithmeticMode_gpu.h index 822e7bde1e..546902dd50 100644 --- a/src/effects/SkArithmeticMode_gpu.h +++ b/src/effects/SkArithmeticMode_gpu.h @@ -96,11 +96,13 @@ public: private: GrArithmeticXPFactory(float k1, float k2, float k3, float k4, bool enforcePMColor); - GrXferProcessor* onCreateXferProcessor(const GrProcOptInfo& colorPOI, + GrXferProcessor* onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const SK_OVERRIDE; - bool willReadDstColor(const GrProcOptInfo& colorPOI, + bool willReadDstColor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const SK_OVERRIDE { return true; } diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp index 321dcfd5e8..358a249060 100644 --- a/src/gpu/GrXferProcessor.cpp +++ b/src/gpu/GrXferProcessor.cpp @@ -38,7 +38,7 @@ GrXferProcessor* GrXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI, const GrDeviceCoordTexture* dstCopy, const GrDrawTargetCaps& caps) const { #ifdef SK_DEBUG - if (this->willReadDstColor(colorPOI, coveragePOI)) { + if (this->willReadDstColor(caps, colorPOI, coveragePOI)) { if (!caps.dstReadInShaderSupport()) { SkASSERT(dstCopy && dstCopy->texture()); } else { @@ -46,14 +46,13 @@ GrXferProcessor* GrXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI, } } else { SkASSERT(!dstCopy || !dstCopy->texture()); - } #endif - return this->onCreateXferProcessor(colorPOI, coveragePOI, dstCopy); + return this->onCreateXferProcessor(caps, colorPOI, coveragePOI, dstCopy); } bool GrXPFactory::willNeedDstCopy(const GrDrawTargetCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const { - return (this->willReadDstColor(colorPOI, coveragePOI) && !caps.dstReadInShaderSupport()); + return (this->willReadDstColor(caps, colorPOI, coveragePOI) && !caps.dstReadInShaderSupport()); } diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp index 2b262116f0..6f49a1d504 100644 --- a/src/gpu/effects/GrCoverageSetOpXP.cpp +++ b/src/gpu/effects/GrCoverageSetOpXP.cpp @@ -223,7 +223,8 @@ GrXPFactory* GrCoverageSetOpXPFactory::Create(SkRegion::Op regionOp, bool invert } GrXferProcessor* -GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI, +GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, const GrDeviceCoordTexture* dstCopy) const { return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage); diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp index 8d8f9f251d..e4d65e41e4 100644 --- a/src/gpu/effects/GrCustomXfermode.cpp +++ b/src/gpu/effects/GrCustomXfermode.cpp @@ -608,10 +608,11 @@ GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode) } GrXferProcessor* -GrCustomXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI, +GrCustomXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const { - return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(colorPOI, coveragePOI)); + return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(caps, colorPOI, coveragePOI)); } diff --git a/src/gpu/effects/GrCustomXfermodePriv.h b/src/gpu/effects/GrCustomXfermodePriv.h index 959b079603..8672529e45 100644 --- a/src/gpu/effects/GrCustomXfermodePriv.h +++ b/src/gpu/effects/GrCustomXfermodePriv.h @@ -77,11 +77,13 @@ public: GrXPFactory::InvariantOutput*) const SK_OVERRIDE; private: - GrXferProcessor* onCreateXferProcessor(const GrProcOptInfo& colorPOI, + GrXferProcessor* onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const SK_OVERRIDE; - bool willReadDstColor(const GrProcOptInfo& colorPOI, + bool willReadDstColor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const SK_OVERRIDE { return true; } diff --git a/src/gpu/effects/GrDisableColorXP.cpp b/src/gpu/effects/GrDisableColorXP.cpp index 637f99baf1..d97589dcb6 100644 --- a/src/gpu/effects/GrDisableColorXP.cpp +++ b/src/gpu/effects/GrDisableColorXP.cpp @@ -100,7 +100,8 @@ GrDisableColorXPFactory::GrDisableColorXPFactory() { } GrXferProcessor* -GrDisableColorXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI, +GrDisableColorXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, const GrDeviceCoordTexture* dstCopy) const { return DisableColorXP::Create(); diff --git a/src/gpu/effects/GrDisableColorXP.h b/src/gpu/effects/GrDisableColorXP.h index fe60b595a0..00675884a9 100644 --- a/src/gpu/effects/GrDisableColorXP.h +++ b/src/gpu/effects/GrDisableColorXP.h @@ -39,11 +39,13 @@ public: private: GrDisableColorXPFactory(); - GrXferProcessor* onCreateXferProcessor(const GrProcOptInfo& colorPOI, + GrXferProcessor* onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDeviceCoordTexture* dstCopy) const SK_OVERRIDE; - bool willReadDstColor(const GrProcOptInfo& colorPOI, + bool willReadDstColor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const SK_OVERRIDE { return false; } diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index a08776a20f..4453c8935d 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -59,6 +59,10 @@ public: kCoverage_PrimaryOutputType, // Modulate color and coverage, write result as the color output. kModulate_PrimaryOutputType, + // Custom Porter-Duff output, used for when we explictly are reading the dst and blending + // in the shader. Secondary Output must be none if you use this. The custom blend uses the + // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D + kCustom_PrimaryOutputType }; enum SecondaryOutputType { @@ -87,11 +91,19 @@ public: const GrDrawTargetCaps& caps) SK_OVERRIDE; void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE { - blendInfo->fSrcBlend = fSrcBlend; - blendInfo->fDstBlend = fDstBlend; + if (!this->willReadDstColor()) { + blendInfo->fSrcBlend = fSrcBlend; + blendInfo->fDstBlend = fDstBlend; + } else { + blendInfo->fSrcBlend = kOne_GrBlendCoeff; + blendInfo->fDstBlend = kZero_GrBlendCoeff; + } blendInfo->fBlendConstant = fBlendConstant; } + GrBlendCoeff getSrcBlend() const { return fSrcBlend; } + GrBlendCoeff getDstBlend() const { return fDstBlend; } + private: PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant, const GrDeviceCoordTexture* dstCopy, bool willReadDstColor); @@ -128,6 +140,50 @@ private: /////////////////////////////////////////////////////////////////////////////// +bool append_porterduff_term(GrGLFPFragmentBuilder* fsBuilder, GrBlendCoeff coeff, + const char* colorName, const char* srcColorName, + const char* dstColorName, bool hasPrevious) { + if (kZero_GrBlendCoeff == coeff) { + return hasPrevious; + } else { + if (hasPrevious) { + fsBuilder->codeAppend(" + "); + } + fsBuilder->codeAppendf("%s", colorName); + switch (coeff) { + case kOne_GrBlendCoeff: + break; + case kSC_GrBlendCoeff: + fsBuilder->codeAppendf(" * %s", srcColorName); + break; + case kISC_GrBlendCoeff: + fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); + break; + case kDC_GrBlendCoeff: + fsBuilder->codeAppendf(" * %s", dstColorName); + break; + case kIDC_GrBlendCoeff: + fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); + break; + case kSA_GrBlendCoeff: + fsBuilder->codeAppendf(" * %s.a", srcColorName); + break; + case kISA_GrBlendCoeff: + fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); + break; + case kDA_GrBlendCoeff: + fsBuilder->codeAppendf(" * %s.a", dstColorName); + break; + case kIDA_GrBlendCoeff: + fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); + break; + default: + SkFAIL("Unsupported Blend Coeff"); + } + return true; + } +} + class GLPorterDuffXferProcessor : public GrGLXferProcessor { public: GLPorterDuffXferProcessor(const GrProcessor&) {} @@ -139,16 +195,24 @@ public: const PorterDuffXferProcessor& xp = processor.cast(); b->add32(xp.primaryOutputType()); b->add32(xp.secondaryOutputType()); + if (xp.willReadDstColor()) { + b->add32(xp.getSrcBlend()); + b->add32(xp.getDstBlend()); + } }; private: void onEmitCode(const EmitArgs& args) SK_OVERRIDE { const PorterDuffXferProcessor& xp = args.fXP.cast(); GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); - if (xp.hasSecondaryOutput()) { + if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutputType()) { + SkASSERT(!xp.willReadDstColor()); switch(xp.secondaryOutputType()) { + case PorterDuffXferProcessor::kNone_SecondaryOutputType: + break; case PorterDuffXferProcessor::kCoverage_SecondaryOutputType: - fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage); + fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, + args.fInputCoverage); break; case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType: fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", @@ -163,24 +227,43 @@ private: default: SkFAIL("Unexpected Secondary Output"); } - } - - switch (xp.primaryOutputType()) { - case PorterDuffXferProcessor::kNone_PrimaryOutputType: - fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary); - break; - case PorterDuffXferProcessor::kColor_PrimaryOutputType: - fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor); - break; - case PorterDuffXferProcessor::kCoverage_PrimaryOutputType: - fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage); - break; - case PorterDuffXferProcessor::kModulate_PrimaryOutputType: - fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor, - args.fInputCoverage); - break; - default: - SkFAIL("Unexpected Primary Output"); + + switch (xp.primaryOutputType()) { + case PorterDuffXferProcessor::kNone_PrimaryOutputType: + fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary); + break; + case PorterDuffXferProcessor::kColor_PrimaryOutputType: + fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor); + break; + case PorterDuffXferProcessor::kCoverage_PrimaryOutputType: + fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage); + break; + case PorterDuffXferProcessor::kModulate_PrimaryOutputType: + fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor, + args.fInputCoverage); + break; + default: + SkFAIL("Unexpected Primary Output"); + } + } else { + SkASSERT(xp.willReadDstColor()); + + const char* dstColor = fsBuilder->dstColor(); + + fsBuilder->codeAppend("vec4 colorBlend ="); + // append src blend + bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(), + args.fInputColor, args.fInputColor, + dstColor, false); + // append dst blend + SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(), + dstColor, args.fInputColor, + dstColor, didAppend)); + fsBuilder->codeAppend(";"); + + fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;", + args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage, + dstColor); } } @@ -196,7 +279,8 @@ PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrColor constant, const GrDeviceCoordTexture* dstCopy, bool willReadDstColor) - : fSrcBlend(srcBlend) + : INHERITED(dstCopy, willReadDstColor) + , fSrcBlend(srcBlend) , fDstBlend(dstBlend) , fBlendConstant(constant) , fPrimaryOutputType(kModulate_PrimaryOutputType) @@ -244,6 +328,11 @@ PorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI, void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags, const GrDrawTargetCaps& caps, bool hasSolidCoverage) { + if (this->willReadDstColor()) { + fPrimaryOutputType = kCustom_PrimaryOutputType; + return; + } + if (optFlags & kIgnoreColor_OptFlag) { if (optFlags & kIgnoreCoverage_OptFlag) { fPrimaryOutputType = kNone_PrimaryOutputType; @@ -284,11 +373,12 @@ GrXferProcessor::OptFlags PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, bool doesStencilWrite) { - bool srcAIsOne; - bool hasCoverage; + if (this->willReadDstColor()) { + return GrXferProcessor::kNone_Opt; + } - srcAIsOne = colorPOI.isOpaque(); - hasCoverage = !coveragePOI.isSolidWhite(); + bool srcAIsOne = colorPOI.isOpaque(); + bool hasCoverage = !coveragePOI.isSolidWhite(); bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); @@ -472,19 +562,20 @@ GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { } GrXferProcessor* -GrPorterDuffXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI, +GrPorterDuffXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, const GrDeviceCoordTexture* dstCopy) const { if (!covPOI.isFourChannelOutput()) { return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy, - this->willReadDstColor(colorPOI, covPOI)); + this->willReadDstColor(caps, colorPOI, covPOI)); } else { if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) { SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags()); GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); return PorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff, blendConstant, dstCopy, - this->willReadDstColor(colorPOI, covPOI)); + this->willReadDstColor(caps, colorPOI, covPOI)); } else { return NULL; } @@ -500,39 +591,6 @@ bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, return false; } -bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI) const { - bool srcAIsOne = colorPOI.isOpaque(); - - bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff || - (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne); - bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff || - (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne); - - if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) { - return true; - } - - // if we don't have coverage we can check whether the dst - // has to read at all. - // check whether coverage can be safely rolled into alpha - // of if we can skip color computation and just emit coverage - if (this->canTweakAlphaForCoverage()) { - return true; - } - if (dstCoeffIsZero) { - if (kZero_GrBlendCoeff == fSrcCoeff) { - return true; - } else if (srcAIsOne) { - return true; - } - } else if (dstCoeffIsOne) { - return true; - } - - return false; -} - bool GrPorterDuffXPFactory::canTweakAlphaForCoverage() const { return can_tweak_alpha_for_coverage(fDstCoeff); } @@ -606,9 +664,37 @@ void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, output->fWillBlendWithDst = false; } -bool GrPorterDuffXPFactory::willReadDstColor(const GrProcOptInfo& colorPOI, +bool GrPorterDuffXPFactory::willReadDstColor(const GrDrawTargetCaps& caps, + const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const { - return false; + // We can always blend correctly if we have dual source blending. + if (caps.dualSourceBlendingSupport()) { + return false; + } + + if (this->canTweakAlphaForCoverage()) { + return false; + } + + bool srcAIsOne = colorPOI.isOpaque(); + + if (kZero_GrBlendCoeff == fDstCoeff) { + if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) { + return false; + } + } + + // Reduces to: coeffS * (Cov*S) + D + if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) { + return false; + } + + // We can always blend correctly if we have solid coverage. + if (coveragePOI.isSolidWhite()) { + return false; + } + + return true; } GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);