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/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 3282f13..c00a5ce 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -454,168 +454,24 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-// Some blend modes allow folding a partial coverage value into the color's
-// alpha channel, while others will blend incorrectly.
-bool GrDrawTarget::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 depth
-     * coefficient in terms of S' and D.
-     */
-    GrBlendCoeff dstCoeff = this->getDrawState().getDstBlendCoeff();
-    return kOne_GrBlendCoeff == dstCoeff ||
-           kISA_GrBlendCoeff == dstCoeff ||
-           kISC_GrBlendCoeff == dstCoeff ||
-           this->getDrawState().isCoverageDrawing();
-}
-
-namespace {
-GrVertexLayout default_blend_opts_vertex_layout() {
-    GrVertexLayout layout = 0;
-    return layout;
-}
-}
-
-GrDrawTarget::BlendOptFlags
-GrDrawTarget::getBlendOpts(bool forceCoverage,
-                           GrBlendCoeff* srcCoeff,
-                           GrBlendCoeff* dstCoeff) const {
-
-    const GrDrawState& drawState = this->getDrawState();
-
-    GrVertexLayout layout;
-    if (kNone_GeometrySrcType == this->getGeomSrc().fVertexSrc) {
-        layout = default_blend_opts_vertex_layout();
-    } else {
-        layout = drawState.getVertexLayout();
-    }
-
-    GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
-    if (NULL == srcCoeff) {
-        srcCoeff = &bogusSrcCoeff;
-    }
-    *srcCoeff = drawState.getSrcBlendCoeff();
-
-    if (NULL == dstCoeff) {
-        dstCoeff = &bogusDstCoeff;
-    }
-    *dstCoeff = drawState.getDstBlendCoeff();
-
-    if (drawState.isColorWriteDisabled()) {
-        *srcCoeff = kZero_GrBlendCoeff;
-        *dstCoeff = kOne_GrBlendCoeff;
-    }
-
-    bool srcAIsOne = drawState.srcAlphaWillBeOne(layout);
-    bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
-                         (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
-    bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
-                         (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
-
-    bool covIsZero = !drawState.isCoverageDrawing() &&
-                     !(layout & GrDrawState::kCoverage_VertexLayoutBit) &&
-                     0 == drawState.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 (drawState.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 != drawState.getCoverage() ||
-                       (layout & GrDrawState::kCoverage_VertexLayoutBit) ||
-                       (layout & GrDrawState::kEdge_VertexLayoutBit);
-    for (int s = drawState.getFirstCoverageStage();
-         !hasCoverage && s < GrDrawState::kNumStages;
-         ++s) {
-        if (drawState.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 (drawState.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;
-}
-
 bool GrDrawTarget::willUseHWAALines() const {
-    // there is a conflict between using smooth lines and our use of
-    // premultiplied alpha. Smooth lines tweak the incoming alpha value
-    // but not in a premul-alpha way. So we only use them when our alpha
-    // is 0xff and tweaking the color for partial coverage is OK
+    // There is a conflict between using smooth lines and our use of premultiplied alpha. Smooth
+    // lines tweak the incoming alpha value but not in a premul-alpha way. So we only use them when
+    // our alpha is 0xff and tweaking the color for partial coverage is OK
     if (!fCaps.hwAALineSupport() ||
         !this->getDrawState().isHWAntialiasState()) {
         return false;
     }
-    BlendOptFlags opts = this->getBlendOpts();
-    return (kDisableBlend_BlendOptFlag & opts) &&
-           (kCoverageAsAlpha_BlendOptFlag & opts);
+    GrDrawState::BlendOptFlags opts = this->getDrawState().getBlendOpts();
+    return (GrDrawState::kDisableBlend_BlendOptFlag & opts) &&
+           (GrDrawState::kCoverageAsAlpha_BlendOptFlag & opts);
 }
 
 bool GrDrawTarget::canApplyCoverage() const {
     // we can correctly apply coverage if a) we have dual source blending
     // or b) one of our blend optimizations applies.
     return this->getCaps().dualSourceBlendingSupport() ||
-           kNone_BlendOpt != this->getBlendOpts(true);
+           GrDrawState::kNone_BlendOpt != this->getDrawState().getBlendOpts(true);
 }
 
 ////////////////////////////////////////////////////////////////////////////////