Move blend optimization functions to GrDrawState.
Review URL: https://codereview.appspot.com/7300089
git-svn-id: http://skia.googlecode.com/svn/trunk@7703 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 5b434c3..f2c6977 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -538,6 +538,134 @@
////////////////////////////////////////////////////////////////////////////////
+// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
+// others will blend incorrectly.
+bool GrDrawState::canTweakAlphaForCoverage() const {
+ /*
+ The fractional coverage is f.
+ The src and dst coeffs are Cs and Cd.
+ The dst and src colors are S and D.
+ We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
+ we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
+ term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
+ find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
+ Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
+ color by definition.
+ */
+ return kOne_GrBlendCoeff == fCommon.fDstBlend ||
+ kISA_GrBlendCoeff == fCommon.fDstBlend ||
+ kISC_GrBlendCoeff == fCommon.fDstBlend ||
+ this->isCoverageDrawing();
+}
+
+GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
+ GrBlendCoeff* srcCoeff,
+ GrBlendCoeff* dstCoeff) const {
+ GrVertexLayout layout = this->getVertexLayout();
+
+ GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
+ if (NULL == srcCoeff) {
+ srcCoeff = &bogusSrcCoeff;
+ }
+ *srcCoeff = this->getSrcBlendCoeff();
+
+ if (NULL == dstCoeff) {
+ dstCoeff = &bogusDstCoeff;
+ }
+ *dstCoeff = this->getDstBlendCoeff();
+
+ if (this->isColorWriteDisabled()) {
+ *srcCoeff = kZero_GrBlendCoeff;
+ *dstCoeff = kOne_GrBlendCoeff;
+ }
+
+ bool srcAIsOne = this->srcAlphaWillBeOne(layout);
+ bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
+ (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
+ bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
+ (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
+
+ bool covIsZero = !this->isCoverageDrawing() &&
+ !(layout & GrDrawState::kCoverage_VertexLayoutBit) &&
+ 0 == this->getCoverage();
+ // When coeffs are (0,1) there is no reason to draw at all, unless
+ // stenciling is enabled. Having color writes disabled is effectively
+ // (0,1). The same applies when coverage is known to be 0.
+ if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne) || covIsZero) {
+ if (this->getStencil().doesWrite()) {
+ return kDisableBlend_BlendOptFlag |
+ kEmitTransBlack_BlendOptFlag;
+ } else {
+ return kSkipDraw_BlendOptFlag;
+ }
+ }
+
+ // check for coverage due to constant coverage, per-vertex coverage,
+ // edge aa or coverage stage
+ bool hasCoverage = forceCoverage ||
+ 0xffffffff != this->getCoverage() ||
+ (layout & GrDrawState::kCoverage_VertexLayoutBit) ||
+ (layout & GrDrawState::kEdge_VertexLayoutBit);
+ for (int s = this->getFirstCoverageStage();
+ !hasCoverage && s < GrDrawState::kNumStages;
+ ++s) {
+ if (this->isStageEnabled(s)) {
+ hasCoverage = true;
+ }
+ }
+
+ // if we don't have coverage we can check whether the dst
+ // has to read at all. If not, we'll disable blending.
+ if (!hasCoverage) {
+ if (dstCoeffIsZero) {
+ if (kOne_GrBlendCoeff == *srcCoeff) {
+ // if there is no coverage and coeffs are (1,0) then we
+ // won't need to read the dst at all, it gets replaced by src
+ return kDisableBlend_BlendOptFlag;
+ } else if (kZero_GrBlendCoeff == *srcCoeff) {
+ // if the op is "clear" then we don't need to emit a color
+ // or blend, just write transparent black into the dst.
+ *srcCoeff = kOne_GrBlendCoeff;
+ *dstCoeff = kZero_GrBlendCoeff;
+ return kDisableBlend_BlendOptFlag | kEmitTransBlack_BlendOptFlag;
+ }
+ }
+ } else if (this->isCoverageDrawing()) {
+ // we have coverage but we aren't distinguishing it from alpha by request.
+ return kCoverageAsAlpha_BlendOptFlag;
+ } else {
+ // check whether coverage can be safely rolled into alpha
+ // of if we can skip color computation and just emit coverage
+ if (this->canTweakAlphaForCoverage()) {
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ if (dstCoeffIsZero) {
+ if (kZero_GrBlendCoeff == *srcCoeff) {
+ // the source color is not included in the blend
+ // the dst coeff is effectively zero so blend works out to:
+ // (c)(0)D + (1-c)D = (1-c)D.
+ *dstCoeff = kISA_GrBlendCoeff;
+ return kEmitCoverage_BlendOptFlag;
+ } else if (srcAIsOne) {
+ // the dst coeff is effectively zero so blend works out to:
+ // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
+ // If Sa is 1 then we can replace Sa with c
+ // and set dst coeff to 1-Sa.
+ *dstCoeff = kISA_GrBlendCoeff;
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ } else if (dstCoeffIsOne) {
+ // the dst coeff is effectively one so blend works out to:
+ // cS + (c)(1)D + (1-c)D = cS + D.
+ *dstCoeff = kOne_GrBlendCoeff;
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ }
+ return kNone_BlendOpt;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
void GrDrawState::AutoViewMatrixRestore::restore() {
if (NULL != fDrawState) {
fDrawState->setViewMatrix(fViewMatrix);