Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(284)

Unified Diff: src/gpu/effects/GrPorterDuffXferProcessor.cpp

Issue 1124373002: Implement Porter Duff XP with a blend table (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: comment Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698