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/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 4b15af0..d020857 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -783,6 +783,7 @@
 #include "GrEffectUnitTest.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 
 /**
  * GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 23937cc..f8b8497 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -48,6 +48,7 @@
 #include "GrCoordTransform.h"
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #include "GrTextureAccess.h"
 
diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp
index 0424a6e..6e01504 100644
--- a/src/effects/SkArithmeticMode.cpp
+++ b/src/effects/SkArithmeticMode.cpp
@@ -15,6 +15,7 @@
 #include "GrContext.h"
 #include "GrCoordTransform.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #endif
 
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index e400663..4ab9944 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -22,6 +22,7 @@
 #include "GrTexture.h"
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "effects/GrSimpleTextureEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkGrPixelRef.h"
diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp
index 35b7825..0e2fd6c 100644
--- a/src/effects/SkColorFilters.cpp
+++ b/src/effects/SkColorFilters.cpp
@@ -131,6 +131,7 @@
 #include "GrEffectUnitTest.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkGr.h"
 
 namespace {
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index cf2e3b7..c24a2b7 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -327,6 +327,7 @@
 #include "GrEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 
 class ColorMatrixEffect : public GrEffect {
 public:
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index b270640..a6897ea 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -14,6 +14,7 @@
 #include "GrContext.h"
 #include "GrCoordTransform.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #endif
 
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index c5b8fc6..682f2ba 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -17,6 +17,7 @@
 #if SK_SUPPORT_GPU
 #include "effects/GrSingleTextureEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "GrEffect.h"
 #include "GrTBackendEffectFactory.h"
 
diff --git a/src/effects/SkLumaColorFilter.cpp b/src/effects/SkLumaColorFilter.cpp
index 4c5e98a..7564307 100644
--- a/src/effects/SkLumaColorFilter.cpp
+++ b/src/effects/SkLumaColorFilter.cpp
@@ -12,6 +12,7 @@
 
 #if SK_SUPPORT_GPU
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "GrContext.h"
 #include "GrTBackendEffectFactory.h"
 #endif
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index 7601603..4a730c2 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -16,6 +16,7 @@
 #if SK_SUPPORT_GPU
 #include "effects/GrSingleTextureEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrTBackendEffectFactory.h"
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index 5baf36b..fa7d205 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -15,6 +15,7 @@
 
 #if SK_SUPPORT_GPU
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "effects/GrSingleTextureEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "GrTexture.h"
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 53180fa..10c6fe5 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -17,6 +17,7 @@
 #include "GrTexture.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "effects/Gr1DKernelEffect.h"
 #endif
 
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp
index f57fcf3..e481162 100644
--- a/src/effects/SkPerlinNoiseShader.cpp
+++ b/src/effects/SkPerlinNoiseShader.cpp
@@ -18,6 +18,7 @@
 #include "GrContext.h"
 #include "GrCoordTransform.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkGr.h"
 #endif
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 09024d3..4cf0987 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -230,6 +230,7 @@
 #include "GrEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkGr.h"
 
 class GLColorTableEffect;
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index fe720b8..fb8a7e5 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -852,6 +852,7 @@
 
 #include "effects/GrTextureStripAtlas.h"
 #include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkGr.h"
 
 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 113877c..332c9b4 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -446,6 +446,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkGr.h"
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 2267d8d..e3aaea3 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -458,6 +458,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkGr.h"
 
 class GrGLRadialGradient : public GrGLGradientEffect {
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 1ba0443..bb9d628 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -174,6 +174,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkGr.h"
 
 class GrGLSweepGradient : public GrGLGradientEffect {
diff --git a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
index 4d0aa0f..8beb6fb 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
@@ -12,6 +12,7 @@
 
 #if SK_SUPPORT_GPU
 #include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
 // For brevity
 typedef GrGLUniformManager::UniformHandle UniformHandle;
 
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 79c231d..a97cc0c 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -383,6 +383,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkGr.h"
 
 // For brevity
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 7765eb1..3116712 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -19,6 +19,7 @@
 #include "SkTraceEvent.h"
 
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLVertexEffect.h"
 
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 48024a6..761c63f 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -8,6 +8,7 @@
 #include "GrAARectRenderer.h"
 #include "GrGpu.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkColorPriv.h"
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index fe4c03e..648bc14 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -10,6 +10,7 @@
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 0736b5a..d710c64 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -8,6 +8,7 @@
 #include "GrBezierEffect.h"
 
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 132d2f4..118efaf 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -1,5 +1,14 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
 #include "GrBicubicEffect.h"
 
+#include "gl/GrGLShaderBuilder.h"
+
 #define DS(x) SkDoubleToScalar(x)
 
 const SkScalar GrBicubicEffect::gMitchellCoefficients[16] = {
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index ff18ef2..c421867 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -10,6 +10,7 @@
 #include "GrTBackendEffectFactory.h"
 #include "GrSimpleTextureEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkMatrix.h"
 
 class GrGLConfigConversionEffect : public GrGLEffect {
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index 49521ca..dd104bd 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -8,6 +8,7 @@
 #include "GrConvexPolyEffect.h"
 
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrTBackendEffectFactory.h"
 
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 14ba4d7..43ef7e76 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -7,6 +7,7 @@
 
 #include "GrConvolutionEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrTBackendEffectFactory.h"
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
index 62326b9..feb9d62 100644
--- a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
@@ -7,6 +7,7 @@
 
 #include "GrCustomCoordsTextureEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "gl/GrGLVertexEffect.h"
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 723f59d..488d1ba 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -12,6 +12,7 @@
 #include "effects/GrVertexEffect.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrContext.h"
 #include "GrCoordTransform.h"
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index 5ae0129..f69980d 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -7,6 +7,7 @@
 
 #include "GrDistanceFieldTextureEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "gl/GrGLVertexEffect.h"
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
index fc37d1a..37354c6 100644
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ b/src/gpu/effects/GrDitherEffect.cpp
@@ -8,6 +8,7 @@
 #include "GrDitherEffect.h"
 
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrTBackendEffectFactory.h"
 
diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp
index ddda4b9..a80b08d 100644
--- a/src/gpu/effects/GrOvalEffect.cpp
+++ b/src/gpu/effects/GrOvalEffect.cpp
@@ -8,6 +8,7 @@
 #include "GrOvalEffect.h"
 
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrTBackendEffectFactory.h"
 
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index d39ab0d..efad436 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -8,6 +8,7 @@
 #include "GrRRectEffect.h"
 
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrConvexPolyEffect.h"
 #include "GrOvalEffect.h"
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index b5ad386..c93abf9 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -7,6 +7,7 @@
 
 #include "GrSimpleTextureEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrTBackendEffectFactory.h"
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index f12fec5..108ec78 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -9,6 +9,7 @@
 #include "GrSimpleTextureEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "SkFloatingPoint.h"
 
 
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index 01ff6d6..76b8581 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -10,6 +10,7 @@
 #include "GrCoordTransform.h"
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 #include "GrTBackendEffectFactory.h"
 
 namespace {
diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h
index 1cc3df2..0727372 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -10,10 +10,11 @@
 
 #include "GrBackendEffectFactory.h"
 #include "GrGLProgramEffects.h"
-#include "GrGLShaderBuilder.h"
 #include "GrGLShaderVar.h"
 #include "GrGLSL.h"
 
+class GrGLShaderBuilder;
+
 /** @file
     This file contains specializations for OpenGL of the shader stages declared in
     include/gpu/GrEffect.h. Objects of type GrGLEffect are responsible for emitting the
@@ -43,12 +44,6 @@
     typedef GrGLProgramEffects::TextureSampler TextureSampler;
     typedef GrGLProgramEffects::TextureSamplerArray TextureSamplerArray;
 
-    enum {
-        kNoEffectKey = GrBackendEffectFactory::kNoEffectKey,
-        // the number of bits in EffectKey available to GenKey
-        kEffectKeyBits = GrBackendEffectFactory::kEffectKeyBits,
-    };
-
     GrGLEffect(const GrBackendEffectFactory& factory)
         : fFactory(factory)
         , fIsVertexEffect(false) {
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;
 }
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index 9165f4e..d7652f4 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -10,7 +10,6 @@
 
 #include "GrGLEffect.h"
 #include "GrDrawState.h"
-#include "GrGLShaderBuilder.h"
 #include "GrGpu.h"
 
 class GrGpuGL;
@@ -30,13 +29,12 @@
     to be API-neutral then so could this class. */
 class GrGLProgramDesc {
 public:
-    GrGLProgramDesc() : fInitialized(false) {}
+    GrGLProgramDesc() {}
     GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; }
 
     // Returns this as a uint32_t array to be used as a key in the program cache.
     const uint32_t* asKey() const {
-        SkASSERT(fInitialized);
-        return reinterpret_cast<const uint32_t*>(fKey.get());
+        return reinterpret_cast<const uint32_t*>(fKey.begin());
     }
 
     // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. When comparing two
