Take two for r8466:

Replace the old attribute binding and index interface with one where we include the binding as part of the attribute array. Also removed the fixed attribute indices for constant color and coverage attributes, and replaced with dynamic ones based on current attribute set. Removed binding of color and coverage attributes unless they're actually set.

Original author: bsalomon@google.com

Author: jvanverth@google.com

Reviewed By: bsalomon@google.com,robertphillips@google.com

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


git-svn-id: http://skia.googlecode.com/svn/trunk@8468 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 9f24190..53c237b 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -485,13 +485,10 @@
 
     // position + edge
     static const GrVertexAttrib kAttribs[] = {
-        {kVec2f_GrVertexAttribType, 0},
-        {kVec4f_GrVertexAttribType, sizeof(GrPoint)}
+        {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
+        {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
     };
-
     drawState->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
-    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-    drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
 
     enum {
         // the edge effects share this stage with glyph rendering
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 0c64a3b..ffc9c50 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -507,8 +507,8 @@
 
     // position + edge
     static const GrVertexAttrib kAttribs[] = {
-        {kVec2f_GrVertexAttribType, 0},
-        {kVec4f_GrVertexAttribType, sizeof(GrPoint)}
+        {kVec2f_GrVertexAttribType, 0,                  kPosition_GrVertexAttribBinding},
+        {kVec4f_GrVertexAttribType, sizeof(GrPoint),    kEffect_GrVertexAttribBinding}
     };
     SkMatrix viewM = drawState->getViewMatrix();
 
@@ -522,8 +522,6 @@
     int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt;
 
     target->drawState()->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
-    target->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-    target->drawState()->setAttribBindings(GrDrawState::kDefault_AttribBindings);
     GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize());
 
     if (!arg->set(target, vertCnt, 0)) {
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index b4f02ba..0093b08 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -13,15 +13,17 @@
 
 namespace {
 
-static void aa_rect_attributes(bool useCoverage, GrAttribBindings* bindings,
-                               GrDrawState::AttribIndex* index) {
-    if (useCoverage) {
-        *bindings = GrDrawState::kCoverage_AttribBindingsBit;
-        *index = GrDrawState::kCoverage_AttribIndex;
-    } else {
-        *bindings = GrDrawState::kColor_AttribBindingsBit;
-        *index = GrDrawState::kColor_AttribIndex;
-    }
+static void aa_rect_attributes(bool useCoverage, const GrVertexAttrib** attribs, int* count) {
+    static const GrVertexAttrib kCoverageAttribs[] = {
+        {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding},
+        {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
+    };
+    static const GrVertexAttrib kColorAttribs[] = {
+        {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding},
+        {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
+    };
+    *attribs = useCoverage ? kCoverageAttribs : kColorAttribs;
+    *count = 2;
 }
 
 static void set_inset_fan(GrPoint* pts, size_t stride,
@@ -128,18 +130,10 @@
                                   bool useVertexCoverage) {
     GrDrawState* drawState = target->drawState();
 
-    // position + color/coverage
-    static const GrVertexAttrib kVertexAttribs[] = {
-        {kVec2f_GrVertexAttribType, 0},
-        {kVec4ub_GrVertexAttribType, sizeof(GrPoint)}
-    };
-    GrAttribBindings bindings;
-    GrDrawState::AttribIndex attribIndex;
-    aa_rect_attributes(useVertexCoverage, &bindings, &attribIndex);
-    drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
-    drawState->setAttribBindings(bindings);
-    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-    drawState->setAttribIndex(attribIndex, 1);
+    const GrVertexAttrib* attribs;
+    int attribCount;
+    aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
+    drawState->setVertexAttribs(attribs, attribCount);
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
     if (!geo.succeeded()) {
@@ -212,18 +206,10 @@
         return;
     }
 
-    // position + color/coverage
-    static const GrVertexAttrib kVertexAttribs[] = {
-        {kVec2f_GrVertexAttribType, 0},
-        {kVec4ub_GrVertexAttribType, sizeof(GrPoint)}
-    };
-    GrAttribBindings bindings;
-    GrDrawState::AttribIndex attribIndex;
-    aa_rect_attributes(useVertexCoverage, &bindings, &attribIndex);
-    drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
-    drawState->setAttribBindings(bindings);
-    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-    drawState->setAttribIndex(attribIndex, 1);
+    const GrVertexAttrib* attribs;
+    int attribCount;
+    aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
+    drawState->setVertexAttribs(attribs, attribCount);
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
     if (!geo.succeeded()) {
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 32b4d6a..85b2c83 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -358,17 +358,13 @@
         GrTextureParams params(SkShader::kClamp_TileMode, needsFiltering);
         drawState->createTextureEffect(0, clampedTexture, SkMatrix::I(), params);
 
-        // position + texture coordinate
+        // position + local coordinate
         static const GrVertexAttrib kVertexAttribs[] = {
-            {kVec2f_GrVertexAttribType, 0},
-            {kVec2f_GrVertexAttribType, sizeof(GrPoint)}
+            {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
+            {kVec2f_GrVertexAttribType, sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding}
         };
-
-        static const GrAttribBindings kAttribBindings = GrDrawState::kLocalCoords_AttribBindingsBit;
-        drawState->setAttribBindings(kAttribBindings);
         drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
-        drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-        drawState->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, 1);
+
         GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0);
 
         if (arg.succeeded()) {
@@ -925,19 +921,16 @@
     GrVertexAttribArray<3> attribs;
     size_t currentOffset = 0;
     int colorOffset = -1, texOffset = -1;
-    GrAttribBindings bindings = GrDrawState::kDefault_AttribBindings;
 
     // set position attribute
-    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, attribs.count());
-    GrVertexAttrib currAttrib = {kVec2f_GrVertexAttribType, currentOffset};
+    GrVertexAttrib currAttrib =
+        {kVec2f_GrVertexAttribType, currentOffset, kPosition_GrVertexAttribBinding};
     attribs.push_back(currAttrib);
     currentOffset += sizeof(GrPoint);
 
     // set up optional texture coordinate attributes
     if (NULL != texCoords) {
-        bindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
-        drawState->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, attribs.count());
-        currAttrib.set(kVec2f_GrVertexAttribType, currentOffset);
+        currAttrib.set(kVec2f_GrVertexAttribType, currentOffset, kLocalCoord_GrVertexAttribBinding);
         attribs.push_back(currAttrib);
         texOffset = currentOffset;
         currentOffset += sizeof(GrPoint);
@@ -945,16 +938,13 @@
 
     // set up optional color attributes
     if (NULL != colors) {
-        bindings |= GrDrawState::kColor_AttribBindingsBit;
-        drawState->setAttribIndex(GrDrawState::kColor_AttribIndex, attribs.count());
-        currAttrib.set(kVec4ub_GrVertexAttribType, currentOffset);
+        currAttrib.set(kVec4ub_GrVertexAttribType, currentOffset, kColor_GrVertexAttribBinding);
         attribs.push_back(currAttrib);
         colorOffset = currentOffset;
         currentOffset += sizeof(GrColor);
     }
 
     drawState->setVertexAttribs(attribs.begin(), attribs.count());
-    drawState->setAttribBindings(bindings);
 
     size_t vertexSize = drawState->getVertexSize();
     GrAssert(vertexSize == currentOffset);
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index f9e12cc..6d7969f 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -46,23 +46,15 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-const size_t GrDrawState::kVertexAttribSizes[kGrVertexAttribTypeCount] = {
-    sizeof(float),          // kFloat_GrVertexAttribType
-    2*sizeof(float),        // kVec2_GrVertexAttribType
-    3*sizeof(float),        // kVec3_GrVertexAttribType
-    4*sizeof(float),        // kVec4_GrVertexAttribType
-    4*sizeof(char)          // kCVec4_GrVertexAttribType
-};
-
 static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
     // this works as long as we're 4 byte-aligned
 #if GR_DEBUG
     uint32_t overlapCheck = 0;
 #endif
-    GrAssert(count <= GrDrawState::kVertexAttribCnt);
+    GrAssert(count <= GrDrawState::kMaxVertexAttribCnt);
     size_t size = 0;
     for (int index = 0; index < count; ++index) {
-        size_t attribSize = GrDrawState::kVertexAttribSizes[attribs[index].fType];
+        size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
         size += attribSize;
 #if GR_DEBUG
         size_t dwordCount = attribSize >> 2;
@@ -76,163 +68,102 @@
 }
 
 size_t GrDrawState::getVertexSize() const {
-    return vertex_size(fVertexAttribs.begin(), fVertexAttribs.count());
+    return vertex_size(fCommon.fVertexAttribs.begin(), fCommon.fVertexAttribs.count());
 }
 
-const GrAttribBindings GrDrawState::kAttribIndexMasks[kAttribIndexCount] = {
-    0,                            // position is not reflected in the bindings
-    kColor_AttribBindingsBit,
-    kCoverage_AttribBindingsBit,
-    kLocalCoords_AttribBindingsBit,
-};
-
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
-    GrAssert(count <= GrDrawState::kVertexAttribCnt);
-    fVertexAttribs.reset();
-    for (int index = 0; index < count; ++index) {
-        fVertexAttribs.push_back(attribs[index]);
+    GrAssert(count <= kMaxVertexAttribCnt);
+    fCommon.fVertexAttribs.reset(attribs, count);
+
+    // Set all the indices to -1
+    memset(fCommon.fFixedFunctionVertexAttribIndices,
+           0xff,
+           sizeof(fCommon.fFixedFunctionVertexAttribIndices));
+#if GR_DEBUG
+    uint32_t overlapCheck = 0;
+#endif
+    for (int i = 0; i < count; ++i) {
+        if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
+            // The fixed function attribs can only be specified once
+            GrAssert(-1 == fCommon.fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
+            GrAssert(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
+                     GrVertexAttribTypeVectorCount(attribs[i].fType));
+            fCommon.fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
+        }
+#if GR_DEBUG
+        size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
+        uint32_t mask = (1 << dwordCount)-1;
+        size_t offsetShift = attribs[i].fOffset >> 2;
+        GrAssert(!(overlapCheck & (mask << offsetShift)));
+        overlapCheck |= (mask << offsetShift);
+#endif
     }
+    // Positions must be specified.
+    GrAssert(-1 != fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrDrawState::setDefaultVertexAttribs() {
-    static const GrVertexAttrib kPositionAttrib = {kVec2f_GrVertexAttribType, 0};
-    fVertexAttribs.reset();
-    fVertexAttribs.push_back(kPositionAttrib);
-
-    fCommon.fAttribBindings = kDefault_AttribBindings;
-
-    fAttribIndices[kPosition_AttribIndex] = 0;
+    static const GrVertexAttrib kPositionAttrib =
+        {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
+    fCommon.fVertexAttribs.reset(&kPositionAttrib, 1);
+    // set all the fixed function indices to -1 except position.
+    memset(fCommon.fFixedFunctionVertexAttribIndices,
+           0xff,
+           sizeof(fCommon.fFixedFunctionVertexAttribIndices));
+    fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 bool GrDrawState::validateVertexAttribs() const {
-    // color and coverage can set indices beyond the standard count
-    static const int kMaxValidAttribIndex = kVertexAttribCnt+2;
-    int attributeTypes[kMaxValidAttribIndex];
-    for (int i = 0; i < kMaxValidAttribIndex; ++i) {
-        attributeTypes[i] = -1;
+    // check consistency of effects and attributes
+    GrSLType slTypes[kMaxVertexAttribCnt];
+    for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
+        slTypes[i] = static_cast<GrSLType>(-1);
     }
-
-    // sentinel to make sure effects don't try to use built-in attributes
-    static const int kBuiltInAttributeType = 10000;
-
-    // check our built-in indices
-    if (fAttribIndices[kPosition_AttribIndex] >= kVertexAttribCnt) {
-        return false;
-    }
-    attributeTypes[fAttribIndices[kPosition_AttribIndex]] = kBuiltInAttributeType;
-    for (int j = kColor_AttribIndex; j <= kCoverage_AttribIndex; ++j) {
-        if (fCommon.fAttribBindings & kAttribIndexMasks[j]) {
-            int attributeIndex = fAttribIndices[j];
-            if (attributeIndex >= kMaxValidAttribIndex) {
-                return false;
-            }
-            // they should not be shared at all
-            if (attributeTypes[attributeIndex] != -1) {
-                return false;
-            }
-            attributeTypes[attributeIndex] = kBuiltInAttributeType;
-        }
-    }
-    if (fCommon.fAttribBindings & kAttribIndexMasks[kLocalCoords_AttribIndex]) {
-        int attributeIndex = fAttribIndices[kLocalCoords_AttribIndex];
-        if (attributeIndex >= kVertexAttribCnt) {
-            return false;
-        }
-        // they should not be shared at all
-        if (attributeTypes[attributeIndex] != -1) {
-            return false;
-        }
-        attributeTypes[attributeIndex] = kBuiltInAttributeType;
-    }
-
-    // now those set by effects
     for (int s = 0; s < kNumStages; ++s) {
-        const GrEffectStage& stage = fStages[s];
-        const GrEffectRef* effect = stage.getEffect();
-        if (effect == NULL) {
-            continue;
-        }
+        if (this->isStageEnabled(s)) {
+            const GrEffectStage& stage = fStages[s];
+            const GrEffectRef* effect = stage.getEffect();
+            // make sure that any attribute indices have the correct binding type, that the attrib
+            // type and effect's shader lang type are compatible, and that attributes shared by
+            // multiple effects use the same shader lang type.
+            const int* attributeIndices = stage.getVertexAttribIndices();
+            int numAttributes = stage.getVertexAttribIndexCount();
+            for (int i = 0; i < numAttributes; ++i) {
+                int attribIndex = attributeIndices[i];
+                if (attribIndex >= fCommon.fVertexAttribs.count() ||
+                    kEffect_GrVertexAttribBinding != fCommon.fVertexAttribs[attribIndex].fBinding) {
+                    return false;
+                }
 
-        // make sure that the count in the stage and the effect matches
-        int numAttributes = stage.getVertexAttribIndexCount();
-        if (numAttributes != effect->get()->numVertexAttribs()) {
-            return false;
-        }
-
-        // make sure that any shared indices have the same type
-        const int* attributeIndices = stage.getVertexAttribIndices();
-        for (int i = 0; i < numAttributes; ++i) {
-            int attributeIndex = attributeIndices[i];
-            if (attributeIndex >= kVertexAttribCnt) {
-                return false;
+                GrSLType effectSLType = (*effect)->vertexAttribType(i);
+                GrVertexAttribType attribType = fCommon.fVertexAttribs[attribIndex].fType;
+                int slVecCount = GrSLTypeVectorCount(effectSLType);
+                int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
+                if (slVecCount != attribVecCount ||
+                    (-1 != slTypes[attribIndex] && slTypes[attribIndex] != effectSLType)) {
+                    return false;
+                }
+                slTypes[attribIndex] = effectSLType;
             }
-
-            GrSLType attributeType = effect->get()->vertexAttribType(i);
-            if (attributeTypes[attributeIndex] != -1 &&
-                attributeTypes[attributeIndex] != attributeType) {
-                return false;
-            }
-            attributeTypes[attributeIndex] = attributeType;
         }
     }
 
     return true;
 }
 
-
-void GrDrawState::VertexAttributesUnitTest() {
-    // not necessarily exhaustive
-    static bool run;
-    if (!run) {
-        run = true;
-
-        GrVertexAttribArray<6> attribs;
-        GrAssert(0 == vertex_size(attribs.begin(), attribs.count()));
-
-        GrVertexAttrib currAttrib = {kFloat_GrVertexAttribType, 0};
-        attribs.push_back(currAttrib);
-        GrAssert(sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
-        attribs[0].fType = kVec2f_GrVertexAttribType;
-        GrAssert(2*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
-        attribs[0].fType = kVec3f_GrVertexAttribType;
-        GrAssert(3*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
-        attribs[0].fType = kVec4f_GrVertexAttribType;
-        GrAssert(4*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
-        attribs[0].fType = kVec4ub_GrVertexAttribType;
-        GrAssert(4*sizeof(char) == vertex_size(attribs.begin(), attribs.count()));
-
-        currAttrib.set(kVec2f_GrVertexAttribType, attribs[0].fOffset + 4*sizeof(char));
-        attribs.push_back(currAttrib);
-        GrAssert(4*sizeof(char) + 2*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
-        currAttrib.set(kVec3f_GrVertexAttribType, attribs[1].fOffset + 2*sizeof(float));
-        attribs.push_back(currAttrib);
-        GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) ==
-                 vertex_size(attribs.begin(), attribs.count()));
-        currAttrib.set(kFloat_GrVertexAttribType, attribs[2].fOffset + 3*sizeof(float));
-        attribs.push_back(currAttrib);
-        GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) + sizeof(float) ==
-                 vertex_size(attribs.begin(), attribs.count()));
-        currAttrib.set(kVec4f_GrVertexAttribType, attribs[3].fOffset + sizeof(float));
-        attribs.push_back(currAttrib);
-        GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) + sizeof(float) + 4*sizeof(float) ==
-                 vertex_size(attribs.begin(), attribs.count()));
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrDrawState::srcAlphaWillBeOne(GrAttribBindings bindings) const {
-
+bool GrDrawState::srcAlphaWillBeOne() const {
     uint32_t validComponentFlags;
     GrColor color;
     // Check if per-vertex or constant color may have partial alpha
-    if (bindings & kColor_AttribBindingsBit) {
+    if (this->hasColorVertexAttribute()) {
         validComponentFlags = 0;
         color = 0; // not strictly necessary but we get false alarms from tools about uninit.
     } else {
@@ -278,7 +209,7 @@
     return (kA_GrColorComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
 }
 
-bool GrDrawState::hasSolidCoverage(GrAttribBindings bindings) const {
+bool GrDrawState::hasSolidCoverage() const {
     // If we're drawing coverage directly then coverage is effectively treated as color.
     if (this->isCoverageDrawing()) {
         return true;
@@ -287,7 +218,7 @@
     GrColor coverage;
     uint32_t validComponentFlags;
     // Initialize to an unknown starting coverage if per-vertex coverage is specified.
-    if (bindings & kCoverage_AttribBindingsBit) {
+    if (this->hasCoverageVertexAttribute()) {
         validComponentFlags = 0;
     } else {
         coverage = fCommon.fCoverage;
@@ -329,7 +260,6 @@
 GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
                                                      GrBlendCoeff* srcCoeff,
                                                      GrBlendCoeff* dstCoeff) const {
-    GrAttribBindings bindings = this->getAttribBindings();
 
     GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
     if (NULL == srcCoeff) {
@@ -347,14 +277,14 @@
         *dstCoeff = kOne_GrBlendCoeff;
     }
 
-    bool srcAIsOne = this->srcAlphaWillBeOne(bindings);
+    bool srcAIsOne = this->srcAlphaWillBeOne();
     bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
                          (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
     bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
                          (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
 
     bool covIsZero = !this->isCoverageDrawing() &&
-                     !(bindings & GrDrawState::kCoverage_AttribBindingsBit) &&
+                     !this->hasCoverageVertexAttribute() &&
                      0 == this->getCoverage();
     // When coeffs are (0,1) there is no reason to draw at all, unless
     // stenciling is enabled. Having color writes disabled is effectively
@@ -371,10 +301,8 @@
     // check for coverage due to constant coverage, per-vertex coverage, or coverage stage
     bool hasCoverage = forceCoverage ||
                        0xffffffff != this->getCoverage() ||
-                       (bindings & GrDrawState::kCoverage_AttribBindingsBit);
-    for (int s = this->getFirstCoverageStage();
-         !hasCoverage && s < GrDrawState::kNumStages;
-         ++s) {
+                       this->hasCoverageVertexAttribute();
+    for (int s = this->getFirstCoverageStage(); !hasCoverage && s < GrDrawState::kNumStages; ++s) {
         if (this->isStageEnabled(s)) {
             hasCoverage = true;
         }
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index d16efa8..2f96c15 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -23,11 +23,6 @@
 #include "SkMatrix.h"
 #include "SkXfermode.h"
 
-/**
- * Type used to describe how attributes bind to program usage
- */
-typedef int GrAttribBindings;
-
 class GrDrawState : public GrRefCnt {
 public:
     SK_DECLARE_INST_COUNT(GrDrawState)
@@ -45,8 +40,8 @@
      * coverage rather than as input to the src/dst color blend step.
      *
      * The input color to the first enabled color-stage is either the constant color or interpolated
-     * per-vertex colors, depending upon GrAttribBindings. The input to the first coverage stage is
-     * either a constant coverage (usually full-coverage) or interpolated per-vertex coverage.
+     * per-vertex colors. The input to the first coverage stage is either a constant coverage
+     * (usually full-coverage) or interpolated per-vertex coverage.
      *
      * See the documentation of kCoverageDrawing_StateBit for information about disabling the
      * the color / coverage distinction.
@@ -62,9 +57,6 @@
     };
 
     GrDrawState() {
-#if GR_DEBUG
-        VertexAttributesUnitTest();
-#endif
         this->reset();
     }
 
@@ -115,53 +107,72 @@
     ////
 
     enum {
-        kVertexAttribCnt = 6,
+        kMaxVertexAttribCnt = kLast_GrVertexAttribBinding + 4,
     };
 
    /**
-     * The format of vertices is represented as an array of vertex attribute
-     * pair, with each pair representing the type of the attribute and the
-     * offset in the vertex structure (see GrVertexAttrib, above).
+     * The format of vertices is represented as an array of GrVertexAttribs, with each representing
+     * the type of the attribute, its offset, and semantic binding (see GrVertexAttrib in
+     * GrTypesPriv.h).
      *
-     * This will only set up the vertex geometry. To bind the attributes in
-     * the shaders, attribute indices and attribute bindings need to be set
-     * as well.
+     * The mapping of attributes with kEffect bindings to GrEffect inputs is specified when
+     * setEffect is called.
      */
 
     /**
      *  Sets vertex attributes for next draw.
      *
      *  @param attribs    the array of vertex attributes to set.
-     *  @param count      the number of attributes being set.
-     *                    limited to a count of kVertexAttribCnt.
+     *  @param count      the number of attributes being set, limited to kMaxVertexAttribCnt.
      */
     void setVertexAttribs(const GrVertexAttrib attribs[], int count);
 
-    const GrVertexAttrib* getVertexAttribs() const { return fVertexAttribs.begin(); }
-    int getVertexAttribCount() const { return fVertexAttribs.count(); }
+    const GrVertexAttrib* getVertexAttribs() const { return fCommon.fVertexAttribs.begin(); }
+    int getVertexAttribCount() const { return fCommon.fVertexAttribs.count(); }
 
     size_t getVertexSize() const;
 
     /**
-     *  Sets default vertex attributes for next draw.
-     *
-     *  This will also set default vertex attribute indices and bindings
+     *  Sets default vertex attributes for next draw. The default is a single attribute:
+     *  {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribType}
      */
     void setDefaultVertexAttribs();
 
+    /**
+     * Getters for index into getVertexAttribs() for particular bindings. -1 is returned if the
+     * binding does not appear in the current attribs. These bindings should appear only once in
+     * the attrib array.
+     */
+
+    int positionAttributeIndex() const {
+        return fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding];
+    }
+    int localCoordAttributeIndex() const {
+        return fCommon.fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding];
+    }
+    int colorVertexAttributeIndex() const {
+        return fCommon.fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding];
+    }
+    int coverageVertexAttributeIndex() const {
+        return fCommon.fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding];
+    }
+
+    bool hasLocalCoordAttribute() const {
+        return -1 != fCommon.fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding];
+    }
+    bool hasColorVertexAttribute() const {
+        return -1 != fCommon.fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding];
+    }
+    bool hasCoverageVertexAttribute() const {
+        return -1 != fCommon.fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding];
+    }
+
     bool validateVertexAttribs() const;
 
-    ////////////////////////////////////////////////////////////////////////////
-    // Helpers for picking apart vertex attributes
-
-    // helper array to let us check the expected so we know what bound attrib indices
-    // we care about
-    static const size_t kVertexAttribSizes[kGrVertexAttribTypeCount];
-
     /**
-     * Accessing positions, texture coords, or colors, of a vertex within an
-     * array is a hassle involving casts and simple math. These helpers exist
-     * to keep GrDrawTarget clients' code a bit nicer looking.
+     * Accessing positions, local coords, or colors, of a vertex within an array is a hassle
+     * involving casts and simple math. These helpers exist to keep GrDrawTarget clients' code a bit
+     * nicer looking.
      */
 
     /**
@@ -218,110 +229,15 @@
 
     /// @}
 
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Attribute Bindings
-    ////
-
-    /**
-     * The vertex data used by the current program is represented as a bitfield
-     * of flags. Programs always use positions and may also use texture
-     * coordinates, per-vertex colors, per-vertex coverage and edge data. The
-     * local coords accessible by effects may either come from positions or
-     * be specified explicitly.
-     */
-
-    /**
-     * Additional Bits that can be specified in GrAttribBindings.
-     */
-    enum AttribBindingsBits {
-        /** explicit local coords are provided (instead of using pre-view-matrix positions) */
-        kLocalCoords_AttribBindingsBit        = 0x1,
-        /* program uses colors (GrColor) */
-        kColor_AttribBindingsBit              = 0x2,
-        /* program uses coverage (GrColor)
-         */
-        kCoverage_AttribBindingsBit           = 0x4,
-        // for below assert
-        kDummyAttribBindingsBit,
-        kHighAttribBindingsBit = kDummyAttribBindingsBit - 1
-    };
-    // make sure we haven't exceeded the number of bits in GrAttribBindings.
-    GR_STATIC_ASSERT(kHighAttribBindingsBit < ((uint64_t)1 << 8*sizeof(GrAttribBindings)));
-
-    enum AttribBindings {
-        kDefault_AttribBindings = 0
-    };
-
-    /**
-     *  Sets attribute bindings for next draw.
-     *
-     *  @param bindings    the attribute bindings to set.
-     */
-    void setAttribBindings(GrAttribBindings bindings) { fCommon.fAttribBindings = bindings; }
-
-    GrAttribBindings getAttribBindings() const { return fCommon.fAttribBindings; }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // Helpers for picking apart attribute bindings
-
     /**
      * Determines whether src alpha is guaranteed to be one for all src pixels
      */
-    bool srcAlphaWillBeOne(GrAttribBindings) const;
+    bool srcAlphaWillBeOne() const;
 
     /**
      * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw.
      */
-    bool hasSolidCoverage(GrAttribBindings) const;
-
-    static void VertexAttributesUnitTest();
-
-    /// @}
-
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Vertex Attribute Indices
-    ////
-
-    /**
-     * Vertex attribute indices map the data set in the vertex attribute array
-     * to the bindings specified in the attribute bindings. Each binding type
-     * has an associated index in the attribute array. This index is used to
-     * look up the vertex attribute data from the array, and potentially as the
-     * attribute index if we're binding attributes in GL.
-     *
-     * Indices which do not have active attribute bindings will be ignored.
-     */
-
-    enum AttribIndex {
-        kPosition_AttribIndex = 0,
-        kColor_AttribIndex,
-        kCoverage_AttribIndex,
-        kLocalCoords_AttribIndex,
-
-        kLast_AttribIndex = kLocalCoords_AttribIndex
-    };
-    static const int kAttribIndexCount = kLast_AttribIndex + 1;
-
-    // these are used when vertex color and coverage isn't set
-    enum {
-        kColorOverrideAttribIndexValue = GrDrawState::kVertexAttribCnt,
-        kCoverageOverrideAttribIndexValue = GrDrawState::kVertexAttribCnt+1,
-    };
-
-    ////////////////////////////////////////////////////////////////////////////
-    // Helpers to set attribute indices. These should match the index in the
-    // current attribute index array.
-
-    /**
-     *  Sets index for next draw. This is used to look up the offset
-     *  from the current vertex attribute array and to bind the attributes.
-     *
-     *  @param index      the attribute index we're setting
-     *  @param value      the value of the index
-     */
-    void setAttribIndex(AttribIndex index, int value) { fAttribIndices[index] = value; }
-
-    int getAttribIndex(AttribIndex index) const       { return fAttribIndices[index]; }
+    bool hasSolidCoverage() const;
 
     /// @}
 
@@ -1068,15 +984,6 @@
         if (fRenderTarget.get() != s.fRenderTarget.get() || fCommon != s.fCommon) {
             return false;
         }
-        if (fVertexAttribs != s.fVertexAttribs) {
-            return false;
-        }
-        for (int i = 0; i < kAttribIndexCount; ++i) {
-            if ((i == kPosition_AttribIndex || s.fCommon.fAttribBindings & (1 << i)) &&
-                fAttribIndices[i] != s.fAttribIndices[i]) {
-                return false;
-            }
-        }
         for (int i = 0; i < kNumStages; i++) {
             bool enabled = this->isStageEnabled(i);
             if (enabled != s.isStageEnabled(i)) {
@@ -1093,10 +1000,6 @@
     GrDrawState& operator= (const GrDrawState& s) {
         this->setRenderTarget(s.fRenderTarget.get());
         fCommon = s.fCommon;
-        fVertexAttribs = s.fVertexAttribs;
-        for (int i = 0; i < kAttribIndexCount; i++) {
-            fAttribIndices[i] = s.fAttribIndices[i];
-        }
         for (int i = 0; i < kNumStages; i++) {
             if (s.isStageEnabled(i)) {
                 this->fStages[i] = s.fStages[i];
@@ -1110,33 +1013,44 @@
     /** Fields that are identical in GrDrawState and GrDrawState::DeferredState. */
     struct CommonState {
         // These fields are roughly sorted by decreasing likelihood of being different in op==
-        GrColor                         fColor;
-        GrAttribBindings                fAttribBindings;
-        SkMatrix                        fViewMatrix;
-        GrBlendCoeff                    fSrcBlend;
-        GrBlendCoeff                    fDstBlend;
-        GrColor                         fBlendConstant;
-        uint32_t                        fFlagBits;
-        GrStencilSettings               fStencilSettings;
-        int                             fFirstCoverageStage;
-        GrColor                         fCoverage;
-        SkXfermode::Mode                fColorFilterMode;
-        GrColor                         fColorFilterColor;
-        DrawFace                        fDrawFace;
+        GrColor                                  fColor;
+        SkMatrix                                 fViewMatrix;
+        GrBlendCoeff                             fSrcBlend;
+        GrBlendCoeff                             fDstBlend;
+        GrColor                                  fBlendConstant;
+        uint32_t                                 fFlagBits;
+        GrVertexAttribArray<kMaxVertexAttribCnt> fVertexAttribs;
+        GrStencilSettings                        fStencilSettings;
+        int                                      fFirstCoverageStage;
+        GrColor                                  fCoverage;
+        SkXfermode::Mode                         fColorFilterMode;
+        GrColor                                  fColorFilterColor;
+        DrawFace                                 fDrawFace;
+
+        // This is simply a different representation of info in fVertexAttribs and thus does
+        // not need to be compared in op==.
+        int fFixedFunctionVertexAttribIndices[kGrFixedFunctionVertexAttribBindingCnt];
+
+        GR_STATIC_ASSERT(kGrVertexAttribBindingCnt <= 8*sizeof(uint32_t));
+
         bool operator== (const CommonState& other) const {
-            return fColor == other.fColor &&
-                   fAttribBindings == other.fAttribBindings &&
-                   fViewMatrix.cheapEqualTo(other.fViewMatrix) &&
-                   fSrcBlend == other.fSrcBlend &&
-                   fDstBlend == other.fDstBlend &&
-                   fBlendConstant == other.fBlendConstant &&
-                   fFlagBits == other.fFlagBits &&
-                   fStencilSettings == other.fStencilSettings &&
-                   fFirstCoverageStage == other.fFirstCoverageStage &&
-                   fCoverage == other.fCoverage &&
-                   fColorFilterMode == other.fColorFilterMode &&
-                   fColorFilterColor == other.fColorFilterColor &&
-                   fDrawFace == other.fDrawFace;
+            bool result = fColor == other.fColor &&
+                          fViewMatrix.cheapEqualTo(other.fViewMatrix) &&
+                          fSrcBlend == other.fSrcBlend &&
+                          fDstBlend == other.fDstBlend &&
+                          fBlendConstant == other.fBlendConstant &&
+                          fFlagBits == other.fFlagBits &&
+                          fVertexAttribs == other.fVertexAttribs &&
+                          fStencilSettings == other.fStencilSettings &&
+                          fFirstCoverageStage == other.fFirstCoverageStage &&
+                          fCoverage == other.fCoverage &&
+                          fColorFilterMode == other.fColorFilterMode &&
+                          fColorFilterColor == other.fColorFilterColor &&
+                          fDrawFace == other.fDrawFace;
+            GrAssert(!result || 0 == memcmp(fFixedFunctionVertexAttribIndices,
+                                            other.fFixedFunctionVertexAttribIndices,
+                                            sizeof(fFixedFunctionVertexAttribIndices)));
+            return result;
         }
         bool operator!= (const CommonState& other) const { return !(*this == other); }
     };
@@ -1169,10 +1083,6 @@
             // TODO: Here we will copy the GrRenderTarget pointer without taking a ref.
             fRenderTarget = drawState.fRenderTarget.get();
             SkSafeRef(fRenderTarget);
-            fVertexAttribs = drawState.fVertexAttribs;
-            for (int i = 0; i < kAttribIndexCount; i++) {
-                fAttribIndices[i] = drawState.fAttribIndices[i];
-            }
             // Here we ref the effects directly rather than the effect-refs. TODO: When the effect-
             // ref gets fully unref'ed it will cause the underlying effect to unref its resources
             // and recycle them to the cache (if no one else is holding a ref to the resources).
@@ -1186,10 +1096,6 @@
             GrAssert(fInitialized);
             drawState->fCommon = fCommon;
             drawState->setRenderTarget(fRenderTarget);
-            drawState->fVertexAttribs = fVertexAttribs;
-            for (int i = 0; i < kAttribIndexCount; i++) {
-                drawState->fAttribIndices[i] = fAttribIndices[i];
-            }
             for (int i = 0; i < kNumStages; ++i) {
                 fStages[i].restoreTo(&drawState->fStages[i]);
             }
@@ -1199,16 +1105,6 @@
             if (fRenderTarget != state.fRenderTarget.get() || fCommon != state.fCommon) {
                 return false;
             }
-            for (int i = 0; i < kAttribIndexCount; ++i) {
-                if ((i == kPosition_AttribIndex ||
-                     state.fCommon.fAttribBindings & kAttribIndexMasks[i]) &&
-                    fAttribIndices[i] != state.fAttribIndices[i]) {
-                    return false;
-                }
-            }
-            if (fVertexAttribs != state.fVertexAttribs) {
-                return false;
-            }
             for (int i = 0; i < kNumStages; ++i) {
                 if (!fStages[i].isEqual(state.fStages[i])) {
                     return false;
@@ -1220,22 +1116,15 @@
     private:
         GrRenderTarget*                       fRenderTarget;
         CommonState                           fCommon;
-        int                                   fAttribIndices[kAttribIndexCount];
-        GrVertexAttribArray<kVertexAttribCnt> fVertexAttribs;
         GrEffectStage::DeferredStage          fStages[kNumStages];
 
         GR_DEBUGCODE(bool fInitialized;)
     };
 
 private:
-    // helper array to let us check the current bindings so we know what bound attrib indices
-    // we care about
-    static const GrAttribBindings kAttribIndexMasks[kAttribIndexCount];
 
     SkAutoTUnref<GrRenderTarget>           fRenderTarget;
     CommonState                            fCommon;
-    int                                    fAttribIndices[kAttribIndexCount];
-    GrVertexAttribArray<kVertexAttribCnt>  fVertexAttribs;
     GrEffectStage                          fStages[kNumStages];
 
     typedef GrRefCnt INHERITED;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index bc7d39e..ea77871 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -615,18 +615,15 @@
                             const SkMatrix* matrix,
                             const GrRect* localRect,
                             const SkMatrix* localMatrix) {
-    GrAttribBindings bindings = 0;
     // position + (optional) texture coord
     static const GrVertexAttrib kAttribs[] = {
-        {kVec2f_GrVertexAttribType, 0},
-        {kVec2f_GrVertexAttribType, sizeof(GrPoint)}
+        {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
+        {kVec2f_GrVertexAttribType, sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding}
     };
     int attribCount = 1;
 
     if (NULL != localRect) {
-        bindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
         attribCount = 2;
-        this->drawState()->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, 1);
     }
 
     GrDrawState::AutoViewMatrixRestore avmr;
@@ -635,8 +632,6 @@
     }
 
     this->drawState()->setVertexAttribs(kAttribs, attribCount);
-    this->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-    this->drawState()->setAttribBindings(bindings);
     AutoReleaseGeometry geo(this, 4, 0);
     if (!geo.succeeded()) {
         GrPrintf("Failed to get space for vertices!\n");
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index a090dcf..8074f26 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -77,22 +77,21 @@
                                    const SkMatrix* matrix,
                                    const GrRect* localRect,
                                    const SkMatrix* localMatrix) {
-
-    GrAttribBindings bindings = GrDrawState::kDefault_AttribBindings;
     GrDrawState::AutoColorRestore acr;
 
     GrDrawState* drawState = this->drawState();
 
     GrColor color = drawState->getColor();
     GrVertexAttribArray<3> attribs;
-    size_t currentOffset = 0;
-    int colorOffset = -1, localOffset = -1;
 
     // set position attrib
-    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, attribs.count());
-    GrVertexAttrib currAttrib = {kVec2f_GrVertexAttribType, currentOffset};
-    attribs.push_back(currAttrib);
-    currentOffset += sizeof(GrPoint);
+    static const GrVertexAttrib kPosAttrib =
+        {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
+    attribs.push_back(kPosAttrib);
+
+    size_t currentOffset = sizeof(GrPoint);
+    int colorOffset = -1;
+    int localOffset = -1;
 
     // Using per-vertex colors allows batching across colors. (A lot of rects in a row differing
     // only in color is a common occurrence in tables). However, having per-vertex colors disables
@@ -100,13 +99,11 @@
     // optimizations help determine whether coverage and color can be blended correctly when
     // dual-source blending isn't available. This comes into play when there is coverage. If colors
     // were a stage it could take a hint that every vertex's color will be opaque.
-    if (this->caps()->dualSourceBlendingSupport() ||
-        drawState->hasSolidCoverage(drawState->getAttribBindings())) {
-        bindings |= GrDrawState::kColor_AttribBindingsBit;
-        drawState->setAttribIndex(GrDrawState::kColor_AttribIndex, attribs.count());
-        currAttrib.set(kVec4ub_GrVertexAttribType, currentOffset);
-        attribs.push_back(currAttrib);
+    if (this->caps()->dualSourceBlendingSupport() || drawState->hasSolidCoverage()) {
         colorOffset = currentOffset;
+        GrVertexAttrib colorAttrib =
+            {kVec4ub_GrVertexAttribType, colorOffset, kColor_GrVertexAttribBinding};
+        attribs.push_back(colorAttrib);
         currentOffset += sizeof(GrColor);
         // We set the draw state's color to white here. This is done so that any batching performed
         // in our subclass's onDraw() won't get a false from GrDrawState::op== due to a color
@@ -116,16 +113,14 @@
     }
 
     if (NULL != localRect) {
-        bindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
-        drawState->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, attribs.count());
-        currAttrib.set(kVec2f_GrVertexAttribType, currentOffset);
-        attribs.push_back(currAttrib);
         localOffset = currentOffset;
+        GrVertexAttrib localCoordAttrib =
+            {kVec2f_GrVertexAttribType, localOffset, kLocalCoord_GrVertexAttribBinding};
+        attribs.push_back(localCoordAttrib);
         currentOffset += sizeof(GrPoint);
     }
 
     drawState->setVertexAttribs(attribs.begin(), attribs.count());
-    drawState->setAttribBindings(bindings);
     AutoReleaseGeometry geo(this, 4, 0);
     if (!geo.succeeded()) {
         GrPrintf("Failed to get space for vertices!\n");
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 8bc0428..2955c75 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -85,11 +85,10 @@
 
     // position + edge
     static const GrVertexAttrib kVertexAttribs[] = {
-        {kVec2f_GrVertexAttribType, 0},
-        {kVec4f_GrVertexAttribType, sizeof(GrPoint)}
+        {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
+        {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
     };
     drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
-    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
     GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
@@ -108,7 +107,6 @@
         // (kPathMaskStage in GrSWMaskHelper)
         kEdgeEffectStage = GrPaint::kTotalStages,
     };
-    drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
 
     GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked);
     static const int kCircleEdgeAttrIndex = 1;
@@ -185,12 +183,11 @@
 
     // position + edge
     static const GrVertexAttrib kVertexAttribs[] = {
-        {kVec2f_GrVertexAttribType, 0},
-        {kVec2f_GrVertexAttribType, sizeof(GrPoint)},
-        {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint)}
+        {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
+        {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding},
+        {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding}
     };
     drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
-    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
     GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
@@ -209,7 +206,6 @@
         // (kPathMaskStage in GrSWMaskHelper)
         kEdgeEffectStage = GrPaint::kTotalStages,
     };
-    drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
 
     GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked);
     static const int kEllipseCenterAttrIndex = 1;
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index ab2bc42..58b3e92 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -194,10 +194,9 @@
     if (NULL == fVertices) {
         // position + texture coord
         static const GrVertexAttrib kVertexAttribs[] = {
-            {kVec2f_GrVertexAttribType, 0},
-            {kVec2f_GrVertexAttribType, sizeof(GrPoint)}
+            {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
+            {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
         };
-        static const GrAttribBindings kAttribBindings = 0;
 
        // If we need to reserve vertices allow the draw target to suggest
         // a number of verts to reserve and whether to perform a flush.
@@ -215,8 +214,6 @@
             fDrawTarget = fContext->getTextTarget(fPaint);
             fDrawTarget->drawState()->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
         }
-        fDrawTarget->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-        fDrawTarget->drawState()->setAttribBindings(kAttribBindings);
         fMaxVertices = kDefaultRequestedVerts;
         // ignore return, no point in flushing again.
         fDrawTarget->geometryHints(&fMaxVertices, NULL);
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index cbaa765..51cae5c 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -705,14 +705,17 @@
     GL_CALL(BindAttribLocation(fProgramID,
                                fDesc.fPositionAttributeIndex,
                                builder.positionAttribute().c_str()));
-    GL_CALL(BindAttribLocation(fProgramID, fDesc.fColorAttributeIndex, COL_ATTR_NAME));
-    GL_CALL(BindAttribLocation(fProgramID, fDesc.fCoverageAttributeIndex, COV_ATTR_NAME));
-
-    if (fDesc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
+    if (-1 != fDesc.fLocalCoordAttributeIndex) {
         GL_CALL(BindAttribLocation(fProgramID,
-                                   fDesc.fLocalCoordsAttributeIndex,
+                                   fDesc.fLocalCoordAttributeIndex,
                                    builder.localCoordsAttribute().c_str()));
     }
+    if (-1 != fDesc.fColorAttributeIndex) {
+        GL_CALL(BindAttribLocation(fProgramID, fDesc.fColorAttributeIndex, COL_ATTR_NAME));
+    }
+    if (-1 != fDesc.fCoverageAttributeIndex) {
+        GL_CALL(BindAttribLocation(fProgramID, fDesc.fCoverageAttributeIndex, COV_ATTR_NAME));
+    }
 
     const GrGLShaderBuilder::AttributePair* attribEnd = builder.getEffectAttributes().end();
     for (const GrGLShaderBuilder::AttributePair* attrib = builder.getEffectAttributes().begin();
@@ -826,8 +829,7 @@
             const GrEffectStage& stage = drawState.getStage(s);
             GrAssert(NULL != stage.getEffect());
 
-            bool explicitLocalCoords =
-                (fDesc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit);
+            bool explicitLocalCoords = -1 != fDesc.fLocalCoordAttributeIndex;
             GrDrawEffect drawEffect(stage, explicitLocalCoords);
             fEffects[s]->setData(fUniformManager, drawEffect);
             int numSamplers = fUniformHandles.fEffectSamplerUnis[s].count();
@@ -847,15 +849,18 @@
 void GrGLProgram::setColor(const GrDrawState& drawState,
                            GrColor color,
                            SharedGLState* sharedState) {
-    if (!(drawState.getAttribBindings() & GrDrawState::kColor_AttribBindingsBit)) {
+    if (!drawState.hasColorVertexAttribute()) {
         switch (fDesc.fColorInput) {
             case GrGLProgramDesc::kAttribute_ColorInput:
-                if (sharedState->fConstAttribColor != color) {
+                GrAssert(-1 != fDesc.fColorAttributeIndex);
+                if (sharedState->fConstAttribColor != color ||
+                    sharedState->fConstAttribColorIndex != fDesc.fColorAttributeIndex) {
                     // OpenGL ES only supports the float varieties of glVertexAttrib
                     GrGLfloat c[4];
                     GrColorToRGBAFloat(color, c);
                     GL_CALL(VertexAttrib4fv(fDesc.fColorAttributeIndex, c));
                     sharedState->fConstAttribColor = color;
+                    sharedState->fConstAttribColorIndex = fDesc.fColorAttributeIndex;
                 }
                 break;
             case GrGLProgramDesc::kUniform_ColorInput:
@@ -868,28 +873,34 @@
                     fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c);
                     fColor = color;
                 }
+                sharedState->fConstAttribColorIndex = -1;
                 break;
             case GrGLProgramDesc::kSolidWhite_ColorInput:
             case GrGLProgramDesc::kTransBlack_ColorInput:
+                sharedState->fConstAttribColorIndex = -1;
                 break;
             default:
                 GrCrash("Unknown color type.");
         }
+    } else {
+        sharedState->fConstAttribColorIndex = -1;
     }
 }
 
 void GrGLProgram::setCoverage(const GrDrawState& drawState,
                               GrColor coverage,
                               SharedGLState* sharedState) {
-    if (!(drawState.getAttribBindings() & GrDrawState::kCoverage_AttribBindingsBit)) {
+    if (!drawState.hasCoverageVertexAttribute()) {
         switch (fDesc.fCoverageInput) {
             case GrGLProgramDesc::kAttribute_ColorInput:
-                if (sharedState->fConstAttribCoverage != coverage) {
+                if (sharedState->fConstAttribCoverage != coverage ||
+                    sharedState->fConstAttribCoverageIndex != fDesc.fCoverageAttributeIndex) {
                     // OpenGL ES only supports the float varieties of  glVertexAttrib
                     GrGLfloat c[4];
                     GrColorToRGBAFloat(coverage, c);
                     GL_CALL(VertexAttrib4fv(fDesc.fCoverageAttributeIndex, c));
                     sharedState->fConstAttribCoverage = coverage;
+                    sharedState->fConstAttribCoverageIndex = fDesc.fCoverageAttributeIndex;
                 }
                 break;
             case GrGLProgramDesc::kUniform_ColorInput:
@@ -902,13 +913,17 @@
                     fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c);
                     fCoverage = coverage;
                 }
+                sharedState->fConstAttribCoverageIndex = -1;
                 break;
             case GrGLProgramDesc::kSolidWhite_ColorInput:
             case GrGLProgramDesc::kTransBlack_ColorInput:
+                sharedState->fConstAttribCoverageIndex = -1;
                 break;
             default:
                 GrCrash("Unknown coverage type.");
         }
+    } else {
+        sharedState->fConstAttribCoverageIndex = -1;
     }
 }
 
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 27b6f80..4b5dfea 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -60,18 +60,23 @@
     GrGLuint programID() const { return fProgramID; }
 
     /**
-     * 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.
+     * Some GL state that is relevant to programs is not stored per-program. In particular color
+     * and coverage attributes can be global state. This struct is read and updated by 
+     * GrGLProgram::setColor and GrGLProgram::setCoverage to allow us to avoid setting this state 
+     * redundantly.
      */
     struct SharedGLState {
         GrColor fConstAttribColor;
+        int     fConstAttribColorIndex;
         GrColor fConstAttribCoverage;
+        int     fConstAttribCoverageIndex;
 
         SharedGLState() { this->invalidate(); }
         void invalidate() {
             fConstAttribColor = GrColor_ILLEGAL;
+            fConstAttribColorIndex = -1;
             fConstAttribCoverage = GrColor_ILLEGAL;
+            fConstAttribCoverageIndex = -1;
         }
     };
 
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 6ed5473..73846b8 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -34,49 +34,42 @@
     // bindings 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->fAttribBindings = drawState.getAttribBindings();
 
     desc->fEmitsPointSize = isPoints;
 
-    bool requiresAttributeColors =
-        !skipColor && SkToBool(desc->fAttribBindings & GrDrawState::kColor_AttribBindingsBit);
-    bool requiresAttributeCoverage =
-        !skipCoverage && SkToBool(desc->fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit);
+    bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
+    bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
+    // we only need the local coords if we're actually going to generate effect code
+    bool requiresLocalCoordAttrib = !(skipCoverage  && skipColor) &&
+                                    drawState.hasLocalCoordAttribute();
 
     // fColorInput/fCoverageInput records how colors are specified for the program so we strip the
     // bits from the bindings to avoid false negatives when searching for an existing program in the
     // cache.
-    desc->fAttribBindings &=
-        ~(GrDrawState::kColor_AttribBindingsBit | GrDrawState::kCoverage_AttribBindingsBit);
 
     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->fAttribBindings &= ~(GrDrawState::kCoverage_AttribBindingsBit);
-    }
 
     bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
     bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
-                             (!requiresAttributeColors && 0xffffffff == drawState.getColor());
+                             (!requiresColorAttrib && 0xffffffff == drawState.getColor());
     if (colorIsTransBlack) {
         desc->fColorInput = kTransBlack_ColorInput;
     } else if (colorIsSolidWhite) {
         desc->fColorInput = kSolidWhite_ColorInput;
-    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
+    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
         desc->fColorInput = kUniform_ColorInput;
     } else {
         desc->fColorInput = kAttribute_ColorInput;
     }
 
-    bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage();
+    bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
 
     if (skipCoverage) {
         desc->fCoverageInput = kTransBlack_ColorInput;
     } else if (covIsSolidWhite) {
         desc->fCoverageInput = kSolidWhite_ColorInput;
-    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
+    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
         desc->fCoverageInput = kUniform_ColorInput;
     } else {
         desc->fCoverageInput = kAttribute_ColorInput;
@@ -92,9 +85,7 @@
             lastEnabledStage = s;
             const GrEffectRef& effect = *drawState.getStage(s).getEffect();
             const GrBackendEffectFactory& factory = effect->getFactory();
-            bool explicitLocalCoords = (drawState.getAttribBindings() &
-                                        GrDrawState::kLocalCoords_AttribBindingsBit);
-            GrDrawEffect drawEffect(drawState.getStage(s), explicitLocalCoords);
+            GrDrawEffect drawEffect(drawState.getStage(s), requiresLocalCoordAttrib);
             desc->fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
             if (effect->willReadDst()) {
                 readsDst = true;
@@ -139,7 +130,7 @@
             firstCoverageStage = drawState.getFirstCoverageStage();
             hasCoverage = true;
         } else {
-            hasCoverage = requiresAttributeCoverage;
+            hasCoverage = requiresCoverageAttrib;
         }
     }
 
@@ -174,38 +165,27 @@
         }
     }
 
-    desc->fPositionAttributeIndex = drawState.getAttribIndex(GrDrawState::kPosition_AttribIndex);
-    if (requiresAttributeColors) {
-        desc->fColorAttributeIndex = drawState.getAttribIndex(GrDrawState::kColor_AttribIndex);
+    desc->fPositionAttributeIndex = drawState.positionAttributeIndex();
+    desc->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
+
+    // For constant color and coverage we need an attribute with an index beyond those already set
+    int availableAttributeIndex = drawState.getVertexAttribCount();
+    if (requiresColorAttrib) {
+        desc->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
+    } else if (GrGLProgramDesc::kAttribute_ColorInput == desc->fColorInput) {
+        GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
+        desc->fColorAttributeIndex = availableAttributeIndex;
+        availableAttributeIndex++;
     } else {
-        desc->fColorAttributeIndex = GrDrawState::kColorOverrideAttribIndexValue;
-    }
-    if (requiresAttributeCoverage) {
-        desc->fCoverageAttributeIndex = drawState.getAttribIndex(GrDrawState::kCoverage_AttribIndex);
-    } else {
-        desc->fCoverageAttributeIndex = GrDrawState::kCoverageOverrideAttribIndexValue;
-    }
-    if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
-        desc->fLocalCoordsAttributeIndex = drawState.getAttribIndex(GrDrawState::kLocalCoords_AttribIndex);
+        desc->fColorAttributeIndex = -1;
     }
 
-#if GR_DEBUG
-    // Verify valid vertex attribute state. These assertions should probably be done somewhere
-    // higher up the callstack
-    const GrVertexAttrib* vertexAttribs = drawState.getVertexAttribs();
-    GrAssert(desc->fPositionAttributeIndex < GrDrawState::kVertexAttribCnt);
-    GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fPositionAttributeIndex].fType).fCount == 2);
-    if (requiresAttributeColors) {
-        GrAssert(desc->fColorAttributeIndex < GrDrawState::kVertexAttribCnt);
-        GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fColorAttributeIndex].fType).fCount == 4);
+    if (requiresCoverageAttrib) {
+        desc->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
+    } else if (GrGLProgramDesc::kAttribute_ColorInput == desc->fCoverageInput) {
+        GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
+        desc->fCoverageAttributeIndex = availableAttributeIndex;
+    } else {
+        desc->fCoverageAttributeIndex = -1;
     }
-    if (requiresAttributeCoverage) {
-        GrAssert(desc->fCoverageAttributeIndex < GrDrawState::kVertexAttribCnt);
-        GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fCoverageAttributeIndex].fType).fCount == 4);
-    }
-    if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
-        GrAssert(desc->fLocalCoordsAttributeIndex < GrDrawState::kVertexAttribCnt);
-        GrAssert(GrGLAttribTypeToLayout(vertexAttribs[desc->fLocalCoordsAttributeIndex].fType).fCount == 2);
-    }
-#endif
 }
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index df5729f..a77ed71 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -39,7 +39,8 @@
     void setRandom(SkMWCRandom*,
                    const GrGpuGL* gpu,
                    const GrTexture* dummyDstTexture,
-                   const GrEffectStage stages[GrDrawState::kNumStages]);
+                   const GrEffectStage stages[GrDrawState::kNumStages],
+                   int currAttribIndex);
 
     /**
      * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the
@@ -76,35 +77,34 @@
         kDualSrcOutputCnt
     };
 
-    // should the FS discard if the coverage is zero (to avoid stencil manipulation)
-    bool                        fDiscardIfZeroCoverage;
-
-    // stripped of bits that don't affect program generation
-    GrAttribBindings            fAttribBindings;
-
     /** Non-zero if this stage has an effect */
     GrGLEffect::EffectKey       fEffectKeys[GrDrawState::kNumStages];
 
-    // To enable experimental geometry shader code (not for use in
-    // production)
-#if GR_GL_EXPERIMENTAL_GS
-    bool                        fExperimentalGS;
-#endif
+    // To enable experimental geometry shader code (not for use in	
+    // production)	 
+#if GR_GL_EXPERIMENTAL_GS	
+    bool                     fExperimentalGS;	
+#endif	
+
     GrGLShaderBuilder::DstReadKey fDstRead;             // set by GrGLShaderBuilder if there
                                                         // are effects that must read the dst.
                                                         // Otherwise, 0.
 
+    // should the FS discard if the coverage is zero (to avoid stencil manipulation)
+    SkBool8                     fDiscardIfZeroCoverage;
+
     uint8_t                     fColorInput;            // casts to enum ColorInput
     uint8_t                     fCoverageInput;         // casts to enum ColorInput
     uint8_t                     fDualSrcOutput;         // casts to enum DualSrcOutput
+
     int8_t                      fFirstCoverageStage;
     SkBool8                     fEmitsPointSize;
     uint8_t                     fColorFilterXfermode;   // casts to enum SkXfermode::Mode
 
     int8_t                      fPositionAttributeIndex;
+    int8_t                      fLocalCoordAttributeIndex;
     int8_t                      fColorAttributeIndex;
     int8_t                      fCoverageAttributeIndex;
-    int8_t                      fLocalCoordsAttributeIndex;
 
     // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Move all
     // code generation to GrGLShaderBuilder (and maybe add getters rather than friending).
diff --git a/src/gpu/gl/GrGLSL.cpp b/src/gpu/gl/GrGLSL.cpp
index 570e61e..3ec7fc4 100644
--- a/src/gpu/gl/GrGLSL.cpp
+++ b/src/gpu/gl/GrGLSL.cpp
@@ -67,15 +67,6 @@
     return declaredOutput;
 }
 
-GrSLType GrSLFloatVectorType (int count) {
-    GR_STATIC_ASSERT(kFloat_GrSLType == 1);
-    GR_STATIC_ASSERT(kVec2f_GrSLType == 2);
-    GR_STATIC_ASSERT(kVec3f_GrSLType == 3);
-    GR_STATIC_ASSERT(kVec4f_GrSLType == 4);
-    GrAssert(count > 0 && count <= 4);
-    return (GrSLType)(count);
-}
-
 const char* GrGLSLVectorHomogCoord(int count) {
     static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 86cead4..1104cd0 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -117,7 +117,7 @@
 
     fPositionVar = &fVSAttrs.push_back();
     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
-    if (desc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
+    if (-1 != desc.fLocalCoordAttributeIndex) {
         fLocalCoordsVar = &fVSAttrs.push_back();
         fLocalCoordsVar->set(kVec2f_GrSLType,
                              GrGLShaderVar::kAttribute_TypeModifier,
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index d03ef78..d299656 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -180,9 +180,7 @@
 
     fProgramCache = SkNEW_ARGS(ProgramCache, (this->glContext()));
 
-    GrAssert(this->glCaps().maxVertexAttributes() >= GrDrawState::kVertexAttribCnt);
-    GrAssert(this->glCaps().maxVertexAttributes() > GrDrawState::kColorOverrideAttribIndexValue);
-    GrAssert(this->glCaps().maxVertexAttributes() > GrDrawState::kCoverageOverrideAttribIndexValue);
+    GrAssert(this->glCaps().maxVertexAttributes() >= GrDrawState::kMaxVertexAttribCnt);
 
     fLastSuccessfulStencilFmtIdx = 0;
     if (false) { // avoid bit rot, suppress warning
diff --git a/src/gpu/gr_unittests.cpp b/src/gpu/gr_unittests.cpp
index ab5049a..618d412 100644
--- a/src/gpu/gr_unittests.cpp
+++ b/src/gpu/gr_unittests.cpp
@@ -77,5 +77,4 @@
     GR_DEBUGCODE(test_bsearch();)
     test_binHashKey();
     GrRedBlackTree<int>::UnitTest();
-    GrDrawState::VertexAttributesUnitTest();
 }