Mark when effects and programs have vertex code

Adds a 'hasVertexCode' method to GrEffect and a 'fHasVertexCode' field
to GrGLProgramDesc::KeyHeader. Also adds a GrVertexEffect class that
effects have to inherit from in order to set the 'hasVertexCode' flag
and be able to emit vertex code, and updates the existing effects to
use it as needed.

R=bsalomon@google.com

Author: cdalton@nvidia.com

Review URL: https://codereview.chromium.org/23653059

git-svn-id: http://skia.googlecode.com/svn/trunk@11537 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index e7590b6..4dc294b 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -17,6 +17,7 @@
 class GrBackendEffectFactory;
 class GrContext;
 class GrEffect;
+class GrVertexEffect;
 class SkString;
 
 /**
@@ -152,7 +153,14 @@
     /** Will this effect read the fragment position? */
     bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
 
-    int numVertexAttribs() const { return fVertexAttribTypes.count(); }
+    /** Will this effect emit custom vertex shader code?
+        (To set this value the effect must inherit from GrVertexEffect.) */
+    bool hasVertexCode() const { return fHasVertexCode; }
+
+    int numVertexAttribs() const {
+        SkASSERT(0 == fVertexAttribTypes.count() || fHasVertexCode);
+        return fVertexAttribTypes.count();
+    }
 
     GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
 
@@ -204,14 +212,11 @@
      */
     void addTextureAccess(const GrTextureAccess* textureAccess);
 
-    /**
-     * Subclasses call this from their constructor to register vertex attributes (at most
-     * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
-     * immutable.
-     */
-    void addVertexAttrib(GrSLType type);
-
-    GrEffect() : fWillReadDstColor(false), fWillReadFragmentPosition(false), fEffectRef(NULL) {}
+    GrEffect()
+        : fWillReadDstColor(false)
+        , fWillReadFragmentPosition(false)
+        , fHasVertexCode(false)
+        , fEffectRef(NULL) {}
 
     /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for
         an example factory function. */
@@ -300,15 +305,17 @@
 
     void EffectRefDestroyed() { fEffectRef = NULL; }
 
-    friend class GrEffectRef;   // to call EffectRefDestroyed()
-    friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
-                                // from deferred state, to call isEqual on naked GrEffects, and
-                                // to inc/dec deferred ref counts.
+    friend class GrEffectRef;    // to call EffectRefDestroyed()
+    friend class GrEffectStage;  // to rewrap GrEffect in GrEffectRef when restoring an effect-stage
+                                 // from deferred state, to call isEqual on naked GrEffects, and
+                                 // to inc/dec deferred ref counts.
+    friend class GrVertexEffect; // to set fHasVertexCode and build fVertexAttribTypes.
 
     SkSTArray<4, const GrTextureAccess*, true>   fTextureAccesses;
     SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
     bool                                         fWillReadDstColor;
     bool                                         fWillReadFragmentPosition;
+    bool                                         fHasVertexCode;
     GrEffectRef*                                 fEffectRef;
 
     typedef SkRefCnt INHERITED;
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 6749b46..7063440 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -21,6 +21,8 @@
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
 
+#include "effects/GrVertexEffect.h"
+
 GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
 }
 
@@ -497,7 +499,7 @@
  * Requires shader derivative instruction support.
  */
 
