Move code that builds GrGLProgram::Desc to GrGLProgram. Move color and coverage flush to GrGLProgram.
Review URL: https://codereview.appspot.com/7322058

git-svn-id: http://skia.googlecode.com/svn/trunk@7708 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index a4f0df2..75f9ea6 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -40,6 +40,155 @@
 
 }
 
+void GrGLProgram::BuildDesc(const GrDrawState& drawState,
+                            bool isPoints,
+                            GrDrawState::BlendOptFlags blendOpts,
+                            GrBlendCoeff srcCoeff,
+                            GrBlendCoeff dstCoeff,
+                            const GrGpuGL* gpu,
+                            Desc* desc) {
+
+    // This should already have been caught
+    GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
+
+    bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
+
+    bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
+                                           GrDrawState::kEmitCoverage_BlendOptFlag));
+
+    // The descriptor is used as a cache key. Thus when a field of the
+    // descriptor will not affect program generation (because of the vertex
+    // layout in use or other descriptor field settings) it should be set
+    // to a canonical value to avoid duplicate programs with different keys.
+
+    // Must initialize all fields or cache will have false negatives!
+    desc->fVertexLayout = drawState.getVertexLayout();
+
+    desc->fEmitsPointSize = isPoints;
+
+    bool requiresAttributeColors = !skipColor &&
+                                   SkToBool(desc->fVertexLayout & GrDrawState::kColor_VertexLayoutBit);
+    bool requiresAttributeCoverage = !skipCoverage &&
+                                     SkToBool(desc->fVertexLayout & GrDrawState::kCoverage_VertexLayoutBit);
+
+    // fColorInput/fCoverageInput records how colors are specified for the program So we strip the
+    // bits from the layout to avoid false negatives when searching for an existing program in the
+    // cache.
+    desc->fVertexLayout &= ~(GrDrawState::kColor_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit);
+
+    desc->fColorFilterXfermode = skipColor ?
+                                SkXfermode::kDst_Mode :
+                                drawState.getColorFilterMode();
+
+    // no reason to do edge aa or look at per-vertex coverage if coverage is ignored
+    if (skipCoverage) {
+        desc->fVertexLayout &= ~(GrDrawState::kEdge_VertexLayoutBit |
+                                 GrDrawState::kCoverage_VertexLayoutBit);
+    }
+
+    bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
+    bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
+                             (!requiresAttributeColors && 0xffffffff == drawState.getColor());
+    if (colorIsTransBlack) {
+        desc->fColorInput = Desc::kTransBlack_ColorInput;
+    } else if (colorIsSolidWhite) {
+        desc->fColorInput = Desc::kSolidWhite_ColorInput;
+    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
+        desc->fColorInput = Desc::kUniform_ColorInput;
+    } else {
+        desc->fColorInput = Desc::kAttribute_ColorInput;
+    }
+
+    bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage();
+
+    if (skipCoverage) {
+        desc->fCoverageInput = Desc::kTransBlack_ColorInput;
+    } else if (covIsSolidWhite) {
+        desc->fCoverageInput = Desc::kSolidWhite_ColorInput;
+    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
+        desc->fCoverageInput = Desc::kUniform_ColorInput;
+    } else {
+        desc->fCoverageInput = Desc::kAttribute_ColorInput;
+    }
+
+    int lastEnabledStage = -1;
+
+    if (!skipCoverage && (desc->fVertexLayout & GrDrawState::kEdge_VertexLayoutBit)) {
+        desc->fVertexEdgeType = drawState.getVertexEdgeType();
+        desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
+    } else {
+        // Use canonical values when edge-aa is not enabled to avoid program cache misses.
+        desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
+        desc->fDiscardIfOutsideEdge = false;
+    }
+
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+
+        bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage;
+        if (!skip && drawState.isStageEnabled(s)) {
+            lastEnabledStage = s;
+            const GrEffectRef& effect = *drawState.getStage(s).getEffect();
+            const GrBackendEffectFactory& factory = effect->getFactory();
+            desc->fEffectKeys[s] = factory.glEffectKey(drawState.getStage(s), gpu->glCaps());
+        } else {
+            desc->fEffectKeys[s] = 0;
+        }
+    }
+
+    desc->fDualSrcOutput = Desc::kNone_DualSrcOutput;
+
+    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
+    // other than pass through values from the VS to the FS anyway).
+#if GR_GL_EXPERIMENTAL_GS
+#if 0
+    desc->fExperimentalGS = gpu->getCaps().geometryShaderSupport();
+#else
+    desc->fExperimentalGS = false;
+#endif
+#endif
+
+    // We want to avoid generating programs with different "first cov stage" values when they would
+    // compute the same result. We set field in the desc to kNumStages when either there are no
+    // coverage stages or the distinction between coverage and color is immaterial.
+    int firstCoverageStage = GrDrawState::kNumStages;
+    desc->fFirstCoverageStage = GrDrawState::kNumStages;
+    bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage;
+    if (hasCoverage) {
+        firstCoverageStage = drawState.getFirstCoverageStage();
+    }
+
+    // other coverage inputs
+    if (!hasCoverage) {
+        hasCoverage = requiresAttributeCoverage ||
+                      (desc->fVertexLayout & GrDrawState::kEdge_VertexLayoutBit);
+    }
+
+    if (hasCoverage) {
+        // color filter is applied between color/coverage computation
+        if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
+            desc->fFirstCoverageStage = firstCoverageStage;
+        }
+
+        if (gpu->getCaps().dualSourceBlendingSupport() &&
+            !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
+                           GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
+            if (kZero_GrBlendCoeff == dstCoeff) {
+                // write the coverage value to second color
+                desc->fDualSrcOutput =  Desc::kCoverage_DualSrcOutput;
+                desc->fFirstCoverageStage = firstCoverageStage;
+            } else if (kSA_GrBlendCoeff == dstCoeff) {
+                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
+                desc->fDualSrcOutput = Desc::kCoverageISA_DualSrcOutput;
+                desc->fFirstCoverageStage = firstCoverageStage;
+            } else if (kSC_GrBlendCoeff == dstCoeff) {
+                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
+                desc->fDualSrcOutput = Desc::kCoverageISC_DualSrcOutput;
+                desc->fFirstCoverageStage = firstCoverageStage;
+            }
+        }
+    }
+}
+
 GrGLProgram* GrGLProgram::Create(const GrGLContextInfo& gl,
                                  const Desc& desc,
                                  const GrEffectStage* stages[]) {
@@ -896,7 +1045,10 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGLProgram::setData(GrGpuGL* gpu) {
+void GrGLProgram::setData(GrGpuGL* gpu,
+                          GrColor color,
+                          GrColor coverage,
+                          SharedGLState* sharedState) {
     const GrDrawState& drawState = gpu->getDrawState();
 
     int rtHeight = drawState.getRenderTarget()->height();
@@ -905,6 +1057,19 @@
         fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(rtHeight));
         fRTHeight = rtHeight;
     }
+
+    this->setColor(drawState, color, sharedState);
+    this->setCoverage(drawState, coverage, sharedState);
+
+    // Setup the SkXfermode::Mode-based colorfilter uniform if necessary
+    if (GrGLUniformManager::kInvalidUniformHandle != fUniformHandles.fColorFilterUni &&
+        fColorFilterColor != drawState.getColorFilterColor()) {
+        GrGLfloat c[4];
+        GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
+        fUniformManager.set4fv(fUniformHandles.fColorFilterUni, 0, 1, c);
+        fColorFilterColor = drawState.getColorFilterColor();
+    }
+
     GrGLint texUnitIdx = 0;
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         if (NULL != fEffects[s]) {
@@ -924,3 +1089,71 @@
         }
     }
 }
