Delay copying effects from DS or ODS till end of creating ODS

Also delay the removal of fixed function VA's until so we only have to do a single removal step

BUG=skia:

Review URL: https://codereview.chromium.org/634073002
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index 19507c0..4a6cd14 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -35,21 +35,52 @@
            drawState.getFixedFunctionVertexAttribIndices(),
            sizeof(fFixedFunctionVertexAttribIndices));
 
-
     fInputColorIsUsed = true;
     fInputCoverageIsUsed = true;
 
+    int firstColorStageIdx = 0;
+    int firstCoverageStageIdx = 0;
+    bool separateCoverageFromColor;
+
+    uint8_t fixedFunctionVAToRemove = 0;
+
+    this->computeEffectiveColorStages(drawState, &firstColorStageIdx, &fixedFunctionVAToRemove);
+    this->computeEffectiveCoverageStages(drawState, &firstCoverageStageIdx);
+    this->adjustFromBlendOpts(drawState, &firstColorStageIdx, &firstCoverageStageIdx,
+                              &fixedFunctionVAToRemove);
+    // Should not be setting any more FFVA to be removed at this point
+    this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove);
+    this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx);
+    this->setOutputStateInfo(drawState, caps, firstCoverageStageIdx, &separateCoverageFromColor);
+
+    // Copy GeometryProcesssor from DS or ODS
     if (drawState.hasGeometryProcessor()) {
         fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor())));
     } else {
         fGeometryProcessor.reset(NULL);
     }
 
-    this->copyEffectiveColorStages(drawState);
-    this->copyEffectiveCoverageStages(drawState);
-    this->adjustFromBlendOpts();
-    this->getStageStats();
-    this->setOutputStateInfo(caps);
+    // Copy Color Stages from DS to ODS
+    if (firstColorStageIdx < drawState.numColorStages()) {
+        fColorStages.reset(&drawState.getColorStage(firstColorStageIdx),
+                           drawState.numColorStages() - firstColorStageIdx);
+    } else {
+        fColorStages.reset();
+    }
+
+    // Copy Coverage Stages from DS to ODS
+    if (drawState.numCoverageStages() > 0 && separateCoverageFromColor) {
+        fCoverageStages.reset(&drawState.getCoverageStage(firstCoverageStageIdx),
+                              drawState.numCoverageStages() - firstCoverageStageIdx);
+    } else {
+        fCoverageStages.reset();
+        if (drawState.numCoverageStages() > 0) {
+            // TODO: Once we have flag to know if we only multiply on stages, only push coverage
+            // into color stages if everything is multiply
+            fColorStages.push_back_n(drawState.numCoverageStages() - firstCoverageStageIdx,
+                                     &drawState.getCoverageStage(firstCoverageStageIdx));
+        }
+    }
 };
 
 GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
@@ -88,55 +119,51 @@
     return drawState.fCachedOptState;
 }
 
