Fix gpu lcd blending to semi-correctly handle alpha coverage
Bug: skia:6606
Change-Id: I16ccd97f5d047eb7fddfed5310bf669e7435ccdd
Reviewed-on: https://skia-review.googlesource.com/17370
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index 970c289..a2302e0 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -73,13 +73,13 @@
class CustomXP : public GrXferProcessor {
public:
CustomXP(SkBlendMode mode, GrBlendEquation hwBlendEquation)
- : fMode(mode),
- fHWBlendEquation(hwBlendEquation) {
+ : fMode(mode)
+ , fHWBlendEquation(hwBlendEquation) {
this->initClassID<CustomXP>();
}
- CustomXP(bool hasMixedSamples, SkBlendMode mode)
- : INHERITED(true, hasMixedSamples)
+ CustomXP(bool hasMixedSamples, SkBlendMode mode, GrProcessorAnalysisCoverage coverage)
+ : INHERITED(true, hasMixedSamples, coverage)
, fMode(mode)
, fHWBlendEquation(static_cast<GrBlendEquation>(-1)) {
this->initClassID<CustomXP>();
@@ -242,7 +242,7 @@
if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
return sk_sp<GrXferProcessor>(new CustomXP(fMode, fHWBlendEquation));
}
- return sk_sp<GrXferProcessor>(new CustomXP(hasMixedSamples, fMode));
+ return sk_sp<GrXferProcessor>(new CustomXP(hasMixedSamples, fMode, coverage));
}
GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index e3548ad..d3ef717 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -392,7 +392,9 @@
class PorterDuffXferProcessor : public GrXferProcessor {
public:
- PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
+ PorterDuffXferProcessor(BlendFormula blendFormula, GrProcessorAnalysisCoverage coverage)
+ : INHERITED(false, false, coverage)
+ , fBlendFormula(blendFormula) {
this->initClassID<PorterDuffXferProcessor>();
}
@@ -501,8 +503,9 @@
class ShaderPDXferProcessor : public GrXferProcessor {
public:
- ShaderPDXferProcessor(bool hasMixedSamples, SkBlendMode xfermode)
- : INHERITED(true, hasMixedSamples), fXfermode(xfermode) {
+ ShaderPDXferProcessor(bool hasMixedSamples, SkBlendMode xfermode,
+ GrProcessorAnalysisCoverage coverage)
+ : INHERITED(true, hasMixedSamples, coverage), fXfermode(xfermode) {
this->initClassID<ShaderPDXferProcessor>();
}
@@ -649,7 +652,8 @@
///////////////////////////////////////////////////////////////////////////////
PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
- : fBlendConstant(blendConstant)
+ : INHERITED(false, false, GrProcessorAnalysisCoverage::kLCD)
+ , fBlendConstant(blendConstant)
, fAlpha(alpha) {
this->initClassID<PDLCDXferProcessor>();
}
@@ -754,8 +758,9 @@
const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
bool hasMixedSamples, const GrCaps& caps) const {
BlendFormula blendFormula;
- if (coverage == GrProcessorAnalysisCoverage::kLCD) {
- if (SkBlendMode::kSrcOver == fBlendMode && color.isConstant() &&
+ bool isLCD = coverage == GrProcessorAnalysisCoverage::kLCD;
+ if (isLCD) {
+ if (SkBlendMode::kSrcOver == fBlendMode && color.isConstant() && color.isOpaque() &&
!caps.shaderCaps()->dualSourceBlendingSupport() &&
!caps.shaderCaps()->dstReadInShaderSupport()) {
// If we don't have dual source blending or in shader dst reads, we fall back to this
@@ -769,10 +774,12 @@
hasMixedSamples, fBlendMode);
}
- if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
- return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode));
+ if ((blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) ||
+ (isLCD && !color.isOpaque())) {
+ return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode,
+ coverage));
}
- return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
+ return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
}
static inline GrXPFactory::AnalysisProperties analysis_properties(
@@ -781,7 +788,13 @@
using AnalysisProperties = GrXPFactory::AnalysisProperties;
AnalysisProperties props = AnalysisProperties::kNone;
bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage;
- auto formula = gBlendTable[color.isOpaque()][hasCoverage][(int)mode];
+ bool isLCD = GrProcessorAnalysisCoverage::kLCD == coverage;
+ BlendFormula formula;
+ if (isLCD) {
+ formula = gLCDBlendTable[(int)mode];
+ } else {
+ formula = gBlendTable[color.isOpaque()][hasCoverage][(int)mode];
+ }
if (formula.canTweakAlphaForCoverage()) {
props |= AnalysisProperties::kCompatibleWithAlphaAsCoverage;
}
@@ -794,7 +807,7 @@
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()) {
+ if (SkBlendMode::kSrcOver == mode && color.isConstant() && color.isOpaque()) {
props |= AnalysisProperties::kIgnoresInputColor;
} else {
if (get_lcd_blend_formula(mode).hasSecondaryOutput()) {
@@ -804,6 +817,12 @@
} 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;
+ }
}
if (!formula.modifiesDst() || !formula.usesInputColor()) {
props |= AnalysisProperties::kIgnoresInputColor;
@@ -851,7 +870,8 @@
const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
static BlendFormula gSrcOverBlendFormula =
MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
- static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
+ static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula,
+ GrProcessorAnalysisCoverage::kSingleChannel);
return gSrcOverXP;
}
@@ -870,7 +890,7 @@
return nullptr;
}
- if (color.isConstant() && !caps.shaderCaps()->dualSourceBlendingSupport() &&
+ if (color.isConstant() && color.isOpaque() && !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
@@ -880,16 +900,17 @@
BlendFormula blendFormula;
blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
- if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
+ if (!color.isOpaque() ||
+ (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport())) {
return sk_sp<GrXferProcessor>(
- new ShaderPDXferProcessor(hasMixedSamples, SkBlendMode::kSrcOver));
+ new ShaderPDXferProcessor(hasMixedSamples, SkBlendMode::kSrcOver, coverage));
}
- return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
+ return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
}
sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) {
BlendFormula formula = get_blend_formula(false, false, false, blendmode);
- return sk_make_sp<PorterDuffXferProcessor>(formula);
+ return sk_make_sp<PorterDuffXferProcessor>(formula, GrProcessorAnalysisCoverage::kNone);
}
GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties(