OptState owns program descriptor

BUG=skia:

Review URL: https://codereview.chromium.org/674543004
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index 77a9fc8..529e9ed 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -9,12 +9,15 @@
 
 #include "GrDrawState.h"
 #include "GrDrawTargetCaps.h"
+#include "gl/GrGpuGL.h"
 
 GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
                                BlendOptFlags blendOptFlags,
                                GrBlendCoeff optSrcCoeff,
                                GrBlendCoeff optDstCoeff,
-                               const GrDrawTargetCaps& caps) {
+                               GrGpu* gpu,
+                               const GrDeviceCoordTexture* dstCopy,
+                               GrGpu::DrawType drawType) {
     fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()), kWrite_GrIOType);
     fColor = drawState.getColor();
     fCoverage = drawState.getCoverage();
@@ -29,13 +32,14 @@
     fBlendOptFlags = blendOptFlags;
     fSrcBlend = optSrcCoeff;
     fDstBlend = optDstCoeff;
+    GrProgramDesc::DescInfo descInfo;
 
-    memcpy(fFixedFunctionVertexAttribIndices,
+    memcpy(descInfo.fFixedFunctionVertexAttribIndices,
            drawState.getFixedFunctionVertexAttribIndices(),
-           sizeof(fFixedFunctionVertexAttribIndices));
+           sizeof(descInfo.fFixedFunctionVertexAttribIndices));
 
-    fInputColorIsUsed = true;
-    fInputCoverageIsUsed = true;
+    descInfo.fInputColorIsUsed = true;
+    descInfo.fInputCoverageIsUsed = true;
 
     int firstColorStageIdx = 0;
     int firstCoverageStageIdx = 0;
@@ -43,16 +47,18 @@
 
     uint8_t fixedFunctionVAToRemove = 0;
 
-    this->computeEffectiveColorStages(drawState, &firstColorStageIdx, &fixedFunctionVAToRemove);
-    this->computeEffectiveCoverageStages(drawState, &firstCoverageStageIdx);
-    this->adjustFromBlendOpts(drawState, &firstColorStageIdx, &firstCoverageStageIdx,
+    this->computeEffectiveColorStages(drawState, &descInfo, &firstColorStageIdx,
+                                      &fixedFunctionVAToRemove);
+    this->computeEffectiveCoverageStages(drawState, &descInfo, &firstCoverageStageIdx);
+    this->adjustFromBlendOpts(drawState, &descInfo, &firstColorStageIdx, &firstCoverageStageIdx,
                               &fixedFunctionVAToRemove);
     // Should not be setting any more FFVA to be removed at this point
     if (0 != fixedFunctionVAToRemove) {
-        this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove);
+        this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove, &descInfo);
     }
-    this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx);
-    this->setOutputStateInfo(drawState, caps, firstCoverageStageIdx, &separateCoverageFromColor);
+    this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx, &descInfo);
+    this->setOutputStateInfo(drawState, *gpu->caps(), firstCoverageStageIdx, &descInfo,
+                             &separateCoverageFromColor);
 
     // Copy GeometryProcesssor from DS or ODS
     if (drawState.hasGeometryProcessor()) {
@@ -79,10 +85,16 @@
             fNumColorStages = fFragmentStages.count();
         }
     }
+
+    // now create a key
+    gpu->buildProgramDesc(*this, descInfo, drawType, dstCopy, &fDesc);
 };
 
-GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
+GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState,
+                                       GrGpu* gpu,
+                                       const GrDeviceCoordTexture* dstCopy,
                                        GrGpu::DrawType drawType) {
+    const GrDrawTargetCaps& caps = *gpu->caps();
     if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
         GrBlendCoeff srcCoeff;
         GrBlendCoeff dstCoeff;
@@ -100,7 +112,7 @@
         }
 
         drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
-                                                                dstCoeff, caps));
+                                                                dstCoeff, gpu, dstCopy, drawType));
         drawState.fCachedCapsID = caps.getUniqueID();
     } else {
 #ifdef SK_DEBUG
@@ -109,8 +121,8 @@
         BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
                                                                           &srcCoeff,
                                                                           &dstCoeff);
-        SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, caps) ==
-                 *drawState.fCachedOptState);
+        SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, gpu, dstCopy,
+                                drawType) == *drawState.fCachedOptState);
 #endif
     }
     drawState.fCachedOptState->ref();
@@ -120,45 +132,47 @@
 void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
                                         const GrDrawTargetCaps& caps,
                                         int firstCoverageStageIdx,