+
+void GrGLProgram::setColor(const GrDrawState& drawState,
+                           GrColor color,
+                           SharedGLState* sharedState) {
+    if (!(drawState.getVertexLayout() & GrDrawState::kColor_VertexLayoutBit)) {
+        switch (fDesc.fColorInput) {
+            case GrGLProgram::Desc::kAttribute_ColorInput:
+                if (sharedState->fConstAttribColor != color) {
+                    // OpenGL ES only supports the float varieties of glVertexAttrib
+                    GrGLfloat c[4];
+                    GrColorToRGBAFloat(color, c);
+                    GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
+                    sharedState->fConstAttribColor = color;
+                }
+                break;
+            case GrGLProgram::Desc::kUniform_ColorInput:
+                if (fColor != color) {
+                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
+                    GrGLfloat c[4];
+                    GrColorToRGBAFloat(color, c);
+                    GrAssert(GrGLUniformManager::kInvalidUniformHandle !=
+                             fUniformHandles.fColorUni);
+                    fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c);
+                    fColor = color;
+                }
+                break;
+            case GrGLProgram::Desc::kSolidWhite_ColorInput:
+            case GrGLProgram::Desc::kTransBlack_ColorInput:
+                break;
+            default:
+                GrCrash("Unknown color type.");
+        }
+    }
+}
+
+void GrGLProgram::setCoverage(const GrDrawState& drawState,
+                              GrColor coverage,
+                              SharedGLState* sharedState) {
+    if (!(drawState.getVertexLayout() & GrDrawState::kCoverage_VertexLayoutBit)) {
+        switch (fDesc.fCoverageInput) {
+            case Desc::kAttribute_ColorInput:
+                if (sharedState->fConstAttribCoverage != coverage) {
+                    // OpenGL ES only supports the float varieties of  glVertexAttrib
+                    GrGLfloat c[4];
+                    GrColorToRGBAFloat(coverage, c);
+                    GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(), c));
+                    sharedState->fConstAttribCoverage = coverage;
+                }
+                break;
+            case Desc::kUniform_ColorInput:
+                if (fCoverage != coverage) {
+                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
+                    GrGLfloat c[4];
+                    GrColorToRGBAFloat(coverage, c);
+                    GrAssert(GrGLUniformManager::kInvalidUniformHandle !=
+                             fUniformHandles.fCoverageUni);
+                    fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c);
+                    fCoverage = coverage;
+                }
+                break;
+            case Desc::kSolidWhite_ColorInput:
+            case Desc::kTransBlack_ColorInput:
+                break;
+            default:
+                GrCrash("Unknown coverage type.");
+        }
+    }
+}
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 8b494c8..fd5e8e4 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -22,6 +22,7 @@
 class GrBinHashKeyBuilder;
 class GrGLEffect;
 class GrGLShaderBuilder;