-void GrOptDrawState::setOutputStateInfo(const GrDrawTargetCaps& caps) {
+void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
+                                        const GrDrawTargetCaps& caps,
+                                        int firstCoverageStageIdx,
+                                        bool* separateCoverageFromColor) {
     // Set this default and then possibly change our mind if there is coverage.
     fPrimaryOutputType = kModulate_PrimaryOutputType;
     fSecondaryOutputType = kNone_SecondaryOutputType;
 
     // If we do have coverage determine whether it matters.
-    bool separateCoverageFromColor = this->hasGeometryProcessor();
+    *separateCoverageFromColor = this->hasGeometryProcessor();
     if (!this->isCoverageDrawing() &&
-        (this->numCoverageStages() > 0 ||
-         this->hasGeometryProcessor() ||
+        (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
+         ds.hasGeometryProcessor() ||
          this->hasCoverageVertexAttribute())) {
 
         if (caps.dualSourceBlendingSupport()) {
             if (kZero_GrBlendCoeff == fDstBlend) {
                 // write the coverage value to second color
                 fSecondaryOutputType =  kCoverage_SecondaryOutputType;
-                separateCoverageFromColor = true;
+                *separateCoverageFromColor = true;
                 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
             } else if (kSA_GrBlendCoeff == fDstBlend) {
                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
-                separateCoverageFromColor = true;
+                *separateCoverageFromColor = true;
                 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
             } else if (kSC_GrBlendCoeff == fDstBlend) {
                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
-                separateCoverageFromColor = true;
+                *separateCoverageFromColor = true;
                 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
             }
         } else if (fReadsDst &&
                    kOne_GrBlendCoeff == fSrcBlend &&
                    kZero_GrBlendCoeff == fDstBlend) {
             fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
-            separateCoverageFromColor = true;
+            *separateCoverageFromColor = true;
         }
     }
-
-    // TODO: Once we have flag to know if we only multiply on stages, only push coverage into color
-    // stages if everything is multipy
-    if (!separateCoverageFromColor) {
-        for (int s = 0; s < this->numCoverageStages(); ++s) {
-            fColorStages.push_back(this->getCoverageStage(s));
-        }
-        fCoverageStages.reset();
-    }
 }
 
-void GrOptDrawState::adjustFromBlendOpts() {
-
+void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
+                                         int* firstColorStageIdx,
+                                         int* firstCoverageStageIdx,
+                                         uint8_t* fixedFunctionVAToRemove) {
     switch (fBlendOptFlags) {
         case kNone_BlendOpt:
         case kSkipDraw_BlendOptFlag:
@@ -147,22 +174,21 @@
         case kEmitCoverage_BlendOptFlag:
             fColor = 0xffffffff;
             fInputColorIsUsed = true;
-            fColorStages.reset();
-            this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
+            *firstColorStageIdx = ds.numColorStages();
+            *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
             break;
         case kEmitTransBlack_BlendOptFlag:
             fColor = 0;
             fCoverage = 0xff;
             fInputColorIsUsed = true;
             fInputCoverageIsUsed = true;
-            fColorStages.reset();
-            fCoverageStages.reset();
-            this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding |
-                                                   0x1 << kCoverage_GrVertexAttribBinding);
+            *firstColorStageIdx = ds.numColorStages();
+            *firstCoverageStageIdx = ds.numCoverageStages();
+            *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
+                                         0x1 << kCoverage_GrVertexAttribBinding);
             break;
         default:
             SkFAIL("Unknown BlendOptFlag");
-
     }
 }
 
@@ -201,9 +227,8 @@
     fVAPtr = fOptVA.get();
 }
 
-void GrOptDrawState::copyEffectiveColorStages(const GrDrawState& ds) {
-    int firstColorStage = 0;
-
+void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds, int* firstColorStageIdx,
+                                                 uint8_t* fixedFunctionVAToRemove) {
     // Set up color and flags for ConstantColorComponent checks
     GrProcessor::InvariantOutput inout;
     inout.fIsSingleComponent = false;
@@ -224,28 +249,21 @@
     for (int i = 0; i < ds.numColorStages(); ++i) {
         const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
         if (!fp->willUseInputColor()) {
-            firstColorStage = i;
+            *firstColorStageIdx = i;
             fInputColorIsUsed = false;
         }
         fp->computeInvariantOutput(&inout);
         if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
-            firstColorStage = i + 1;
+            *firstColorStageIdx = i + 1;
             fColor = inout.fColor;
             fInputColorIsUsed = true;
-            this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
+            *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
         }
     }
-    if (firstColorStage < ds.numColorStages()) {
-        fColorStages.reset(&ds.getColorStage(firstColorStage),
-                           ds.numColorStages() - firstColorStage);
-    } else {
-        fColorStages.reset();
-    }
 }
 
-void GrOptDrawState::copyEffectiveCoverageStages(const GrDrawState& ds) {
-    int firstCoverageStage = 0;
-
+void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
+                                                    int* firstCoverageStageIdx) {
     // We do not try to optimize out constantColor coverage effects here. It is extremely rare
     // to have a coverage effect that returns a constant value for all four channels. Thus we
     // save having to make extra virtual calls by not checking for it.
@@ -256,17 +274,11 @@
     for (int i = 0; i < ds.numCoverageStages(); ++i) {
         const GrProcessor* processor = ds.getCoverageStage(i).getProcessor();
         if (!processor->willUseInputColor()) {
-            firstCoverageStage = i;
+            *firstCoverageStageIdx = i;
             fInputCoverageIsUsed = false;
         }
     }
 #endif
-    if (ds.numCoverageStages() > 0) {
-        fCoverageStages.reset(&ds.getCoverageStage(firstCoverageStage),
-                              ds.numCoverageStages() - firstCoverageStage);
-    } else {
-        fCoverageStages.reset();
-    }
 }
 
 static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