@@ -48,7 +46,7 @@
     uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); }
 
     // For unit testing.
-    void setRandom(SkRandom*,
+    bool setRandom(SkRandom*,
                    const GrGpuGL* gpu,
                    const GrRenderTarget* dummyDstRenderTarget,
                    const GrTexture* dummyDstCopyTexture,
@@ -64,7 +62,7 @@
      * not contain all stages from the draw state and coverage stages from the drawState may
      * be treated as color stages in the output.
      */
-    static void Build(const GrDrawState&,
+    static bool Build(const GrDrawState&,
                       GrGpu::DrawType drawType,
                       GrDrawState::BlendOptFlags,
                       GrBlendCoeff srcCoeff,
@@ -76,12 +74,10 @@
                       GrGLProgramDesc* outDesc);
 
     int numColorEffects() const {
-        SkASSERT(fInitialized);
         return this->getHeader().fColorEffectCnt;
     }
 
     int numCoverageEffects() const {
-        SkASSERT(fInitialized);
         return this->getHeader().fCoverageEffectCnt;
     }
 
@@ -90,7 +86,6 @@
     GrGLProgramDesc& operator= (const GrGLProgramDesc& other);
 
     bool operator== (const GrGLProgramDesc& other) const {
-        SkASSERT(fInitialized && other.fInitialized);
         // The length is masked as a hint to the compiler that the address will be 4 byte aligned.
         return 0 == memcmp(this->asKey(), other.asKey(), this->keyLength() & ~0x3);
     }
@@ -145,13 +140,12 @@
     }
 
     struct KeyHeader {
-        GrGLShaderBuilder::DstReadKey fDstReadKey;      // set by GrGLShaderBuilder if there
+        uint8_t                     fDstReadKey;        // set by GrGLShaderBuilder if there
                                                         // are effects that must read the dst.
                                                         // Otherwise, 0.
-        GrGLShaderBuilder::FragPosKey fFragPosKey;      // set by GrGLShaderBuilder if there are
+        uint8_t                     fFragPosKey;        // set by GrGLShaderBuilder if there are
                                                         // effects that read the fragment position.
                                                         // Otherwise, 0.
-
         ColorInput                  fColorInput : 8;
         ColorInput                  fCoverageInput : 8;
         CoverageOutput              fCoverageOutput : 8;
@@ -174,48 +168,72 @@
         int8_t                      fCoverageEffectCnt;
     };
 
-    // The key is 1 uint32_t for the length, followed another for the checksum, the header, and then
-    // the effect keys. Everything is fixed length except the effect key array.
+    // The key, stored in fKey, is composed of five parts:
+    // 1. uint32_t for total key length.
+    // 2. uint32_t for a checksum.
+    // 3. Header struct defined above.
+    // 4. uint32_t offsets to beginning of every effects' key (see 5).
+    // 5. per-effect keys. Each effect's key is a variable length array of uint32_t.
     enum {
         kLengthOffset = 0,
         kChecksumOffset = kLengthOffset + sizeof(uint32_t),
         kHeaderOffset = kChecksumOffset + sizeof(uint32_t),
         kHeaderSize = SkAlign4(sizeof(KeyHeader)),
-        kEffectKeyOffset = kHeaderOffset + kHeaderSize,
+        kEffectKeyLengthsOffset = kHeaderOffset + kHeaderSize,
     };
 
     template<typename T, size_t OFFSET> T* atOffset() {
-        return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET);
+        return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
     }
 
     template<typename T, size_t OFFSET> const T* atOffset() const {
-        return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET);
+        return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
     }
 
