Fix to lcd blending in ganesh
This fixes the bug where a src color may originally be opaque but after
blending it is no longer opaque. We need to know the opacity after the
blend so this restricts us on which blend modes even work this way.
Bug: skia:
Change-Id: Ib3208887d718e5f25272ed7b0bf44683d04884d7
Reviewed-on: https://skia-review.googlesource.com/17488
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index 269262b..834f3af 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -775,7 +775,7 @@
}
if ((blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) ||
- (isLCD && !color.isOpaque())) {
+ (isLCD && (SkBlendMode::kSrcOver != fBlendMode || !color.isOpaque()))) {
return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode,
coverage));
}
@@ -795,36 +795,41 @@
} else {
formula = gBlendTable[color.isOpaque()][hasCoverage][(int)mode];
}
- if (formula.canTweakAlphaForCoverage()) {
+
+ if (formula.canTweakAlphaForCoverage() && !isLCD) {
props |= AnalysisProperties::kCompatibleWithAlphaAsCoverage;
}
- // With dual-source blending we never need the destination color in the shader.
- if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
- // Mixed samples implicity computes a fractional coverage from sample coverage. This could
- // affect the formula used. However, we don't expect to have mixed samples without dual
- // source blending.
- SkASSERT(!caps.usesMixedSamples());
- if (GrProcessorAnalysisCoverage::kLCD == coverage) {
- // Check for special case of srcover with a known color which can be done using the
- // blend constant.
- if (SkBlendMode::kSrcOver == mode && color.isConstant() && color.isOpaque() &&
- !caps.shaderCaps()->dstReadInShaderSupport()) {
- props |= AnalysisProperties::kIgnoresInputColor;
- } else {
- if (get_lcd_blend_formula(mode).hasSecondaryOutput() || !color.isOpaque()) {
- props |= AnalysisProperties::kReadsDstInShader;
- }
+
+ if (isLCD) {
+ if (SkBlendMode::kSrcOver == mode && color.isConstant() && color.isOpaque() &&
+ !caps.shaderCaps()->dualSourceBlendingSupport() &&
+ !caps.shaderCaps()->dstReadInShaderSupport()) {
+ props |= AnalysisProperties::kIgnoresInputColor;
+ } else {
+ // For LCD blending, if the color is not opaque we must read the dst in shader even if
+ // we have dual source blending. The opaqueness check must be done after blending so for
+ // simplicity we only allow src-over to not take the dst read path (though src, src-in,
+ // and DstATop would also work). We also fall into the dst read case for src-over if we
+ // do not have dual source blending.
+ if (SkBlendMode::kSrcOver != mode ||
+ !color.isOpaque() ||
+ !caps.shaderCaps()->dualSourceBlendingSupport()) {
+ props |= AnalysisProperties::kReadsDstInShader;
}
- } else if (formula.hasSecondaryOutput()) {
- props |= AnalysisProperties::kReadsDstInShader;
}
} else {
- // For LCD blending, if the color is not opaque we must read the dst in shader even if we
- // have dual source blending.
- if (isLCD && !color.isOpaque()) {
- props |= AnalysisProperties::kReadsDstInShader;
+ // With dual-source blending we never need the destination color in the shader.
+ if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
+ // Mixed samples implicity computes a fractional coverage from sample coverage. This
+ // could affect the formula used. However, we don't expect to have mixed samples without
+ // dual source blending.
+ SkASSERT(!caps.usesMixedSamples());
+ if (formula.hasSecondaryOutput()) {
+ props |= AnalysisProperties::kReadsDstInShader;
+ }
}
}
+
if (!formula.modifiesDst() || !formula.usesInputColor()) {
props |= AnalysisProperties::kIgnoresInputColor;
}
diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp
index f000077..90c9b50 100644
--- a/tests/GrPorterDuffTest.cpp
+++ b/tests/GrPorterDuffTest.cpp
@@ -56,6 +56,7 @@
kISAModulate_OutputType,
kISCModulate_OutputType
};
+static const int kInvalid_OutputType = -1;
static GrProcessorSet::Analysis do_analysis(const GrXPFactory* xpf,
const GrProcessorAnalysisColor& colorInput,
@@ -77,16 +78,24 @@
GrProcessorAnalysisColor inputColor, GrProcessorAnalysisCoverage inputCoverage) {
const GrXPFactory* xpf = GrPorterDuffXPFactory::Get(xfermode);
+ bool isLCD = GrProcessorAnalysisCoverage::kLCD == inputCoverage;
+
GrProcessorSet::Analysis analysis = do_analysis(xpf, inputColor, inputCoverage, caps);
fCompatibleWithCoverageAsAlpha = analysis.isCompatibleWithCoverageAsAlpha();
fCanCombineOverlappedStencilAndCover = analysis.canCombineOverlappedStencilAndCover();
fIgnoresInputColor = analysis.inputColorIsIgnored();
sk_sp<const GrXferProcessor> xp(
GrXPFactory::MakeXferProcessor(xpf, inputColor, inputCoverage, false, caps));
- TEST_ASSERT(!analysis.requiresDstTexture());
+ TEST_ASSERT(!analysis.requiresDstTexture() ||
+ (isLCD &&
+ !caps.shaderCaps()->dstReadInShaderSupport() &&
+ (SkBlendMode::kSrcOver != xfermode ||
+ !inputColor.isOpaque())));
GetXPOutputTypes(xp.get(), &fPrimaryOutputType, &fSecondaryOutputType);
xp->getBlendInfo(&fBlendInfo);
- TEST_ASSERT(!xp->willReadDstColor());
+ TEST_ASSERT(!xp->willReadDstColor() ||
+ (isLCD && (SkBlendMode::kSrcOver != xfermode ||
+ !inputColor.isOpaque())));
TEST_ASSERT(xp->hasSecondaryOutput() == GrBlendCoeffRefsSrc2(fBlendInfo.fDstBlend));
}
@@ -115,34 +124,34 @@
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
- TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kSrc:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kDst:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
- TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kSrcOver:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
@@ -159,121 +168,121 @@
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kSrcIn:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kDstIn:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kISAModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
- TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kSrcOut:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kDstOut:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kSAModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kSrcATop:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kDstATop:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kISAModulate_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kXor:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kPlus:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kModulate:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kISCModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
- TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
- TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkBlendMode::kScreen:
TEST_ASSERT(!xpi.fCanCombineOverlappedStencilAndCover);
TEST_ASSERT(!xpi.fIgnoresInputColor);
TEST_ASSERT(!xpi.fCompatibleWithCoverageAsAlpha);
- TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
- TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kInvalid_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
- TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
default: