Chromium Code Reviews| Index: src/gpu/effects/GrPorterDuffXferProcessor.cpp |
| diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
| index 5f34f75854838a6d419eedcabf366b0dde7586c5..17903a70fd2b12858ba7e52d89925c624039acc8 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) |
| /** |
|
robertphillips
2015/09/03 13:28:41
coeef -> coeff ?
egdaniel
2015/09/03 13:50:38
Done.
|
| + * Basic coeef 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); |
| } |
| @@ -700,11 +750,7 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, |
|
robertphillips
2015/09/03 13:28:41
Can/should this go in a header now ?
egdaniel
2015/09/03 13:50:38
Done.
|
| bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, |
| uint32_t knownColorFlags) const { |
| - if (SkXfermode::kSrcOver_Mode == fXfermode && |
| - kRGBA_GrColorComponentFlags == knownColorFlags) { |
| - return true; |
| - } |
| - return false; |
| + return true; |
| } |
| void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, |
| @@ -745,8 +791,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. |