@@ -278,24 +290,26 @@
     }
 }
 
-void GrOptDrawState::getStageStats() {
+void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
+                                   int firstCoverageStageIdx) {
     // We will need a local coord attrib if there is one currently set on the optState and we are
     // actually generating some effect code
-    fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() && this->numTotalStages() > 0;
+    fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() &&
+        ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;
 
     fReadsDst = false;
     fReadsFragPosition = false;
 
-    for (int s = 0; s < this->numColorStages(); ++s) {
-        const GrFragmentStage& stage = this->getColorStage(s);
+    for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
+        const GrFragmentStage& stage = ds.getColorStage(s);
         get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
     }
-    for (int s = 0; s < this->numCoverageStages(); ++s) {
-        const GrFragmentStage& stage = this->getCoverageStage(s);
+    for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
+        const GrFragmentStage& stage = ds.getCoverageStage(s);
         get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
     }
-    if (this->hasGeometryProcessor()) {
-        const GrGeometryStage& stage = *this->getGeometryProcessor();
+    if (ds.hasGeometryProcessor()) {
+        const GrGeometryStage& stage = *ds.getGeometryProcessor();
         fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition();
     }
 }
diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h
index 1f8c442..2721e9d 100644
--- a/src/gpu/GrOptDrawState.h
+++ b/src/gpu/GrOptDrawState.h
@@ -375,19 +375,17 @@
      * Loops through all the color stage effects to check if the stage will ignore color input or
      * always output a constant color. In the ignore color input case we can ignore all previous
      * stages. In the constant color case, we can ignore all previous stages and
-     * the current one and set the state color to the constant color. Once we determine the so
-     * called first effective stage, we copy all the effective stages into our optimized
-     * state.
+     * the current one and set the state color to the constant color.
      */
-    void copyEffectiveColorStages(const GrDrawState& ds);
+    void computeEffectiveColorStages(const GrDrawState& ds, int* firstColorStageIdx,
+                                     uint8_t* fixFunctionVAToRemove);
 
     /**
      * Loops through all the coverage stage effects to check if the stage will ignore color input.
      * If a coverage stage will ignore input, then we can ignore all coverage stages before it. We
-     * loop to determine the first effective coverage stage, and then copy all of our effective
-     * coverage stages into our optimized state.
+     * loop to determine the first effective coverage stage.
      */
-    void copyEffectiveCoverageStages(const GrDrawState& ds);
+    void computeEffectiveCoverageStages(const GrDrawState& ds, int* firstCoverageStageIdx);
 
     /**
      * This function takes in a flag and removes the corresponding fixed function vertex attributes.
@@ -400,20 +398,22 @@
      * Alter the OptDrawState (adjusting stages, vertex attribs, flags, etc.) based on the
      * BlendOptFlags.
      */
-    void adjustFromBlendOpts();
+    void adjustFromBlendOpts(const GrDrawState& ds, int* firstColorStageIdx,
+                             int* firstCoverageStageIdx, uint8_t* fixedFunctionVAToRemove);
 
     /**
      * Loop over the effect stages to determine various info like what data they will read and what
      * shaders they require.
      */
-    void getStageStats();
+    void getStageStats(const GrDrawState& ds, int firstColorStageIdx, int firstCoverageStageIdx);
 
     /**
      * Calculates the primary and secondary output types of the shader. For certain output types
      * the function may adjust the blend coefficients. After this function is called the src and dst
      * blend coeffs will represent those used by backend API.
      */
-    void setOutputStateInfo(const GrDrawTargetCaps&);
+    void setOutputStateInfo(const GrDrawState& ds, const GrDrawTargetCaps&,
+                            int firstCoverageStageIdx, bool* separateCoverageFromColor);
 
     bool isEqual(const GrOptDrawState& that) const;
 
@@ -433,7 +433,7 @@
     GrBlendCoeff                        fSrcBlend;
     GrBlendCoeff                        fDstBlend;
 
-    typedef SkSTArray<4, GrFragmentStage> FragmentStageArray;
+    typedef SkSTArray<8, GrFragmentStage> FragmentStageArray;
     SkAutoTDelete<GrGeometryStage>        fGeometryProcessor;
     FragmentStageArray                    fColorStages;
     FragmentStageArray                    fCoverageStages;