Cache the return values of getBlendOpts in GrDrawState

BUG=skia:
R=bsalomon@google.com

Author: egdaniel@google.com

Review URL: https://codereview.chromium.org/404473007
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 8285a32..14ba6fa 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -59,6 +59,7 @@
 
     this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
     this->setCoverage(paint.getCoverage());
+    this->invalidateBlendOptFlags();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -119,6 +120,7 @@
         overlapCheck |= (mask << offsetShift);
 #endif
     }
+    this->invalidateBlendOptFlags();
     // Positions must be specified.
     SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
 }
@@ -137,6 +139,7 @@
            0xff,
            sizeof(fFixedFunctionVertexAttribIndices));
     fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
+    this->invalidateBlendOptFlags();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -286,16 +289,35 @@
 GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
                                                      GrBlendCoeff* srcCoeff,
                                                      GrBlendCoeff* dstCoeff) const {
-
     GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
     if (NULL == srcCoeff) {
         srcCoeff = &bogusSrcCoeff;
     }
-    *srcCoeff = this->getSrcBlendCoeff();
-
     if (NULL == dstCoeff) {
         dstCoeff = &bogusDstCoeff;
     }
+
+    if (forceCoverage) {
+        return this->calcBlendOpts(true, srcCoeff, dstCoeff);
+    }
+
+    if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
+        *srcCoeff = fOptSrcBlend;
+        *dstCoeff = fOptDstBlend;
+        return fBlendOptFlags;
+    }
+
+    fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
+    fOptSrcBlend = *srcCoeff;
+    fOptDstBlend = *dstCoeff;
+
+    return fBlendOptFlags;
+}
+
+GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
+                                                      GrBlendCoeff* srcCoeff,
+                                                      GrBlendCoeff* dstCoeff) const {
+    *srcCoeff = this->getSrcBlendCoeff();
     *dstCoeff = this->getDstBlendCoeff();
 
     if (this->isColorWriteDisabled()) {
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index de14763..cef21af 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -59,6 +59,7 @@
             for (int i = 0; i < fCoverageStages.count(); ++i) {
                 fCoverageStages[i].localCoordChange(preConcatMatrix);
             }
+            this->invalidateBlendOptFlags();
         }
     }
 
@@ -249,7 +250,10 @@
      *
      *  @param color    the color to set.
      */
-    void setColor(GrColor color) { fColor = color; }
+    void setColor(GrColor color) {
+        fColor = color;
+        this->invalidateBlendOptFlags();
+    }
 
     GrColor getColor() const { return fColor; }
 
@@ -308,6 +312,7 @@
      */
     void setCoverage(uint8_t coverage) {
         fCoverage = GrColorPackRGBA(coverage, coverage, coverage, coverage);
+        this->invalidateBlendOptFlags();
     }
 
     uint8_t getCoverage() const {
@@ -343,12 +348,14 @@
     const GrEffect* addColorEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
         SkASSERT(NULL != effect);
         SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1));
+        this->invalidateBlendOptFlags();
         return effect;
     }
 
     const GrEffect* addCoverageEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
         SkASSERT(NULL != effect);
         SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1));
+        this->invalidateBlendOptFlags();
         return effect;
     }
 
@@ -391,12 +398,16 @@
 
         void set(GrDrawState* ds) {
             if (NULL != fDrawState) {
-                int n = fDrawState->fColorStages.count() - fColorEffectCnt;
-                SkASSERT(n >= 0);
-                fDrawState->fColorStages.pop_back_n(n);
-                n = fDrawState->fCoverageStages.count() - fCoverageEffectCnt;
+                int m = fDrawState->fColorStages.count() - fColorEffectCnt;
+                SkASSERT(m >= 0);
+                fDrawState->fColorStages.pop_back_n(m);
+
+                int n = fDrawState->fCoverageStages.count() - fCoverageEffectCnt;
                 SkASSERT(n >= 0);
                 fDrawState->fCoverageStages.pop_back_n(n);
+                if (m + n > 0) {
+                    fDrawState->invalidateBlendOptFlags();
+                }
                 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
             }
             fDrawState = ds;
@@ -449,6 +460,7 @@
     void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
         fSrcBlend = srcCoeff;
         fDstBlend = dstCoeff;
+        this->invalidateBlendOptFlags();
     #ifdef SK_DEBUG
         if (GrBlendCoeffRefsDst(dstCoeff)) {
             GrPrintf("Unexpected dst blend coeff. Won't work correctly with coverage stages.\n");
@@ -478,7 +490,10 @@
      *
      * @param constant the constant to set
      */
-    void setBlendConstant(GrColor constant) { fBlendConstant = constant; }
+    void setBlendConstant(GrColor constant) {
+        fBlendConstant = constant;
+        this->invalidateBlendOptFlags();
+    }
 
     /**
      * Retrieves the last value set by setBlendConstant()
@@ -523,9 +538,18 @@
          * Emit transparent black instead of the src color, no need to compute coverage.
          */
         kEmitTransBlack_BlendOptFlag    = 0x10,
+        /**
+         * Flag used to invalidate the cached BlendOptFlags, OptSrcCoeff, and OptDstCoeff cached by
+         * the get BlendOpts function. 
+         */
+        kInvalid_BlendOptFlag        = 0x20,
     };
     GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags);
 