+class SkMWCRandom;
 
 // optionally compile the experimental GS code. Set to GR_DEBUG
 // so that debug build bots will execute the code.
@@ -40,7 +41,19 @@
 public:
     SK_DECLARE_INST_COUNT(GrGLProgram)
 
-    struct Desc;
+    class Desc;
+
+    /**
+     * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the
+     * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs.
+     */
+    static void BuildDesc(const GrDrawState&,
+                          bool isPoints,
+                          GrDrawState::BlendOptFlags,
+                          GrBlendCoeff srcCoeff,
+                          GrBlendCoeff dstCoeff,
+                          const GrGpuGL* gpu,
+                          Desc* outDesc);
 
     static GrGLProgram* Create(const GrGLContextInfo& gl,
                                const Desc& desc,
@@ -70,15 +83,34 @@
     static int TexCoordAttributeIdx(int tcIdx) { return 4 + tcIdx; }
 
     /**
+     * Some GL state that is relevant to programs is not stored per-program. In particular vertex
+     * attributes are global state. This struct is read and updated by GrGLProgram::setData to
+     * allow us to avoid setting this state redundantly.
+     */
+    struct SharedGLState {
+        GrColor fConstAttribColor;
+        GrColor fConstAttribCoverage;
+
+        SharedGLState() { this->invalidate(); }
+        void invalidate() {
+            fConstAttribColor = GrColor_ILLEGAL;
+            fConstAttribCoverage = GrColor_ILLEGAL;
+        }
+    };
+
+    /**
      * This function uploads uniforms and calls each GrGLEffect's setData. It is called before a
      * draw occurs using the program after the program has already been bound. It also uses the
      * GrGpuGL object to bind the textures required by the GrGLEffects.
+     *
+     * The color and coverage params override the GrDrawState's getColor() and getCoverage() values.
      */
-    void setData(GrGpuGL*);
+    void setData(GrGpuGL*, GrColor color, GrColor coverage, SharedGLState*);
 
     // Parameters that affect code generation
     // This structs should be kept compact; it is input to an expensive hash key generator.
-    struct Desc {
+    class Desc {
+    public:
         Desc() {
             // since we use this as part of a key we can't have any uninitialized
             // padding
@@ -90,6 +122,12 @@
             return reinterpret_cast<const uint32_t*>(this);
         }
 
+        // For unit testing.
+        void setRandom(SkMWCRandom*,
+                       const GrGpuGL* gpu,
+                       const GrEffectStage stages[GrDrawState::kNumStages]);
+
+    private:
         // Specifies where the initial color comes from before the stages are applied.
         enum ColorInput {
             kSolidWhite_ColorInput,
@@ -133,6 +171,8 @@
         int8_t                      fFirstCoverageStage;
         SkBool8                     fEmitsPointSize;
         uint8_t                     fColorFilterXfermode;   // casts to enum SkXfermode::Mode
+
+        friend class GrGLProgram;
     };
 private:
     GrGLProgram(const GrGLContextInfo& gl,
@@ -172,6 +212,14 @@
 
     const char* adjustInColor(const SkString& inColor) const;
 
+    // Helper for setData(). Makes GL calls to specify the initial color when there is not
+    // per-vertex colors.
+    void setColor(const GrDrawState&, GrColor color, SharedGLState*);
+
+    // Helper for setData(). Makes GL calls to specify the initial coverage when there is not
+    // per-vertex coverages.
+    void setCoverage(const GrDrawState&, GrColor coverage, SharedGLState*);
+
     typedef SkSTArray<4, UniformHandle, true> SamplerUniSArray;
 
     struct UniformHandles {
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index ff3941d..56a2991 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -497,8 +497,7 @@
     }
 
     fHWProgramID = 0;
-    fHWConstAttribColor = GrColor_ILLEGAL;
-    fHWConstAttribCoverage = GrColor_ILLEGAL;
+    fSharedGLProgramState.invalidate();
 }
 
 namespace {
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 7bb458d..b911f40 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -55,6 +55,8 @@
 
     virtual void abandonResources() SK_OVERRIDE;
 
+    const GrGLCaps& glCaps() const { return fGLContextInfo.caps(); }
+
 private:
     // GrGpu overrides
     virtual void onResetContext() SK_OVERRIDE;
@@ -107,8 +109,6 @@
                                   bool insideClip) SK_OVERRIDE;
     virtual bool flushGraphicsState(DrawType) SK_OVERRIDE;
 
-    const GrGLCaps& glCaps() const { return fGLContextInfo.caps(); }
-
     // binds texture unit in GL
     void setTextureUnit(int unitIdx);
 
@@ -135,9 +135,6 @@
 
     static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
 
-    // for readability of function impls
-    typedef GrGLProgram::Desc        ProgramDesc;
-
     class ProgramCache : public ::GrNoncopyable {
     public:
         ProgramCache(const GrGLContextInfo& gl);
@@ -146,7 +143,7 @@
         GrGLProgram* getProgram(const GrGLProgram::Desc& desc, const GrEffectStage* stages[]);
     private:
         enum {
-            kKeySize = sizeof(ProgramDesc),
+            kKeySize = sizeof(GrGLProgram::Desc),
             // We may actually have kMaxEntries+1 shaders in the GL context because we create a new
             // shader before evicting from the cache.
             kMaxEntries = 32
@@ -184,16 +181,10 @@
         const GrGLContextInfo&      fGL;
     };
 
-    // sets the color specified by GrDrawState::setColor()
-    void flushColor(GrColor color);
-
-    // sets the color specified by GrDrawState::setCoverage()
-    void flushCoverage(GrColor color);
 
     // sets the MVP matrix uniform for currently bound program
     void flushViewMatrix(DrawType type);
 
-
     // flushes dithering, color-mask, and face culling stat
     void flushMiscFixedFunctionState();
 
@@ -201,11 +192,6 @@
     // flushing the scissor after that function is called.
     void flushScissor();
 
-    void buildProgram(bool isPoints,
-                      GrDrawState::BlendOptFlags blendOpts,
-                      GrBlendCoeff dstCoeff,
-                      ProgramDesc* desc);
-
     // Inits GrDrawTarget::Caps, subclass may enable additional caps.
     void initCaps();
 
@@ -266,8 +252,8 @@
     ///@{
     int                         fHWActiveTextureUnitIdx;
     GrGLuint                    fHWProgramID;
-    GrColor                     fHWConstAttribColor;
-    GrColor                     fHWConstAttribCoverage;
+
+    GrGLProgram::SharedGLState  fSharedGLProgramState;
 
     enum TriState {
         kNo_TriState,
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 570ca19..feff02e 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -31,7 +31,7 @@
     fCount = 0;
 }
 
-GrGLProgram* GrGpuGL::ProgramCache::getProgram(const ProgramDesc& desc,
+GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgram::Desc& desc,
                                                const GrEffectStage* stages[]) {
     Entry newEntry;
     newEntry.fKey.setKeyData(desc.asKey());
@@ -174,101 +174,6 @@
     }
 }
 
-///////////////////////////////////////////////////////////////////////////////
-
-void GrGpuGL::flushColor(GrColor color) {
-    const ProgramDesc& desc = fCurrentProgram->getDesc();
-    const GrDrawState& drawState = this->getDrawState();
-
-    if (drawState.getVertexLayout() & GrDrawState::kColor_VertexLayoutBit) {
-        // color will be specified per-vertex as an attribute
-        // invalidate the const vertex attrib color
-        fHWConstAttribColor = GrColor_ILLEGAL;
-    } else {
-        switch (desc.fColorInput) {
-            case ProgramDesc::kAttribute_ColorInput:
-                if (fHWConstAttribColor != color) {
-                    // OpenGL ES only supports the float varieties of glVertexAttrib
-                    GrGLfloat c[4];
-                    GrColorToRGBAFloat(color, c);
-                    GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
-                    fHWConstAttribColor = color;
-                }
-                break;
-            case ProgramDesc::kUniform_ColorInput:
-                if (fCurrentProgram->fColor != color) {
-                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
-                    GrGLfloat c[4];
-                    GrColorToRGBAFloat(color, c);
-                    GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniformHandles.fColorUni);
-                    fCurrentProgram->fUniformManager.set4fv(
-                                                        fCurrentProgram->fUniformHandles.fColorUni,
-                                                        0, 1, c);
-                    fCurrentProgram->fColor = color;
-                }
-                break;
-            case ProgramDesc::kSolidWhite_ColorInput:
-            case ProgramDesc::kTransBlack_ColorInput:
-                break;
-            default:
-                GrCrash("Unknown color type.");
-        }
-    }
-    UniformHandle filterColorUni = fCurrentProgram->fUniformHandles.fColorFilterUni;
-    if (kInvalidUniformHandle != filterColorUni &&
-        fCurrentProgram->fColorFilterColor != drawState.getColorFilterColor()) {
-        GrGLfloat c[4];
-        GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
-        fCurrentProgram->fUniformManager.set4fv(filterColorUni, 0, 1, c);
-        fCurrentProgram->fColorFilterColor = drawState.getColorFilterColor();
-    }
-}
-
-void GrGpuGL::flushCoverage(GrColor coverage) {
-    const ProgramDesc& desc = fCurrentProgram->getDesc();
-    // const GrDrawState& drawState = this->getDrawState();
-
-
-    if (this->getDrawState().getVertexLayout() & GrDrawState::kCoverage_VertexLayoutBit) {
-        // coverage will be specified per-vertex as an attribute
-        // invalidate the const vertex attrib coverage
-        fHWConstAttribCoverage = GrColor_ILLEGAL;
-    } else {
-        switch (desc.fCoverageInput) {
-            case ProgramDesc::kAttribute_ColorInput:
-                if (fHWConstAttribCoverage != coverage) {
-                    // OpenGL ES only supports the float varieties of
-                    // glVertexAttrib
-                    GrGLfloat c[4];
-                    GrColorToRGBAFloat(coverage, c);
-                    GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(),
-                                            c));
-                    fHWConstAttribCoverage = coverage;
-                }
-                break;
-            case ProgramDesc::kUniform_ColorInput:
-                if (fCurrentProgram->fCoverage != coverage) {
-                    // OpenGL ES doesn't support unsigned byte varieties of
-                    // glUniform
-                    GrGLfloat c[4];
-                    GrColorToRGBAFloat(coverage, c);
-                    GrAssert(kInvalidUniformHandle !=
-                             fCurrentProgram->fUniformHandles.fCoverageUni);
-                    fCurrentProgram->fUniformManager.set4fv(
-                                                    fCurrentProgram->fUniformHandles.fCoverageUni,
-                                                    0, 1, c);
-                    fCurrentProgram->fCoverage = coverage;
-                }
-                break;
-            case ProgramDesc::kSolidWhite_ColorInput:
-            case ProgramDesc::kTransBlack_ColorInput:
-                break;
-            default:
-                GrCrash("Unknown coverage type.");
-        }
-    }
-}
-
 bool GrGpuGL::flushGraphicsState(DrawType type) {
     const GrDrawState& drawState = this->getDrawState();
 
@@ -291,7 +196,13 @@
             stages[i] = drawState.isStageEnabled(i) ? &drawState.getStage(i) : NULL;
         }
         GrGLProgram::Desc desc;
