Chromium Code Reviews| Index: src/gpu/effects/GrPorterDuffXferProcessor.cpp |
| diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
| index c1db0ca091969dda1f68bb89c6d5391f142ff5d7..49b64458bc0c08bc327fb4e07895a2e5a9330c69 100644 |
| --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
| +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
| @@ -53,37 +53,26 @@ public: |
| /// @name Stage Output Types |
| //// |
| - enum PrimaryOutputType { |
| - kNone_PrimaryOutputType, |
| - kColor_PrimaryOutputType, |
| - kCoverage_PrimaryOutputType, |
| + enum OutputType { |
| + kNone_OutputType, |
| + kColor_OutputType, |
| + kCoverage_OutputType, |
| // Modulate color and coverage, write result as the color output. |
| - kModulate_PrimaryOutputType, |
| + kModulate_OutputType, |
| + // Write coverage * (1 - colorA) as the color output. |
| + kCoverageISA_OutputType, |
| + // Write coverage * (1 - colorRGBA) as the color output. |
| + kCoverageISC_OutputType, |
| // 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 |
| + // in the shader. This is only vaid for the primary output, and secondary output is ignored |
| + // if you use this. Uses the equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D |
| + kCustom_OutputType |
| }; |
| - enum SecondaryOutputType { |
| - // There is no secondary output |
| - kNone_SecondaryOutputType, |
| - // Writes coverage as the secondary output. Only set if dual source blending is supported |
| - // and primary output is kModulate. |
| - kCoverage_SecondaryOutputType, |
| - // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending |
| - // is supported and primary output is kModulate. |
| - kCoverageISA_SecondaryOutputType, |
| - // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source |
| - // blending is supported and primary output is kModulate. |
| - kCoverageISC_SecondaryOutputType, |
| - |
| - kSecondaryOutputTypeCnt, |
| - }; |
| - |
| - PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; } |
| - SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; } |
| + OutputType primaryOutputType() const { return fPrimaryOutputType; } |
| + OutputType secondaryOutputType() const { return fSecondaryOutputType; } |
| + GrBlendEquation getBlendEquation() const { return fBlendEquation; } |
| GrBlendCoeff getSrcBlend() const { return fSrcBlend; } |
| GrBlendCoeff getDstBlend() const { return fDstBlend; } |
| @@ -101,18 +90,17 @@ private: |
| void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { |
| if (!this->willReadDstColor()) { |
| + blendInfo->fEquation = fBlendEquation; |
| blendInfo->fSrcBlend = fSrcBlend; |
| blendInfo->fDstBlend = fDstBlend; |
| - } else { |
| - blendInfo->fSrcBlend = kOne_GrBlendCoeff; |
| - blendInfo->fDstBlend = kZero_GrBlendCoeff; |
| } |
| blendInfo->fBlendConstant = fBlendConstant; |
| } |
| bool onIsEqual(const GrXferProcessor& xpBase) const override { |
| const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>(); |
| - if (fSrcBlend != xp.fSrcBlend || |
| + if (fBlendEquation != xp.fBlendEquation || |
| + fSrcBlend != xp.fSrcBlend || |
| fDstBlend != xp.fDstBlend || |
| fBlendConstant != xp.fBlendConstant || |
| fPrimaryOutputType != xp.fPrimaryOutputType || |
| @@ -129,17 +117,48 @@ private: |
| void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrDrawTargetCaps& caps, |
| bool hasSolidCoverage); |
| - GrBlendCoeff fSrcBlend; |
| - GrBlendCoeff fDstBlend; |
| - GrColor fBlendConstant; |
| - PrimaryOutputType fPrimaryOutputType; |
| - SecondaryOutputType fSecondaryOutputType; |
| + GrBlendEquation fBlendEquation; |
| + GrBlendCoeff fSrcBlend; |
| + GrBlendCoeff fDstBlend; |
| + GrColor fBlendConstant; |
| + OutputType fPrimaryOutputType; |
| + OutputType fSecondaryOutputType; |
| typedef GrXferProcessor INHERITED; |
| }; |
| /////////////////////////////////////////////////////////////////////////////// |
| +static void append_color_output(GrGLXPFragmentBuilder* fsBuilder, |
| + PorterDuffXferProcessor::OutputType outputType, |
| + const char* outputName, const char* inputColor, |
| + const char* inputCoverage) { |
| + switch (outputType) { |
| + case PorterDuffXferProcessor::kNone_OutputType: |
| + fsBuilder->codeAppendf("%s = vec4(0);", outputName); |
| + break; |
| + case PorterDuffXferProcessor::kColor_OutputType: |
| + fsBuilder->codeAppendf("%s = %s;", outputName, inputColor); |
| + break; |
| + case PorterDuffXferProcessor::kCoverage_OutputType: |
| + fsBuilder->codeAppendf("%s = %s;", outputName, inputCoverage); |
| + break; |
| + case PorterDuffXferProcessor::kModulate_OutputType: |
| + fsBuilder->codeAppendf("%s = %s * %s;", outputName, inputColor, inputCoverage); |
| + break; |
| + case PorterDuffXferProcessor::kCoverageISA_OutputType: |
| + fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", |
| + outputName, inputColor, inputCoverage); |
| + break; |
| + case PorterDuffXferProcessor::kCoverageISC_OutputType: |
| + fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", |
| + outputName, inputColor, inputCoverage); |
| + break; |
| + default: |
| + SkFAIL("Unexpected Output"); |
| + } |
| +} |
| + |
| bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff, |
| const char* colorName, const char* srcColorName, |
| const char* dstColorName, bool hasPrevious) { |
| @@ -205,46 +224,14 @@ private: |
| void onEmitCode(const EmitArgs& args) override { |
| const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>(); |
| GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); |
| - if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutputType()) { |
| + if (PorterDuffXferProcessor::kCustom_OutputType != 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); |
| - break; |
| - case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType: |
| - fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", |
| - args.fOutputSecondary, args.fInputColor, |
| - args.fInputCoverage); |
| - break; |
| - case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType: |
| - fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", |
| - args.fOutputSecondary, args.fInputColor, |
| - args.fInputCoverage); |
| - break; |
| - 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"); |
| + if (PorterDuffXferProcessor::kNone_OutputType != xp.secondaryOutputType()) { |
| + append_color_output(fsBuilder, xp.secondaryOutputType(), args.fOutputSecondary, |
| + args.fInputColor, args.fInputCoverage); |
| } |
| + append_color_output(fsBuilder, xp.primaryOutputType(), args.fOutputPrimary, |
| + args.fInputColor, args.fInputCoverage); |
| } else { |
| SkASSERT(xp.willReadDstColor()); |
| @@ -280,11 +267,12 @@ PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend, |
| const GrDeviceCoordTexture* dstCopy, |
| bool willReadDstColor) |
| : INHERITED(dstCopy, willReadDstColor) |
| + , fBlendEquation(kAdd_GrBlendEquation) |
| , fSrcBlend(srcBlend) |
| , fDstBlend(dstBlend) |
| , fBlendConstant(constant) |
| - , fPrimaryOutputType(kModulate_PrimaryOutputType) |
| - , fSecondaryOutputType(kNone_SecondaryOutputType) { |
| + , fPrimaryOutputType(kModulate_OutputType) |
| + , fSecondaryOutputType(kNone_OutputType) { |
| this->initClassID<PorterDuffXferProcessor>(); |
| } |
| @@ -317,41 +305,59 @@ void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags |
| const GrDrawTargetCaps& caps, |
| bool hasSolidCoverage) { |
| if (this->willReadDstColor()) { |
| - fPrimaryOutputType = kCustom_PrimaryOutputType; |
| + fPrimaryOutputType = kCustom_OutputType; |
| return; |
| } |
| if (optFlags & kIgnoreColor_OptFlag) { |
| if (optFlags & kIgnoreCoverage_OptFlag) { |
| - fPrimaryOutputType = kNone_PrimaryOutputType; |
| + fPrimaryOutputType = kNone_OutputType; |
| return; |
| } else { |
| - fPrimaryOutputType = kCoverage_PrimaryOutputType; |
| + fPrimaryOutputType = kCoverage_OutputType; |
| return; |
| } |
| } else if (optFlags & kIgnoreCoverage_OptFlag) { |
| - fPrimaryOutputType = kColor_PrimaryOutputType; |
| + fPrimaryOutputType = kColor_OutputType; |
| return; |
| } |
| - // If we do have coverage determine whether it matters. Dual source blending is expensive so |
| - // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source |
| - // blending if we have any effective coverage stages OR the geometry processor doesn't emits |
| - // solid coverage. |
| + // If we do have coverage determine whether it matters. Coverage drawing mode "just works", |
| + // without the need for special handling. (We get coverage when there are any effective coverage |
| + // stages OR the geometry processor doesn't emit solid coverage.) |
| if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) { |
| + // Try to handle coverage using an alternate blend equation. Dual source blending is |
| + // expensive and not supported on all platforms. |
| + if (kZero_GrBlendCoeff == fSrcBlend) { |
|
egdaniel
2015/05/15 14:58:03
I wonder if it is time to merge getInternalOptimiz
|
| + if (kSA_GrBlendCoeff == fDstBlend) { |
| + // The formula with f=coverage is: f * D * Sa + (1-f) * D |
| + // This can be rewritten as: D - [f * (1-Sa)] * D |
| + fBlendEquation = kReverseSubtract_GrBlendEquation; |
| + fDstBlend = kOne_GrBlendCoeff; |
| + fSrcBlend = kDC_GrBlendCoeff; |
| + fPrimaryOutputType = kCoverageISA_OutputType; |
| + return; |
| + } else if (kSC_GrBlendCoeff == fDstBlend) { |
| + // The formula with f=coverage is: f * D * S + (1-f) * D |
| + // This can be rewritten as: D - [f * (1-S)] * D |
| + fBlendEquation = kReverseSubtract_GrBlendEquation; |
| + fDstBlend = kOne_GrBlendCoeff; |
| + fSrcBlend = kDC_GrBlendCoeff; |
| + fPrimaryOutputType = kCoverageISC_OutputType; |
| + return; |
| + } |
| + } |
| if (caps.shaderCaps()->dualSourceBlendingSupport()) { |
| if (kZero_GrBlendCoeff == fDstBlend) { |
| // write the coverage value to second color |
| - fSecondaryOutputType = kCoverage_SecondaryOutputType; |
| + fSecondaryOutputType = kCoverage_OutputType; |
| fDstBlend = kIS2C_GrBlendCoeff; |
| + return; |
| } else if (kSA_GrBlendCoeff == fDstBlend) { |
| // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. |
| - fSecondaryOutputType = kCoverageISA_SecondaryOutputType; |
| - fDstBlend = kIS2C_GrBlendCoeff; |
| - } else if (kSC_GrBlendCoeff == fDstBlend) { |
| - // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. |
| - fSecondaryOutputType = kCoverageISC_SecondaryOutputType; |
| + fSecondaryOutputType = kCoverageISA_OutputType; |
| fDstBlend = kIS2C_GrBlendCoeff; |
| + return; |
| } |
| } |
| } |
| @@ -459,7 +465,7 @@ PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, |
| } |
| bool PorterDuffXferProcessor::hasSecondaryOutput() const { |
| - return kNone_SecondaryOutputType != fSecondaryOutputType; |
| + return kNone_OutputType != fSecondaryOutputType; |
| } |
| /////////////////////////////////////////////////////////////////////////////// |
| @@ -777,15 +783,25 @@ bool GrPorterDuffXPFactory::willReadDstColor(const GrDrawTargetCaps& caps, |
| 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; |
| + switch (fDstCoeff) { |
| + case kZero_GrBlendCoeff: |
| + if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) { |
| + return false; |
| + } |
| + break; |
| + case kSA_GrBlendCoeff: |
| + // Reduces to: coeffS * (Cov*S) + D |
| + if (srcAIsOne) { |
| + return false; |
| + } |
| + // fallthrough |
| + case kSC_GrBlendCoeff: |
| + // Can be implemented with kReverseSubtract_GrBlendEquation. |
| + if (kZero_GrBlendCoeff == fSrcCoeff) { |
| + return false; |
| + } |
| + break; |
| + default: break; |
| } |
| // We can always blend correctly if we have solid coverage. |