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.");
+        }
+    }
+}