This moves us towards variable length effect keys. The overall program key now allows for it. After the header it stores an array of offsets to effect keys. This allows us to grab the effect keys to pass to effects when they generate code. It also ensures that we can't get a collision by sets of keys that are different lengths but are the same when appended  together.

R=robertphillips@google.com, jvanverth@google.com, egdaniel@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/356513003
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index ecd48e0..2c260cd 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -14,29 +14,28 @@
 
 #include "SkChecksum.h"
 
-namespace {
-inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage,
-                                                      const GrGLCaps& caps,
-                                                      bool useExplicitLocalCoords,
-                                                      bool* setTrueIfReadsDst,
-                                                      bool* setTrueIfReadsPos,
-                                                      bool* setTrueIfHasVertexCode) {
-    const GrEffect* effect = stage.getEffect();
-    const GrBackendEffectFactory& factory = effect->getFactory();
+static inline bool get_key_and_update_stats(const GrEffectStage& stage,
+                                            const GrGLCaps& caps,
+                                            bool useExplicitLocalCoords,
+                                            GrEffectKeyBuilder* b, 
+                                            bool* setTrueIfReadsDst,
+                                            bool* setTrueIfReadsPos,
+                                            bool* setTrueIfHasVertexCode) {
+    const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
     GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
-    if (effect->willReadDstColor()) {
+    if (stage.getEffect()->willReadDstColor()) {
         *setTrueIfReadsDst = true;
     }
-    if (effect->willReadFragmentPosition()) {
+    if (stage.getEffect()->willReadFragmentPosition()) {
         *setTrueIfReadsPos = true;
     }
-    if (effect->hasVertexCode()) {
+    if (stage.getEffect()->hasVertexCode()) {
         *setTrueIfHasVertexCode = true;
     }
-    return factory.glEffectKey(drawEffect, caps);
+    return factory.getGLEffectKey(drawEffect, caps, b);
 }
-}
-void GrGLProgramDesc::Build(const GrDrawState& drawState,
+
+bool GrGLProgramDesc::Build(const GrDrawState& drawState,
                             GrGpu::DrawType drawType,
                             GrDrawState::BlendOptFlags blendOpts,
                             GrBlendCoeff srcCoeff,
@@ -94,45 +93,68 @@
                              (!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
                              (!inputColorIsUsed);
 
-    int numEffects = (skipColor ? 0 : (drawState.numColorStages() - firstEffectiveColorStage)) +
-                     (skipCoverage ? 0 : (drawState.numCoverageStages() - firstEffectiveCoverageStage));
-
-    size_t newKeyLength = KeyLength(numEffects);
-    bool allocChanged;
-    desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
-    if (allocChanged || !desc->fInitialized) {
-        // make sure any padding in the header is zero if we we haven't used this allocation before.
-        memset(desc->header(), 0, kHeaderSize);
-    }
-    // write the key length
-    *desc->atOffset<uint32_t, kLengthOffset>() = SkToU32(newKeyLength);
-
-    KeyHeader* header = desc->header();
-    EffectKey* effectKeys = desc->effectKeys();
-
-    int currEffectKey = 0;
     bool readsDst = false;
     bool readFragPosition = false;
     // We use vertexshader-less shader programs only when drawing paths.
     bool hasVertexCode = !(GrGpu::kDrawPath_DrawType == drawType ||
                            GrGpu::kDrawPaths_DrawType == drawType);
+    int numStages = 0;
+    if (!skipColor) {
+        numStages += drawState.numColorStages() - firstEffectiveColorStage;
+    }
+    if (!skipCoverage) {
+        numStages += drawState.numCoverageStages() - firstEffectiveCoverageStage;
+    }
+    GR_STATIC_ASSERT(0 == kEffectKeyLengthsOffset % sizeof(uint32_t));
+    // Make room for everything up to and including the array of offsets to effect keys.
+    desc->fKey.reset();
+    desc->fKey.push_back_n(kEffectKeyLengthsOffset + sizeof(uint32_t) * numStages);
 
+    size_t offset = desc->fKey.count();
+    int offsetIndex = 0;
+
+    bool effectKeySuccess = true;
     if (!skipColor) {
         for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
-            effectKeys[currEffectKey++] =
-                get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
-                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition,
-                                         &hasVertexCode);
+            uint32_t* offsetLocation = reinterpret_cast<uint32_t*>(desc->fKey.begin() +
+                                                                   kEffectKeyLengthsOffset +
+                                                                   offsetIndex * sizeof(uint32_t));
+            *offsetLocation = offset;
+            ++offsetIndex;
+
+            GrEffectKeyBuilder b(&desc->fKey);
+            effectKeySuccess |= get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
+                                                         requiresLocalCoordAttrib, &b, &readsDst,
+                                                         &readFragPosition, &hasVertexCode);
+            offset += b.size();
         }
     }
     if (!skipCoverage) {
         for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
-            effectKeys[currEffectKey++] =
-                get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
-                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition,
-                                         &hasVertexCode);
+            uint32_t* offsetLocation = reinterpret_cast<uint32_t*>(desc->fKey.begin() +
+                                                                   kEffectKeyLengthsOffset +
+                                                                   offsetIndex * sizeof(uint32_t));
+            *offsetLocation = offset;
+            ++offsetIndex;
+            GrEffectKeyBuilder b(&desc->fKey);
+            effectKeySuccess |= get_key_and_update_stats(drawState.getCoverageStage(s),
+                                                         gpu->glCaps(), requiresLocalCoordAttrib,
+                                                         &b, &readsDst, &readFragPosition,
+                                                         &hasVertexCode);
+            offset += b.size();
         }
     }
+    if (!effectKeySuccess) {
+        desc->fKey.reset();
+        return false;
+    }
+
+    KeyHeader* header = desc->header();
+    // make sure any padding in the header is zeroed.
+    memset(desc->header(), 0, kHeaderSize);
+
+    // Because header is a pointer into the dynamic array, we can't push any new data into the key
+    // below here.
 
     header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
     header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
@@ -268,18 +290,23 @@
     header->fColorEffectCnt = colorStages->count();
     header->fCoverageEffectCnt = coverageStages->count();
 
-    *desc->checksum() = 0;
-    *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
-                                            newKeyLength);
-    desc->fInitialized = true;
+    desc->finalize();
+    return true;
+}
+
+void GrGLProgramDesc::finalize() {
+    int keyLength = fKey.count();
+    SkASSERT(0 == (keyLength % 4));
+    *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);
+
+    uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
+    *checksum = 0;
+    *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
 }
 
 GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
-    fInitialized = other.fInitialized;
-    if (fInitialized) {
-        size_t keyLength = other.keyLength();
-        fKey.reset(keyLength);
-        memcpy(fKey.get(), other.fKey.get(), keyLength);
-    }
+    size_t keyLength = other.keyLength();
+    fKey.reset(keyLength);
+    memcpy(fKey.begin(), other.fKey.begin(), keyLength);
     return *this;
 }