Index: src/gpu/effects/GrPorterDuffXferProcessor.cpp |
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
index 506383a29ea9ce969ab103dd0d5333d4f78e8037..c9499a087d95255241c8695dd4249e4e22f44ff1 100644 |
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp |
@@ -53,36 +53,24 @@ 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; } |
GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI, |
const GrProcOptInfo& coveragePOI, |
@@ -90,6 +78,7 @@ public: |
GrColor* overrideColor, |
const GrDrawTargetCaps& caps) override; |
+ 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>(); |
} |
@@ -329,41 +317,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) { |
+ 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; |
Chris Dalton
2015/05/07 01:44:02
This branch is no longer used. Modulate was the on
|
+ return; |
} |
} |
} |
@@ -469,7 +475,7 @@ PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, |
} |
bool PorterDuffXferProcessor::hasSecondaryOutput() const { |
- return kNone_SecondaryOutputType != fSecondaryOutputType; |
+ return kNone_OutputType != fSecondaryOutputType; |
} |
/////////////////////////////////////////////////////////////////////////////// |
@@ -674,15 +680,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. |