+                                        GrProgramDesc::DescInfo* descInfo,
                                         bool* separateCoverageFromColor) {
     // Set this default and then possibly change our mind if there is coverage.
-    fPrimaryOutputType = kModulate_PrimaryOutputType;
-    fSecondaryOutputType = kNone_SecondaryOutputType;
+    descInfo->fPrimaryOutputType = GrProgramDesc::kModulate_PrimaryOutputType;
+    descInfo->fSecondaryOutputType = GrProgramDesc::kNone_SecondaryOutputType;
 
     // If we do have coverage determine whether it matters.
     *separateCoverageFromColor = this->hasGeometryProcessor();
     if (!this->isCoverageDrawing() &&
         (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
          ds.hasGeometryProcessor() ||
-         this->hasCoverageVertexAttribute())) {
+         descInfo->hasCoverageVertexAttribute())) {
 
         if (caps.dualSourceBlendingSupport()) {
             if (kZero_GrBlendCoeff == fDstBlend) {
                 // write the coverage value to second color
-                fSecondaryOutputType =  kCoverage_SecondaryOutputType;
+                descInfo->fSecondaryOutputType = GrProgramDesc::kCoverage_SecondaryOutputType;
                 *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;
+                descInfo->fSecondaryOutputType = GrProgramDesc::kCoverageISA_SecondaryOutputType;
                 *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;
+                descInfo->fSecondaryOutputType = GrProgramDesc::kCoverageISC_SecondaryOutputType;
                 *separateCoverageFromColor = true;
                 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
             }
-        } else if (fReadsDst &&
+        } else if (descInfo->fReadsDst &&
                    kOne_GrBlendCoeff == fSrcBlend &&
                    kZero_GrBlendCoeff == fDstBlend) {
-            fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
+            descInfo->fPrimaryOutputType = GrProgramDesc::kCombineWithDst_PrimaryOutputType;
             *separateCoverageFromColor = true;
         }
     }
 }
 
 void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
+                                         GrProgramDesc::DescInfo* descInfo,
                                          int* firstColorStageIdx,
                                          int* firstCoverageStageIdx,
                                          uint8_t* fixedFunctionVAToRemove) {
@@ -171,15 +185,15 @@
             break;
         case kEmitCoverage_BlendOptFlag:
             fColor = 0xffffffff;
-            fInputColorIsUsed = true;
+            descInfo->fInputColorIsUsed = true;
             *firstColorStageIdx = ds.numColorStages();
             *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
             break;
         case kEmitTransBlack_BlendOptFlag:
             fColor = 0;
             fCoverage = 0xff;
-            fInputColorIsUsed = true;
-            fInputCoverageIsUsed = true;
+            descInfo->fInputColorIsUsed = true;
+            descInfo->fInputCoverageIsUsed = true;
             *firstColorStageIdx = ds.numColorStages();
             *firstCoverageStageIdx = ds.numCoverageStages();
             *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
@@ -190,12 +204,13 @@
     }
 }
 
-void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
+void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag,
+                                                      GrProgramDesc::DescInfo* descInfo) {
     int numToRemove = 0;
     uint8_t maskCheck = 0x1;
     // Count the number of vertex attributes that we will actually remove
     for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
-        if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
+        if ((maskCheck & removeVAFlag) && -1 != descInfo->fFixedFunctionVertexAttribIndices[i]) {
             ++numToRemove;
         }
         maskCheck <<= 1;
@@ -211,11 +226,11 @@
         if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
             uint8_t maskCheck = 0x1 << currAttrib.fBinding;
             if (maskCheck & removeVAFlag) {
-                SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
-                fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
+                SkASSERT(-1 != descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
+                descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
                 continue;
             }
-            fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
+            descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
         }
         memcpy(dst, src, sizeof(GrVertexAttrib));
         ++newIdx;
@@ -225,12 +240,14 @@
     fVAPtr = fOptVA.get();
 }
 