-    typedef GrGLEffect::EffectKey EffectKey;
+    typedef GrBackendEffectFactory::EffectKey EffectKey;
 
-    uint32_t* checksum() { return this->atOffset<uint32_t, kChecksumOffset>(); }
     KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); }
-    EffectKey* effectKeys() { return this->atOffset<EffectKey, kEffectKeyOffset>(); }
+
+    void finalize();
 
     const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); }
-    const EffectKey* getEffectKeys() const { return this->atOffset<EffectKey, kEffectKeyOffset>(); }
 
-    static size_t KeyLength(int effectCnt) {
-        GR_STATIC_ASSERT(!(sizeof(EffectKey) & 0x3));
-        return kEffectKeyOffset + effectCnt * sizeof(EffectKey);
-    }
+    /** Used to provide effects' keys to their emitCode() function. */
+    class EffectKeyProvider {
+    public:
+        enum EffectType {
+            kColor_EffectType,
+            kCoverage_EffectType,
+        };
 
-    enum {
-        kMaxPreallocEffects = 16,
-        kPreAllocSize = kEffectKeyOffset +  kMaxPreallocEffects * sizeof(EffectKey),
+        EffectKeyProvider(const GrGLProgramDesc* desc, EffectType type) : fDesc(desc) {
+            // Coverage effect key offsets begin immediately after those of the color effects.
+            fBaseIndex = kColor_EffectType == type ? 0 : desc->numColorEffects();
+        }
+
+        EffectKey get(int index) const {
+            const uint32_t* offsets = reinterpret_cast<const uint32_t*>(fDesc->fKey.begin() +
+                                                                        kEffectKeyLengthsOffset);
+            uint32_t offset = offsets[fBaseIndex + index];
+            return *reinterpret_cast<const EffectKey*>(fDesc->fKey.begin() + offset);
+        }
+    private:
+        const GrGLProgramDesc*  fDesc;
+        int                     fBaseIndex;
     };
 
-    SkAutoSMalloc<kPreAllocSize> fKey;
-    bool fInitialized;
+    enum {
+        kMaxPreallocEffects = 8,
+        kIntsPerEffect      = 4,    // This is an overestimate of the average effect key size.
+        kPreAllocSize = kEffectKeyLengthsOffset +
+                        kMaxPreallocEffects * sizeof(uint32_t) * kIntsPerEffect,
+    };
 
-    // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Move all
-    // code generation to GrGLShaderBuilder (and maybe add getters rather than friending).
+    SkSTArray<kPreAllocSize, uint8_t, true> fKey;
+
+    // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Split out
+    // part of GrGLShaderBuilder that is used by effects so that this header doesn't need to be
+    // visible to GrGLEffects. Then make public accessors as necessary and remove friends.
     friend class GrGLProgram;
     friend class GrGLShaderBuilder;
     friend class GrGLFullShaderBuilder;
diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp
index fd91f58..65d14fd 100644
--- a/src/gpu/gl/GrGLProgramEffects.cpp
+++ b/src/gpu/gl/GrGLProgramEffects.cpp
@@ -239,7 +239,7 @@
     SkSTArray<4, TextureSampler> samplers(effect->numTextures());
 
     this->emitAttributes(builder, stage);
-    this->emitTransforms(builder, effect, key, &coords);
+    this->emitTransforms(builder, drawEffect, &coords);
     this->emitSamplers(builder, effect, &samplers);
 
     GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
@@ -277,12 +277,11 @@
 }
 
 void GrGLVertexProgramEffects::emitTransforms(GrGLFullShaderBuilder* builder,
-                                              const GrEffect* effect,
-                                              EffectKey effectKey,
+                                              const GrDrawEffect& drawEffect,
                                               TransformedCoordsArray* outCoords) {
     SkTArray<Transform, true>& transforms = fTransforms.push_back();
-    EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey);
-    int numTransforms = effect->numTransforms();
+    EffectKey totalKey = GenTransformKey(drawEffect);
+    int numTransforms = drawEffect.effect()->numTransforms();
     transforms.push_back_n(numTransforms);
     for (int t = 0; t < numTransforms; t++) {
         GrSLType varyingType = kVoid_GrSLType;
@@ -398,7 +397,7 @@
     SkSTArray<4, TextureSampler> samplers(effect->numTextures());
 
     SkASSERT(0 == stage.getVertexAttribIndexCount());
-    this->setupPathTexGen(builder, effect, key, &coords);
+    this->setupPathTexGen(builder, drawEffect, &coords);
     this->emitSamplers(builder, effect, &samplers);
 
     GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
@@ -416,11 +415,10 @@
 }
 
 void GrGLPathTexGenProgramEffects::setupPathTexGen(GrGLFragmentOnlyShaderBuilder* builder,
-                                           const GrEffect* effect,
-                                           EffectKey effectKey,
+                                           const GrDrawEffect& drawEffect,
                                            TransformedCoordsArray* outCoords) {
-    int numTransforms = effect->numTransforms();
-    EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey);
+    int numTransforms = drawEffect.effect()->numTransforms();
+    EffectKey totalKey = GenTransformKey(drawEffect);
     int texCoordIndex = builder->addTexCoordSets(numTransforms);
     SkNEW_APPEND_TO_TARRAY(&fTransforms, Transforms, (totalKey, texCoordIndex));
     SkString name;
