Add a requiresVertexShader method to GrGLEffect

Adds requiresVertexShader to GrGLEffect and updates the necessary
effects to override it and return true. Also reworks GrGLProgram
and GrGLShaderBuilder so the program creates all the GL effects
at the beginning, and determines if it needs a vertex shader before
creating the shader builder.

R=bsalomon@google.com

Author: cdalton@nvidia.com

Review URL: https://chromiumcodereview.appspot.com/23471008

git-svn-id: http://skia.googlecode.com/svn/trunk@11140 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index e50e6b4..5ecc4e2 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -524,6 +524,8 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
             : INHERITED (factory) {}
 
+        virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
         virtual void emitCode(GrGLShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 9d436c3..b104df5 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -44,6 +44,8 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
+        virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
         virtual void emitCode(GrGLShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
@@ -164,6 +166,8 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
+        virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
         virtual void emitCode(GrGLShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 70c6f11..79c8e83 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -91,6 +91,8 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
+        virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
         virtual void emitCode(GrGLShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
@@ -205,6 +207,8 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
+        virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
         virtual void emitCode(GrGLShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 0d57b10..a55ceab 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -15,6 +15,8 @@
 public:
     GrGLConicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
+    virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
     virtual void emitCode(GrGLShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
@@ -158,6 +160,8 @@
 public:
     GrGLQuadEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
+    virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
     virtual void emitCode(GrGLShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
@@ -290,6 +294,8 @@
 public:
     GrGLCubicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
+    virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
+
     virtual void emitCode(GrGLShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index ccf761a..97e711e 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -24,6 +24,11 @@
         }
     }
 
+    virtual bool requiresVertexShader(const GrDrawEffect& drawEffect) const SK_OVERRIDE {
+        const GrSimpleTextureEffect& ste = drawEffect.castEffect<GrSimpleTextureEffect>();
+        return GrEffect::kCustom_CoordsType == ste.coordsType();
+    }
+
     virtual void emitCode(GrGLShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h
index 5df2281..2d7258e 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -51,6 +51,13 @@
 
     virtual ~GrGLEffect();
 
+    /** Called when GrGLProgram is about to create its GrGLShaderBuilder. When possible, effects
+        should handle programs that don't have a vertex shader. But if an effect requires special
+        vertex processing that can't be accomplished with the fixed pipeline, it can override this
+        method and return true to guarantee the GrGLShaderBuilder in emitCode has a VertexBuilder.
+        */
+    virtual bool requiresVertexShader(const GrDrawEffect&) const { return false; }
+
     /** Called when the program stage should insert its code into the shaders. The code in each
         shader will be in its own block ({}) and so locally scoped names will not collide across
         stages.
diff --git a/src/gpu/gl/GrGLEffectMatrix.cpp b/src/gpu/gl/GrGLEffectMatrix.cpp
index 7530b59..ef3812e 100644
--- a/src/gpu/gl/GrGLEffectMatrix.cpp
+++ b/src/gpu/gl/GrGLEffectMatrix.cpp
@@ -48,6 +48,7 @@
                                     SkString* fsCoordName,
                                     SkString* vsCoordName,
                                     const char* suffix) {
+    // TODO: Handle vertexless shaders here before we start enabling them.
     GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
     SkASSERT(NULL != vertexBuilder);
 
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index ac9794d..ebc5782 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -446,10 +446,32 @@
     SkASSERT(0 == fProgramID);
 
     const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
+    bool hasExplicitLocalCoords = -1 != header.fLocalCoordAttributeIndex;
 
-    bool needsVertexShader = true;
+    // Get the coeffs for the Mode-based color filter, determine if color is needed.
+    SkXfermode::Coeff colorCoeff;
+    SkXfermode::Coeff filterColorCoeff;
+    SkAssertResult(
+        SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>(header.fColorFilterXfermode),
+                                &filterColorCoeff,
+                                &colorCoeff));
+    bool needColor, needFilterColor;
+    need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor);
 
-    GrGLShaderBuilder builder(fGpu->ctxInfo(), fUniformManager, fDesc, needsVertexShader);
+    // Create the GL effects.
+    bool hasVertexShaderEffects = false;
+
+    SkTArray<GrDrawEffect> colorDrawEffects(needColor ? fDesc.numColorEffects() : 0);
+    if (needColor) {
+        this->buildGLEffects(&GrGLProgram::fColorEffects, colorStages, fDesc.numColorEffects(),
+                             hasExplicitLocalCoords, &colorDrawEffects, &hasVertexShaderEffects);
+    }
+
+    SkTArray<GrDrawEffect> coverageDrawEffects(fDesc.numCoverageEffects());
+    this->buildGLEffects(&GrGLProgram::fCoverageEffects, coverageStages, fDesc.numCoverageEffects(),
+                         hasExplicitLocalCoords, &coverageDrawEffects, &hasVertexShaderEffects);
+
+    GrGLShaderBuilder builder(fGpu->ctxInfo(), fUniformManager, fDesc, hasVertexShaderEffects);
 
     if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) {
         const char* viewMName;
@@ -486,16 +508,6 @@
     SkString inColor;
     GrSLConstantVec knownColorValue = this->genInputColor(&builder, &inColor);
 
-    // Get the coeffs for the Mode-based color filter, determine if color is needed.
-    SkXfermode::Coeff colorCoeff;
-    SkXfermode::Coeff filterColorCoeff;
-    SkAssertResult(
-        SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>(header.fColorFilterXfermode),
-                                &filterColorCoeff,
-                                &colorCoeff));
-    bool needColor, needFilterColor;
-    need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor);
-
     // used in order for builder to return the per-stage uniform handles.
     typedef SkTArray<GrGLUniformManager::UniformHandle, true>* UniHandleArrayPtr;
     int maxColorOrCovEffectCnt = GrMax(fDesc.numColorEffects(), fDesc.numCoverageEffects());
@@ -504,20 +516,17 @@
 
     if (needColor) {
         for (int e = 0; e < fDesc.numColorEffects(); ++e) {
+            glEffects[e] = fColorEffects[e].fGLEffect;
             effectUniformArrays[e] = &fColorEffects[e].fSamplerUnis;
         }
 
-        builder.emitEffects(colorStages,
+        builder.emitEffects(glEffects.get(),
+                            colorDrawEffects.begin(),
                             fDesc.effectKeys(),
                             fDesc.numColorEffects(),
                             &inColor,
                             &knownColorValue,
-                            effectUniformArrays.get(),
-                            glEffects.get());
-
-        for (int e = 0; e < fDesc.numColorEffects(); ++e) {
-            fColorEffects[e].fGLEffect = glEffects[e];
-        }
+                            effectUniformArrays.get());
     }
 
     // Insert the color filter. This will soon be replaced by a color effect.
@@ -548,19 +557,17 @@
     GrSLConstantVec knownCoverageValue = this->genInputCoverage(&builder, &inCoverage);
 
     for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
+        glEffects[e] = fCoverageEffects[e].fGLEffect;
         effectUniformArrays[e] = &fCoverageEffects[e].fSamplerUnis;
     }
 
-    builder.emitEffects(coverageStages,
+    builder.emitEffects(glEffects.get(),
+                        coverageDrawEffects.begin(),
                         fDesc.getEffectKeys() + fDesc.numColorEffects(),
                         fDesc.numCoverageEffects(),
                         &inCoverage,
                         &knownCoverageValue,
-                        effectUniformArrays.get(),
-                        glEffects.get());
-    for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
-        fCoverageEffects[e].fGLEffect = glEffects[e];
-    }
+                        effectUniformArrays.get());
 
     // discard if coverage is zero
     if (header.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
@@ -689,6 +696,28 @@
     return true;
 }
 
+void GrGLProgram::buildGLEffects(SkTArray<EffectAndSamplers> GrGLProgram::* effectSet,
+                                 const GrEffectStage* stages[],
+                                 int count,
+                                 bool hasExplicitLocalCoords,
+                                 SkTArray<GrDrawEffect>* drawEffects,
+                                 bool* hasVertexShaderEffects) {
+    for (int e = 0; e < count; ++e) {
+        SkASSERT(NULL != stages[e] && NULL != stages[e]->getEffect());
+
+        const GrEffectStage& stage = *stages[e];
+        SkNEW_APPEND_TO_TARRAY(drawEffects, GrDrawEffect, (stage, hasExplicitLocalCoords));
+
+        const GrDrawEffect& drawEffect = (*drawEffects)[e];
+        GrGLEffect* effect = (this->*effectSet)[e].fGLEffect =
+            (*stage.getEffect())->getFactory().createGLInstance(drawEffect);
+
+        if (!*hasVertexShaderEffects && effect->requiresVertexShader(drawEffect)) {
+            *hasVertexShaderEffects = true;
+        }
+    }
+}
+
 bool GrGLProgram::bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder,
                                                    bool bindColorOut,
                                                    bool bindDualSrcOut) {
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 4a16b0c..bef2ecf 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -178,6 +178,14 @@
 
     void genGeometryShader(GrGLShaderBuilder::VertexBuilder* vertexBuilder) const;
 
+    // Creates a set of GrGLEffects and GrGLDrawEffects.
+    void buildGLEffects(SkTArray<EffectAndSamplers> GrGLProgram::* effectSet,
+                        const GrEffectStage* stages[],
+                        int count,
+                        bool hasExplicitLocalCoords,
+                        SkTArray<GrDrawEffect>* drawEffects,
+                        bool* hasVertexShaderEffects);
+
     // Creates a GL program ID, binds shader attributes to GL vertex attrs, and links the program
     bool bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder,
                                           bool bindColorOut,
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index e62bfde..5e00d7f 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -94,7 +94,7 @@
 GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo,
                                      GrGLUniformManager& uniformManager,
                                      const GrGLProgramDesc& desc,
-                                     bool needsVertexShader)
+                                     bool hasVertexShaderEffects)
     : fUniforms(kVarsPerBlock)
     , fCtxInfo(ctxInfo)
     , fUniformManager(uniformManager)
@@ -106,9 +106,8 @@
 
     const GrGLProgramDesc::KeyHeader& header = desc.getHeader();
 
-    if (needsVertexShader) {
-        fVertexBuilder.reset(SkNEW_ARGS(VertexBuilder, (this, desc)));
-    }
+    // TODO: go vertexless when possible.
+    fVertexBuilder.reset(SkNEW_ARGS(VertexBuilder, (this, desc)));
 
     // Emit code to read the dst copy textue if necessary.
     if (kNoDstRead_DstReadKey != header.fDstReadKey &&
@@ -217,7 +216,7 @@
 
 const char* GrGLShaderBuilder::dstColor() {
     if (fCodeStage.inStageCode()) {
-        const GrEffectRef& effect = *fCodeStage.effectStage()->getEffect();
+        const GrEffectRef& effect = *fCodeStage.effect();
         if (!effect->willReadDstColor()) {
             GrDebugCrash("GrGLEffect asked for dst color but its generating GrEffect "
                          "did not request access.");
@@ -363,7 +362,7 @@
 
 const char* GrGLShaderBuilder::fragmentPosition() {
     if (fCodeStage.inStageCode()) {
-        const GrEffectRef& effect = *fCodeStage.effectStage()->getEffect();
+        const GrEffectRef& effect = *fCodeStage.effect();
         if (!effect->willReadFragmentPosition()) {
             GrDebugCrash("GrGLEffect asked for frag position but its generating GrEffect "
                          "did not request access.");
@@ -500,24 +499,23 @@
 }
 
 void GrGLShaderBuilder::emitEffects(
-                        const GrEffectStage* effectStages[],
+                        GrGLEffect* const glEffects[],
+                        const GrDrawEffect drawEffects[],
                         const GrBackendEffectFactory::EffectKey effectKeys[],
                         int effectCnt,
                         SkString* fsInOutColor,
                         GrSLConstantVec* fsInOutColorKnownValue,
-                        SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[],
-                        GrGLEffect* glEffects[]) {
+                        SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[]) {
     bool effectEmitted = false;
 
     SkString inColor = *fsInOutColor;
     SkString outColor;
 
     for (int e = 0; e < effectCnt; ++e) {
-        SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect());
-        const GrEffectStage& stage = *effectStages[e];
-        const GrEffectRef& effect = *stage.getEffect();
+        const GrDrawEffect& drawEffect = drawEffects[e];
+        const GrEffectRef& effect = *drawEffect.effect();
 
-        CodeStage::AutoStageRestore csar(&fCodeStage, &stage);
+        CodeStage::AutoStageRestore csar(&fCodeStage, &effect);
 
         int numTextures = effect->numTextures();
         SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
@@ -526,11 +524,9 @@
             textureSamplers[t].init(this, &effect->textureAccess(t), t);
             effectSamplerHandles[e]->push_back(textureSamplers[t].fSamplerUniform);
         }
-        GrDrawEffect drawEffect(stage, fVertexBuilder.get()
-                                       && fVertexBuilder->hasExplicitLocalCoords());
 
-        int numAttributes = stage.getVertexAttribIndexCount();
-        const int* attributeIndices = stage.getVertexAttribIndices();
+        int numAttributes = drawEffect.getVertexAttribIndexCount();
+        const int* attributeIndices = drawEffect.getVertexAttribIndices();
         SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames;
         for (int a = 0; a < numAttributes; ++a) {
             // TODO: Make addAttribute mangle the name.
@@ -542,8 +538,6 @@
                                                attributeName);
         }
 
-        glEffects[e] = effect->getFactory().createGLInstance(drawEffect);
-
         if (kZeros_GrSLConstantVec == *fsInOutColorKnownValue) {
             // Effects have no way to communicate zeros, they treat an empty string as ones.
             this->nameVariable(&inColor, '\0', "input");
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 28f1b38..42df62a 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -107,7 +107,7 @@
     GrGLShaderBuilder(const GrGLContextInfo&,
                       GrGLUniformManager&,
                       const GrGLProgramDesc&,
-                      bool needsVertexShader);
+                      bool hasVertexShaderEffects);
 
     /**
      * Use of these features may require a GLSL extension to be enabled. Shaders may not compile
@@ -256,13 +256,13 @@
      * glEffects array is updated to contain the GrGLEffect generated for each entry in
      * effectStages.
      */
-    void emitEffects(const GrEffectStage* effectStages[],
+    void emitEffects(GrGLEffect* const glEffects[],
+                     const GrDrawEffect drawEffects[],
                      const GrBackendEffectFactory::EffectKey effectKeys[],
                      int effectCnt,
                      SkString*  inOutFSColor,
                      GrSLConstantVec* fsInOutColorKnownValue,
-                     SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[],
-                     GrGLEffect* glEffects[]);
+                     SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[]);
 
     GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
     GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const {
@@ -388,16 +388,16 @@
 private:
     class CodeStage : GrNoncopyable {
     public:
-        CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
+        CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffect(NULL) {}
 
         bool inStageCode() const {
             this->validate();
-            return NULL != fEffectStage;
+            return NULL != fEffect;
         }
 
-        const GrEffectStage* effectStage() const {
+        const GrEffectRef* effect() const {
             this->validate();
-            return fEffectStage;
+            return fEffect;
         }
 
         int stageIndex() const {
@@ -407,34 +407,34 @@
 
         class AutoStageRestore : GrNoncopyable {
         public:
-            AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
+            AutoStageRestore(CodeStage* codeStage, const GrEffectRef* effect) {
                 SkASSERT(NULL != codeStage);
                 fSavedIndex = codeStage->fCurrentIndex;
-                fSavedEffectStage = codeStage->fEffectStage;
+                fSavedEffect = codeStage->fEffect;
 
-                if (NULL == newStage) {
+                if (NULL == effect) {
                     codeStage->fCurrentIndex = -1;
                 } else {
                     codeStage->fCurrentIndex = codeStage->fNextIndex++;
                 }
-                codeStage->fEffectStage = newStage;
+                codeStage->fEffect = effect;
 
                 fCodeStage = codeStage;
             }
             ~AutoStageRestore() {
                 fCodeStage->fCurrentIndex = fSavedIndex;
-                fCodeStage->fEffectStage = fSavedEffectStage;
+                fCodeStage->fEffect = fSavedEffect;
             }
         private:
-            CodeStage*              fCodeStage;
-            int                     fSavedIndex;
-            const GrEffectStage*    fSavedEffectStage;
+            CodeStage*            fCodeStage;
+            int                   fSavedIndex;
+            const GrEffectRef*    fSavedEffect;
         };
     private:
-        void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
-        int                     fNextIndex;
-        int                     fCurrentIndex;
-        const GrEffectStage*    fEffectStage;
+        void validate() const { SkASSERT((NULL == fEffect) == (-1 == fCurrentIndex)); }
+        int                   fNextIndex;
+        int                   fCurrentIndex;
+        const GrEffectRef*    fEffect;
     } fCodeStage;
 
     /**