-void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds, int* firstColorStageIdx,
+void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds,
+                                                 GrProgramDesc::DescInfo* descInfo,
+                                                 int* firstColorStageIdx,
                                                  uint8_t* fixedFunctionVAToRemove) {
     // Set up color and flags for ConstantColorComponent checks
     GrProcessor::InvariantOutput inout;
     inout.fIsSingleComponent = false;
-    if (!this->hasColorVertexAttribute()) {
+    if (!descInfo->hasColorVertexAttribute()) {
         inout.fColor = ds.getColor();
         inout.fValidFlags = kRGBA_GrColorComponentFlags;
     } else {
@@ -249,12 +266,12 @@
         fp->computeInvariantOutput(&inout);
         if (!inout.fWillUseInputColor) {
             *firstColorStageIdx = i;
-            fInputColorIsUsed = false;
+            descInfo->fInputColorIsUsed = false;
         }
         if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
             *firstColorStageIdx = i + 1;
             fColor = inout.fColor;
-            fInputColorIsUsed = true;
+            descInfo->fInputColorIsUsed = true;
             *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
             // Since we are clearing all previous color stages we are in a state where we have found
             // zero stages that don't multiply the inputColor.
@@ -264,6 +281,7 @@
 }
 
 void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
+                                                    GrProgramDesc::DescInfo* descInfo,
                                                     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
@@ -278,7 +296,7 @@
         fp->computeInvariantOutput(&inout);
         if (!inout.fWillUseInputColor) {
             *firstCoverageStageIdx = i;
-            fInputCoverageIsUsed = false;
+            descInfo->fInputCoverageIsUsed = false;
         }
     }
 #endif
@@ -294,26 +312,26 @@
 }
 
 void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
-                                   int firstCoverageStageIdx) {
+                                   int firstCoverageStageIdx, GrProgramDesc::DescInfo* descInfo) {
     // 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() &&
+    descInfo->fRequiresLocalCoordAttrib = descInfo->hasLocalCoordAttribute() &&
         ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;
 
-    fReadsDst = false;
-    fReadsFragPosition = false;
+    descInfo->fReadsDst = false;
+    descInfo->fReadsFragPosition = false;
 
     for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
         const GrFragmentStage& stage = ds.getColorStage(s);
-        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
+        get_stage_stats(stage, &descInfo->fReadsDst, &descInfo->fReadsFragPosition);
     }
     for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
         const GrFragmentStage& stage = ds.getCoverageStage(s);
-        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
+        get_stage_stats(stage, &descInfo->fReadsDst, &descInfo->fReadsFragPosition);
     }
     if (ds.hasGeometryProcessor()) {
         const GrGeometryProcessor& gp = *ds.getGeometryProcessor();
-        fReadsFragPosition = fReadsFragPosition || gp.willReadFragmentPosition();
+        descInfo->fReadsFragPosition = descInfo->fReadsFragPosition || gp.willReadFragmentPosition();
     }
 }
 
@@ -324,14 +342,15 @@
 }
 
 bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
-    bool usingVertexColors = this->hasColorVertexAttribute();
+    if (this->fDesc != that.fDesc) {
+        return false;
+    }
+    bool usingVertexColors = that.fDesc.header().fColorAttributeIndex != -1;
     if (!usingVertexColors && this->fColor != that.fColor) {
         return false;
     }
 
     if (this->getRenderTarget() != that.getRenderTarget() ||
-        this->fFragmentStages.count() != that.fFragmentStages.count() ||
-        this->fNumColorStages != that.fNumColorStages ||
         !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
         this->fSrcBlend != that.fSrcBlend ||
         this->fDstBlend != that.fDstBlend ||
@@ -341,23 +360,15 @@
         this->fVAStride != that.fVAStride ||
         memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
         this->fStencilSettings != that.fStencilSettings ||
-        this->fDrawFace != that.fDrawFace ||
-        this->fInputColorIsUsed != that.fInputColorIsUsed ||
-        this->fInputCoverageIsUsed != that.fInputCoverageIsUsed ||
-        this->fReadsDst != that.fReadsDst ||
-        this->fReadsFragPosition != that.fReadsFragPosition ||
-        this->fRequiresLocalCoordAttrib != that.fRequiresLocalCoordAttrib ||
-        this->fPrimaryOutputType != that.fPrimaryOutputType ||
-        this->fSecondaryOutputType != that.fSecondaryOutputType) {
+        this->fDrawFace != that.fDrawFace) {
         return false;
     }
 
-    bool usingVertexCoverage = this->hasCoverageVertexAttribute();
+    bool usingVertexCoverage = this->fDesc.header().fCoverageAttributeIndex != -1;
     if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
         return false;
     }
 
-    bool explicitLocalCoords = this->hasLocalCoordAttribute();
     if (this->hasGeometryProcessor()) {
         if (!that.hasGeometryProcessor()) {
             return false;
@@ -368,17 +379,13 @@
         return false;
     }
 
+    bool explicitLocalCoords = this->fDesc.header().fLocalCoordAttributeIndex != -1;
     for (int i = 0; i < this->numFragmentStages(); i++) {
         if (!GrFragmentStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i),
                                             explicitLocalCoords)) {
             return false;
         }
     }
-
-    SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
-                         that.fFixedFunctionVertexAttribIndices,
-                         sizeof(this->fFixedFunctionVertexAttribIndices)));
-
     return true;
 }