+    void invalidateBlendOptFlags() {
+        fBlendOptFlags = kInvalid_BlendOptFlag;
+    }
+
     /**
      * Determines what optimizations can be applied based on the blend. The coefficients may have
      * to be tweaked in order for the optimization to work. srcCoeff and dstCoeff are optional
@@ -535,6 +559,9 @@
      *
      * Subclasses of GrDrawTarget that actually draw (as opposed to those that just buffer for
      * playback) must call this function and respect the flags that replace the output color.
+     *
+     * If the cached BlendOptFlags does not have the invalidate bit set, then getBlendOpts will
+     * simply returned the cached flags and coefficients. Otherwise it will calculate the values. 
      */
     BlendOptFlags getBlendOpts(bool forceCoverage = false,
                                GrBlendCoeff* srcCoeff = NULL,
@@ -689,6 +716,7 @@
      */
     void setStencil(const GrStencilSettings& settings) {
         fStencilSettings = settings;
+        this->invalidateBlendOptFlags();
     }
 
     /**
@@ -696,6 +724,7 @@
      */
     void disableStencil() {
         fStencilSettings.setDisabled();
+        this->invalidateBlendOptFlags();
     }
 
     const GrStencilSettings& getStencil() const { return fStencilSettings; }
@@ -750,6 +779,7 @@
 
     void resetStateFlags() {
         fFlagBits = 0;
+        this->invalidateBlendOptFlags();
     }
 
     /**
@@ -759,6 +789,7 @@
      */
     void enableState(uint32_t stateBits) {
         fFlagBits |= stateBits;
+        this->invalidateBlendOptFlags();
     }
 
     /**
@@ -768,6 +799,7 @@
      */
     void disableState(uint32_t stateBits) {
         fFlagBits &= ~(stateBits);
+        this->invalidateBlendOptFlags();
     }
 
     /**
@@ -892,6 +924,9 @@
         fDrawFace = that.fDrawFace;
         fColorStages = that.fColorStages;
         fCoverageStages = that.fCoverageStages;
+        fOptSrcBlend = that.fOptSrcBlend;
+        fOptDstBlend = that.fOptDstBlend;
+        fBlendOptFlags = that.fBlendOptFlags;
 
         memcpy(fFixedFunctionVertexAttribIndices,
                that.fFixedFunctionVertexAttribIndices,
@@ -923,8 +958,13 @@
         fStencilSettings.setDisabled();
         fCoverage = 0xffffffff;
         fDrawFace = kBoth_DrawFace;
+
+        this->invalidateBlendOptFlags();
     }
 
+    BlendOptFlags calcBlendOpts(bool forceCoverage = false,
+                               GrBlendCoeff* srcCoeff = NULL,
+                               GrBlendCoeff* dstCoeff = NULL) const;
 
     // These fields are roughly sorted by decreasing likelihood of being different in op==
     SkAutoTUnref<GrRenderTarget>        fRenderTarget;
@@ -943,6 +983,10 @@
     typedef SkSTArray<4, GrEffectStage> EffectStageArray;
     EffectStageArray                    fColorStages;
     EffectStageArray                    fCoverageStages;
+    
+    mutable GrBlendCoeff                        fOptSrcBlend;
+    mutable GrBlendCoeff                        fOptDstBlend;
+    mutable BlendOptFlags                       fBlendOptFlags;
 
     // This is simply a different representation of info in fVertexAttribs and thus does
     // not need to be compared in op==.