Index: src/gpu/effects/GrPorterDuffXferProcessor.cpp |
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
index 5f34f75854838a6d419eedcabf366b0dde7586c5..4c50e47ab9ae1d3845fb603a4f8d42c639a7cbff 100644 |
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
@@ -31,6 +31,7 @@ public: |
kNone_OutputType, //<! 0 |
kCoverage_OutputType, //<! inputCoverage |
kModulate_OutputType, //<! inputColor * inputCoverage |
+ kSAModulate_OutputType, //<! inputColor.a * inputCoverage |
kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage |
kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage |
@@ -139,6 +140,15 @@ GR_MAKE_BITFIELD_OPS(BlendFormula::Properties); |
kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF) |
/** |
+ * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in |
+ * LCD dst-out. |
+ */ |
+#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \ |
+ INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \ |
+ BlendFormula::kNone_OutputType, \ |
+ kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF) |
+ |
+/** |
* When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set |
* the primary output type to none. |
*/ |
@@ -289,6 +299,24 @@ static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = { |
/* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), |
}}}; |
+static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = { |
+ /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType), |
+ /* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff), |
+ /* dst */ NO_DST_WRITE_FORMULA, |
+ /* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff), |
+ /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
+ /* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff), |
+ /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType), |
+ /* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff), |
+ /* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff), |
+ /* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff), |
+ /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff), |
+ /* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff), |
+ /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), |
+ /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType), |
+ /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), |
+}; |
+ |
static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI, |
const GrProcOptInfo& coveragePOI, |
bool hasMixedSamples, |
@@ -300,6 +328,14 @@ static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI, |
return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode]; |
} |
+static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI, |
+ SkXfermode::Mode xfermode) { |
+ SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode); |
+ SkASSERT(coveragePOI.isFourChannelOutput()); |
+ |
+ return gLCDBlendTable[xfermode]; |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
class PorterDuffXferProcessor : public GrXferProcessor { |
@@ -363,6 +399,13 @@ static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmen |
fsBuilder->codeAppendf("%s = %s;", output, inColor); |
} |
break; |
+ case BlendFormula::kSAModulate_OutputType: |
+ if (xp.readsCoverage()) { |
+ fsBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage); |
+ } else { |
+ fsBuilder->codeAppendf("%s = %s;", output, inColor); |
+ } |
+ break; |
case BlendFormula::kISAModulate_OutputType: |
if (xp.readsCoverage()) { |
fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage); |
@@ -444,7 +487,9 @@ PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, |
if (coveragePOI.isSolidWhite()) { |
optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag; |
} |
- if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) { |
+ if (colorPOI.allStagesMultiplyInput() && |
+ fBlendFormula.canTweakAlphaForCoverage() && |
+ !coveragePOI.isFourChannelOutput()) { |
optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; |
} |
} |
@@ -579,7 +624,6 @@ public: |
private: |
void emitOutputsForBlendState(const EmitArgs& args) override { |
GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); |
- |
fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor, |
args.fInputCoverage); |
} |
@@ -684,12 +728,18 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, |
const GrProcOptInfo& covPOI, |
bool hasMixedSamples, |
const DstTexture* dstTexture) const { |
+ BlendFormula blendFormula; |
if (covPOI.isFourChannelOutput()) { |
- SkASSERT(!dstTexture || !dstTexture->texture()); |
- return PDLCDXferProcessor::Create(fXfermode, colorPOI); |
+ 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); |
} |
- BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode); |
if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) { |
return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode); |
} |
@@ -698,15 +748,6 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, |
return new PorterDuffXferProcessor(blendFormula); |
} |
-bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, |
- uint32_t knownColorFlags) const { |
- if (SkXfermode::kSrcOver_Mode == fXfermode && |
- kRGBA_GrColorComponentFlags == knownColorFlags) { |
- return true; |
- } |
- return false; |
-} |
- |
void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, |
InvariantBlendedColor* blendedColor) const { |
// Find the blended color info based on the formula that does not have coverage. |
@@ -745,8 +786,16 @@ bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, |
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()) { |
- return false; // The LCD XP will abort rather than doing a dst read. |
+ if (SkXfermode::kSrcOver_Mode == fXfermode && |
+ kRGBA_GrColorComponentFlags == colorPOI.validFlags()) { |
+ 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. |