diff --git a/src/gpu/gl/GrGLProgramEffects.h b/src/gpu/gl/GrGLProgramEffects.h
index 137befd..5a2fefd 100644
--- a/src/gpu/gl/GrGLProgramEffects.h
+++ b/src/gpu/gl/GrGLProgramEffects.h
@@ -189,8 +189,7 @@
      * TransformedCoordsArray* object, which is in turn passed to the effect's emitCode() function.
      */
     void emitTransforms(GrGLFullShaderBuilder*,
-                        const GrEffect*,
-                        EffectKey,
+                        const GrDrawEffect&,
                         TransformedCoordsArray*);
 
     /**
@@ -277,8 +276,7 @@
      * effect's emitCode() function.
      */
     void setupPathTexGen(GrGLFragmentOnlyShaderBuilder*,
-                         const GrEffect*,
-                         EffectKey,
+                         const GrDrawEffect&,
                          TransformedCoordsArray*);
 
     /**
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 4b7de02..7a57d8e 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -194,15 +194,19 @@
     ///////////////////////////////////////////////////////////////////////////
     // emit the per-effect code for both color and coverage effects
 
+    GrGLProgramDesc::EffectKeyProvider colorKeyProvider(
+        &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType);
     fOutput.fColorEffects.reset(this->createAndEmitEffects(colorStages,
-                                                           this->desc().getEffectKeys(),
                                                            this->desc().numColorEffects(),
+                                                           colorKeyProvider,
                                                            &inputColor));
 
+    GrGLProgramDesc::EffectKeyProvider coverageKeyProvider(
+        &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType);
     fOutput.fCoverageEffects.reset(this->createAndEmitEffects(coverageStages,
-                                    this->desc().getEffectKeys() + this->desc().numColorEffects(),
-                                    this->desc().numCoverageEffects(),
-                                    &inputCoverage));
+                                   this->desc().numCoverageEffects(),
+                                   coverageKeyProvider,
+                                   &inputCoverage));
 
     this->emitCodeAfterEffects();
 
@@ -601,8 +605,8 @@
 
 void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder,
                                              const GrEffectStage* effectStages[],
-                                             const EffectKey effectKeys[],
                                              int effectCnt,
+                                             const GrGLProgramDesc::EffectKeyProvider& keyProvider,
                                              GrGLSLExpr4* fsInOutColor) {
     bool effectEmitted = false;
 
@@ -632,7 +636,7 @@
 
 
         programEffectsBuilder->emitEffect(stage,
-                                          effectKeys[e],
+                                          keyProvider.get(e),
                                           outColor.c_str(),
                                           inColor.isOnes() ? NULL : inColor.c_str(),
                                           fCodeStage.stageIndex());
@@ -976,15 +980,15 @@
 
 GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects(
         const GrEffectStage* effectStages[],
-        const EffectKey effectKeys[],
         int effectCnt,
+        const GrGLProgramDesc::EffectKeyProvider& keyProvider,
         GrGLSLExpr4* inOutFSColor) {
 
     GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
     this->INHERITED::createAndEmitEffects(&programEffectsBuilder,
                                           effectStages,
-                                          effectKeys,
                                           effectCnt,
+                                          keyProvider,
                                           inOutFSColor);
     return programEffectsBuilder.finish();
 }
@@ -1093,16 +1097,16 @@
 
 GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects(
         const GrEffectStage* effectStages[],
-        const EffectKey effectKeys[],
         int effectCnt,
+        const GrGLProgramDesc::EffectKeyProvider& keyProvider,
         GrGLSLExpr4* inOutFSColor) {
 
     GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this,
                                                                  effectCnt);
     this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder,
                                           effectStages,
-                                          effectKeys,
                                           effectCnt,
+                                          keyProvider,
                                           inOutFSColor);
     return pathTexGenEffectsBuilder.finish();
 }
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 7e71acf..c28cd09 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -13,6 +13,7 @@
 #include "GrColor.h"
 #include "GrEffect.h"
 #include "SkTypes.h"
+#include "gl/GrGLProgramDesc.h"
 #include "gl/GrGLProgramEffects.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLUniformManager.h"
@@ -253,8 +254,8 @@
     // Helper for emitEffects().
     void createAndEmitEffects(GrGLProgramEffectsBuilder*,
                               const GrEffectStage* effectStages[],
-                              const EffectKey effectKeys[],
                               int effectCnt,
+                              const GrGLProgramDesc::EffectKeyProvider&,
                               GrGLSLExpr4* inOutFSColor);
 
     // Generates a name for a variable. The generated string will be name prefixed by the prefix
@@ -338,15 +339,15 @@
 
     /**
     * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
-    * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key
-    * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and
-    * is updated to be the output color of the last stage.
-    * The handles to texture samplers for effectStage[i] are added to
+    * deleting it when finished. effectStages contains the effects to add. The effect key provider 
+    * is used to communicate the key each effect created in its GenKey function. inOutFSColor
+    * specifies the input color to the first stage and is updated to be the output color of the
+    * last stage. The handles to texture samplers for effectStage[i] are added to
     * effectSamplerHandles[i].
     */
     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