-        this->buildProgram(kDrawPoints_DrawType == type, blendOpts, dstCoeff, &desc);
+        GrGLProgram::BuildDesc(this->getDrawState(),
+                               kDrawPoints_DrawType == type,
+                               blendOpts,
+                               srcCoeff,
+                               dstCoeff,
+                               this,
+                               &desc);
 
         fCurrentProgram.reset(fProgramCache->getProgram(desc, stages));
         if (NULL == fCurrentProgram.get()) {
@@ -319,10 +230,7 @@
             color = drawState.getColor();
             coverage = drawState.getCoverage();
         }
-        this->flushColor(color);
-        this->flushCoverage(coverage);
-
-        fCurrentProgram->setData(this);
+        fCurrentProgram->setData(this, color, coverage, &fSharedGLProgramState);
     }
     this->flushStencil(type);
     this->flushViewMatrix(type);
@@ -399,6 +307,7 @@
     }
 
     if (newColorOffset > 0) {
+        fSharedGLProgramState.fConstAttribColor = GrColor_ILLEGAL;
         GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
         int idx = GrGLProgram::ColorAttributeIdx();
         if (oldColorOffset <= 0) {
@@ -412,6 +321,7 @@
     }
 
     if (newCoverageOffset > 0) {
+        fSharedGLProgramState.fConstAttribColor = GrColor_ILLEGAL;
         GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset);
         int idx = GrGLProgram::CoverageAttributeIdx();
         if (oldCoverageOffset <= 0) {
@@ -442,146 +352,3 @@
     fHWGeometryState.fVertexLayout = currLayout;
     fHWGeometryState.fArrayPtrsDirty = false;
 }
-
-void GrGpuGL::buildProgram(bool isPoints,
-                           GrDrawState::BlendOptFlags blendOpts,
-                           GrBlendCoeff dstCoeff,
-                           ProgramDesc* desc) {
-    const GrDrawState& drawState = this->getDrawState();
-
-    // This should already have been caught
-    GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
-
-    bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
-
-    bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
-                                           GrDrawState::kEmitCoverage_BlendOptFlag));
-
-    // The descriptor is used as a cache key. Thus when a field of the
-    // descriptor will not affect program generation (because of the vertex
-    // layout in use or other descriptor field settings) it should be set
-    // to a canonical value to avoid duplicate programs with different keys.
-
-    // Must initialize all fields or cache will have false negatives!
-    desc->fVertexLayout = this->getDrawState().getVertexLayout();
-
-    desc->fEmitsPointSize = isPoints;
-
-    bool requiresAttributeColors = !skipColor &&
-                                   SkToBool(desc->fVertexLayout & GrDrawState::kColor_VertexLayoutBit);
-    bool requiresAttributeCoverage = !skipCoverage &&
-                                     SkToBool(desc->fVertexLayout & GrDrawState::kCoverage_VertexLayoutBit);
-
-    // fColorInput/fCoverageInput records how colors are specified for the.
-    // program. So we strip the bits from the layout to avoid false negatives
-    // when searching for an existing program in the cache.
-    desc->fVertexLayout &= ~(GrDrawState::kColor_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit);
-
-    desc->fColorFilterXfermode = skipColor ?
-                                SkXfermode::kDst_Mode :
-                                drawState.getColorFilterMode();
-
-    // no reason to do edge aa or look at per-vertex coverage if coverage is
-    // ignored
-    if (skipCoverage) {
-        desc->fVertexLayout &= ~(GrDrawState::kEdge_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit);
-    }
-
-    bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
-    bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
-                             (!requiresAttributeColors && 0xffffffff == drawState.getColor());
-    if (colorIsTransBlack) {
-        desc->fColorInput = ProgramDesc::kTransBlack_ColorInput;
-    } else if (colorIsSolidWhite) {
-        desc->fColorInput = ProgramDesc::kSolidWhite_ColorInput;
-    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
-        desc->fColorInput = ProgramDesc::kUniform_ColorInput;
-    } else {
-        desc->fColorInput = ProgramDesc::kAttribute_ColorInput;
-    }
-
-    bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage();
-
-    if (skipCoverage) {
-        desc->fCoverageInput = ProgramDesc::kTransBlack_ColorInput;
-    } else if (covIsSolidWhite) {
-        desc->fCoverageInput = ProgramDesc::kSolidWhite_ColorInput;
-    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
-        desc->fCoverageInput = ProgramDesc::kUniform_ColorInput;
-    } else {
-        desc->fCoverageInput = ProgramDesc::kAttribute_ColorInput;
-    }
-
-    int lastEnabledStage = -1;
-
-    if (!skipCoverage && (desc->fVertexLayout &GrDrawState::kEdge_VertexLayoutBit)) {
-        desc->fVertexEdgeType = drawState.getVertexEdgeType();
-        desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
-    } else {
-        // Use canonical values when edge-aa is not enabled to avoid program cache misses.
-        desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
-        desc->fDiscardIfOutsideEdge = false;
-    }
-
-    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-
-        bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage;
-        if (!skip && drawState.isStageEnabled(s)) {
-            lastEnabledStage = s;
-            const GrEffectRef& effect = *drawState.getStage(s).getEffect();
-            const GrBackendEffectFactory& factory = effect->getFactory();
-            desc->fEffectKeys[s] = factory.glEffectKey(drawState.getStage(s), this->glCaps());
-        } else {
-            desc->fEffectKeys[s] = 0;
-        }
-    }
-
-    desc->fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
-
-    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
-    // other than pass through values from the VS to the FS anyway).
-#if 0 && GR_GL_EXPERIMENTAL_GS
-    desc->fExperimentalGS = this->getCaps().fGeometryShaderSupport;
-#endif
-
-    // We want to avoid generating programs with different "first cov stage" values when they would
-    // compute the same result. We set field in the desc to kNumStages when either there are no
-    // coverage stages or the distinction between coverage and color is immaterial.
-    int firstCoverageStage = GrDrawState::kNumStages;
-    desc->fFirstCoverageStage = GrDrawState::kNumStages;
-    bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage;
-    if (hasCoverage) {
-        firstCoverageStage = drawState.getFirstCoverageStage();
-    }
-
-    // other coverage inputs
-    if (!hasCoverage) {
-        hasCoverage = requiresAttributeCoverage ||
-                      (desc->fVertexLayout & GrDrawState::kEdge_VertexLayoutBit);
-    }
-
-    if (hasCoverage) {
-        // color filter is applied between color/coverage computation
-        if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
-            desc->fFirstCoverageStage = firstCoverageStage;
-        }
-
-        if (this->getCaps().dualSourceBlendingSupport() &&
-            !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
-                           GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
-            if (kZero_GrBlendCoeff == dstCoeff) {
-                // write the coverage value to second color
-                desc->fDualSrcOutput =  ProgramDesc::kCoverage_DualSrcOutput;
-                desc->fFirstCoverageStage = firstCoverageStage;
-            } else if (kSA_GrBlendCoeff == dstCoeff) {
-                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
-                desc->fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
-                desc->fFirstCoverageStage = firstCoverageStage;
-            } else if (kSC_GrBlendCoeff == dstCoeff) {
-                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
-                desc->fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
-                desc->fFirstCoverageStage = firstCoverageStage;
-            }
-        }
-    }
-}