-class QuadEdgeEffect : public GrEffect {
+class QuadEdgeEffect : public GrVertexEffect {
 public:
 
     static GrEffectRef* Create() {
@@ -586,7 +588,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(QuadEdgeEffect);
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 4856bb5..e4bf853 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -10,6 +10,7 @@
 #include "gl/GrGLEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkColorPriv.h"
+#include "effects/GrVertexEffect.h"
 
 SK_DEFINE_INST_COUNT(GrAARectRenderer)
 
@@ -17,7 +18,7 @@
 class GrGLAlignedRectEffect;
 
 // Axis Aligned special case
-class GrAlignedRectEffect : public GrEffect {
+class GrAlignedRectEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create() {
         GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
@@ -101,7 +102,7 @@
 
 
 private:
-    GrAlignedRectEffect() : GrEffect() {
+    GrAlignedRectEffect() : GrVertexEffect() {
         this->addVertexAttrib(kVec4f_GrSLType);
     }
 
@@ -109,7 +110,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 
@@ -137,7 +138,7 @@
  * The munged width and height are stored in a vec2 varying ("WidthHeight")
  * with the width in x and the height in y.
  */
-class GrRectEffect : public GrEffect {
+class GrRectEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create() {
         GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
@@ -236,7 +237,7 @@
 
 
 private:
-    GrRectEffect() : GrEffect() {
+    GrRectEffect() : GrVertexEffect() {
         this->addVertexAttrib(kVec4f_GrSLType);
         this->addVertexAttrib(kVec2f_GrSLType);
         this->setWillReadFragmentPosition();
@@ -246,7 +247,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 
diff --git a/src/gpu/GrEffect.cpp b/src/gpu/GrEffect.cpp
index dc83f7b..53dabb6 100644
--- a/src/gpu/GrEffect.cpp
+++ b/src/gpu/GrEffect.cpp
@@ -90,11 +90,6 @@
     fTextureAccesses.push_back(access);
 }
 
-void GrEffect::addVertexAttrib(GrSLType type) {
-    SkASSERT(fVertexAttribTypes.count() < kMaxVertexAttribs);
-    fVertexAttribTypes.push_back(type);
-}
-
 void* GrEffect::operator new(size_t size) {
     return GrEffect_Globals::GetTLS()->allocate(size);
 }
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 013c7ab..66ca053 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -19,6 +19,8 @@
 #include "SkRRect.h"
 #include "SkStrokeRec.h"
 
+#include "effects/GrVertexEffect.h"
+
 SK_DEFINE_INST_COUNT(GrOvalRenderer)
 
 namespace {
@@ -56,7 +58,7 @@
  * specified as offset_x, offset_y (both from center point), outer radius and inner radius.
  */
 
-class CircleEdgeEffect : public GrEffect {
+class CircleEdgeEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create(bool stroke) {
         GR_CREATE_STATIC_EFFECT(gCircleStrokeEdge, CircleEdgeEffect, (true));
@@ -134,7 +136,7 @@
 
 
 private:
-    CircleEdgeEffect(bool stroke) : GrEffect() {
+    CircleEdgeEffect(bool stroke) : GrVertexEffect() {
         this->addVertexAttrib(kVec4f_GrSLType);
         fStroke = stroke;
     }
@@ -148,7 +150,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(CircleEdgeEffect);
@@ -170,7 +172,7 @@
  * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
  */
 
-class EllipseEdgeEffect : public GrEffect {
+class EllipseEdgeEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create(bool stroke) {
         GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true));
@@ -269,7 +271,7 @@
     };
 
 private:
-    EllipseEdgeEffect(bool stroke) : GrEffect() {
+    EllipseEdgeEffect(bool stroke) : GrVertexEffect() {
         this->addVertexAttrib(kVec2f_GrSLType);
         this->addVertexAttrib(kVec4f_GrSLType);
         fStroke = stroke;
@@ -284,7 +286,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect);
@@ -307,7 +309,7 @@
  * The result is device-independent and can be used with any affine matrix.
  */
 
-class DIEllipseEdgeEffect : public GrEffect {
+class DIEllipseEdgeEffect : public GrVertexEffect {
 public:
     enum Mode { kStroke = 0, kHairline, kFill };
 
@@ -430,7 +432,7 @@
     };
 
 private:
-    DIEllipseEdgeEffect(Mode mode) : GrEffect() {
+    DIEllipseEdgeEffect(Mode mode) : GrVertexEffect() {
         this->addVertexAttrib(kVec2f_GrSLType);
         this->addVertexAttrib(kVec2f_GrSLType);
         fMode = mode;
@@ -445,7 +447,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(DIEllipseEdgeEffect);
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index c7eadb7..b3e9f62 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -128,7 +128,7 @@
     return GrTBackendEffectFactory<GrConicEffect>::getInstance();
 }
 
-GrConicEffect::GrConicEffect(GrBezierEdgeType edgeType) : GrEffect() {
+GrConicEffect::GrConicEffect(GrBezierEdgeType edgeType) : GrVertexEffect() {
     this->addVertexAttrib(kVec4f_GrSLType);
     fEdgeType = edgeType;
 }
@@ -260,7 +260,7 @@
     return GrTBackendEffectFactory<GrQuadEffect>::getInstance();
 }
 
-GrQuadEffect::GrQuadEffect(GrBezierEdgeType edgeType) : GrEffect() {
+GrQuadEffect::GrQuadEffect(GrBezierEdgeType edgeType) : GrVertexEffect() {
     this->addVertexAttrib(kVec4f_GrSLType);
     fEdgeType = edgeType;
 }
@@ -403,7 +403,7 @@
     return GrTBackendEffectFactory<GrCubicEffect>::getInstance();
 }
 
-GrCubicEffect::GrCubicEffect(GrBezierEdgeType edgeType) : GrEffect() {
+GrCubicEffect::GrCubicEffect(GrBezierEdgeType edgeType) : GrVertexEffect() {
     this->addVertexAttrib(kVec4f_GrSLType);
     fEdgeType = edgeType;
 }
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index d31cd7e..5de7b80 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -8,8 +8,9 @@
 #ifndef GrBezierEffect_DEFINED
 #define GrBezierEffect_DEFINED
 
-#include "GrEffect.h"
 #include "GrDrawTargetCaps.h"
+#include "GrEffect.h"
+#include "GrVertexEffect.h"
 
 enum GrBezierEdgeType {
     kFillAA_GrBezierEdgeType,
@@ -67,7 +68,7 @@
  */
 class GrGLConicEffect;
 
-class GrConicEffect : public GrEffect {
+class GrConicEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create(const GrBezierEdgeType edgeType, const GrDrawTargetCaps& caps) {
         GR_CREATE_STATIC_EFFECT(gConicFillAA, GrConicEffect, (kFillAA_GrBezierEdgeType));
@@ -117,7 +118,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -131,7 +132,7 @@
  */
 class GrGLQuadEffect;
 
-class GrQuadEffect : public GrEffect {
+class GrQuadEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create(const GrBezierEdgeType edgeType, const GrDrawTargetCaps& caps) {
         GR_CREATE_STATIC_EFFECT(gQuadFillAA, GrQuadEffect, (kFillAA_GrBezierEdgeType));
@@ -181,7 +182,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -197,7 +198,7 @@
  */
 class GrGLCubicEffect;
 
-class GrCubicEffect : public GrEffect {
+class GrCubicEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create(const GrBezierEdgeType edgeType, const GrDrawTargetCaps& caps) {
         GR_CREATE_STATIC_EFFECT(gCubicFillAA, GrCubicEffect, (kFillAA_GrBezierEdgeType));
@@ -247,7 +248,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 #endif
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.h b/src/gpu/effects/GrCustomCoordsTextureEffect.h
index fad35c8..1caecf2 100644
--- a/src/gpu/effects/GrCustomCoordsTextureEffect.h
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.h
@@ -9,6 +9,7 @@
 #define GrCustomCoordsTextureEffect_DEFINED
 
 #include "GrEffect.h"
+#include "GrVertexEffect.h"
 
 class GrGLCustomCoordsTextureEffect;
 
@@ -17,7 +18,7 @@
  * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input
  * coords are a custom attribute.
  */
-class GrCustomCoordsTextureEffect : public GrEffect {
+class GrCustomCoordsTextureEffect : public GrVertexEffect {
 public:
     static GrEffectRef* Create(GrTexture* tex, const GrTextureParams& p) {
         AutoEffectUnref effect(SkNEW_ARGS(GrCustomCoordsTextureEffect, (tex, p)));
@@ -43,7 +44,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrEffect INHERITED;
+    typedef GrVertexEffect INHERITED;
 };
 
 #endif
diff --git a/src/gpu/effects/GrVertexEffect.h b/src/gpu/effects/GrVertexEffect.h
new file mode 100644
index 0000000..387ec7a
--- /dev/null
+++ b/src/gpu/effects/GrVertexEffect.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVertexEffect_DEFINED
+#define GrVertexEffect_DEFINED
+
+#include "GrEffect.h"
+
+/**
+ * If an effect needs specialized vertex shader code, then it must inherit from this class.
+ * Otherwise it won't be able to add vertex attribs, and it might be given a vertexless shader
+ * program in emitCode.
+ */
+class GrVertexEffect : public GrEffect {
+public:
+    GrVertexEffect() { fHasVertexCode = true; }
+
+protected:
+    /**
+     * Subclasses call this from their constructor to register vertex attributes (at most
+     * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
+     * immutable.
+     */
+    void addVertexAttrib(GrSLType type) {
+        SkASSERT(fVertexAttribTypes.count() < kMaxVertexAttribs);
+        fVertexAttribTypes.push_back(type);
+    }
+
+private:
+    typedef GrEffect INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 91ac266..8b731fb 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -19,7 +19,8 @@
                                                       const GrGLCaps& caps,
                                                       bool useExplicitLocalCoords,
                                                       bool* setTrueIfReadsDst,
-                                                      bool* setTrueIfReadsPos) {
+                                                      bool* setTrueIfReadsPos,
+                                                      bool* setTrueIfHasVertexCode) {
     const GrEffectRef& effect = *stage.getEffect();
     const GrBackendEffectFactory& factory = effect->getFactory();
     GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
@@ -29,6 +30,9 @@
     if (effect->willReadFragmentPosition()) {
         *setTrueIfReadsPos = true;
     }
+    if (effect->hasVertexCode()) {
+        *setTrueIfHasVertexCode = true;
+    }
     return factory.glEffectKey(drawEffect, caps);
 }
 }
@@ -87,21 +91,25 @@
     int currEffectKey = 0;
     bool readsDst = false;
     bool readFragPosition = false;
+    bool hasVertexCode = false;
     if (!skipColor) {
         for (int s = 0; s < drawState.numColorStages(); ++s) {
             effectKeys[currEffectKey++] =
                 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
-                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition);
+                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition,
+                                         &hasVertexCode);
         }
     }
     if (!skipCoverage) {
         for (int s = 0; s < drawState.numCoverageStages(); ++s) {
             effectKeys[currEffectKey++] =
                 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
-                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition);
+                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition,
+                                         &hasVertexCode);
         }
     }
 
+    header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
     header->fEmitsPointSize = isPoints;
     header->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();
 
@@ -122,6 +130,7 @@
         header->fColorInput = kUniform_ColorInput;
     } else {
         header->fColorInput = kAttribute_ColorInput;
+        header->fHasVertexCode = true;
     }
 
     bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
@@ -134,6 +143,7 @@
         header->fCoverageInput = kUniform_ColorInput;
     } else {
         header->fCoverageInput = kAttribute_ColorInput;
+        header->fHasVertexCode = true;
     }
 
     if (readsDst) {
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index fb67a97..308b0c7 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -158,6 +158,7 @@
         uint8_t                     fCoverageInput;         // casts to enum ColorInput
         uint8_t                     fCoverageOutput;        // casts to enum CoverageOutput
 
+        SkBool8                     fHasVertexCode;
         SkBool8                     fEmitsPointSize;
         uint8_t                     fColorFilterXfermode;   // casts to enum SkXfermode::Mode