-                                                     const EffectKey effectKeys[],
                                                      int effectCnt,
+                                                     const GrGLProgramDesc::EffectKeyProvider&,
                                                      GrGLSLExpr4* inOutFSColor) = 0;
 
     /**
@@ -465,8 +466,8 @@
     virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE;
 
     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
-                                                     const EffectKey effectKeys[],
                                                      int effectCnt,
+                                                     const GrGLProgramDesc::EffectKeyProvider&,
                                                      GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
 
     virtual void emitCodeAfterEffects() SK_OVERRIDE;
@@ -510,8 +511,8 @@
     virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {}
 
     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
-                                                     const EffectKey effectKeys[],
                                                      int effectCnt,
+                                                     const GrGLProgramDesc::EffectKeyProvider&,
                                                      GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
 
     virtual void emitCodeAfterEffects() SK_OVERRIDE {}
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index bd4758c..9e1b6f5 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -234,7 +234,7 @@
         SkSTArray<8, const GrEffectStage*, true> colorStages;
         SkSTArray<8, const GrEffectStage*, true> coverageStages;
         GrGLProgramDesc desc;
-        GrGLProgramDesc::Build(this->getDrawState(),
+        if (!GrGLProgramDesc::Build(this->getDrawState(),
                                type,
                                blendOpts,
                                srcCoeff,
@@ -243,7 +243,10 @@
                                dstCopy,
                                &colorStages,
                                &coverageStages,
-                               &desc);
+                               &desc)) {
+            SkDEBUGFAIL("Failed to generate GL program descriptor");
+            return false;
+        }
 
         fCurrentProgram.reset(fProgramCache->getProgram(desc,
                                                         colorStages.begin(),