Resubmit r7899 and r7901.


git-svn-id: http://skia.googlecode.com/svn/trunk@7929 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/AndroidPathRenderer/GrAndroidPathRenderer.cpp b/experimental/AndroidPathRenderer/GrAndroidPathRenderer.cpp
index 2050f09..66cb93a 100644
--- a/experimental/AndroidPathRenderer/GrAndroidPathRenderer.cpp
+++ b/experimental/AndroidPathRenderer/GrAndroidPathRenderer.cpp
@@ -36,12 +36,25 @@
     android::uirenderer::PathRenderer::ConvexPathVertices(origPath, stroke, antiAlias, NULL,
                                                           &vertices);
 
-    // set vertex layout depending on anti-alias
-    GrVertexLayout layout = antiAlias ? GrDrawState::kCoverage_VertexLayoutBit : 0;
+    // set vertex attributes depending on anti-alias
+    GrDrawState* drawState = target->drawState();
+    if (antiAlias) {
+        // position + coverage
+        GrVertexAttrib attribs[] = {
+            GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+            GrVertexAttrib(kVec4ub_GrVertexAttribType, sizeof(GrPoint))
+        };
+        drawState->setVertexAttribs(attribs, SK_ARRAY_COUNT(attribs));
+        drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
+        drawState->setAttribIndex(GrDrawState::kCoverage_AttribIndex, 1);
+        drawState->setAttribBindings(GrDrawState::kCoverage_AttribBindingsBit);
+    } else {
+        drawState->setDefaultVertexAttribs();
+    }
 
     // allocate our vert buffer
     int vertCount = vertices.getSize();
-    GrDrawTarget::AutoReleaseGeometry geo(target, layout, vertCount, 0);
+    GrDrawTarget::AutoReleaseGeometry geo(target, vertCount, 0);
     if (!geo.succeeded()) {
         GrPrintf("Failed to get space for vertices!\n");
         return false;
@@ -49,6 +62,7 @@
 
     // copy android verts to our vertex buffer
     if (antiAlias) {
+        GrAssert(sizeof(ColorVertex) == drawState->getVertexSize());
         ColorVertex* outVert = reinterpret_cast<ColorVertex*>(geo.vertices());
         android::uirenderer::AlphaVertex* inVert =
             reinterpret_cast<android::uirenderer::AlphaVertex*>(vertices.getBuffer());
@@ -63,7 +77,7 @@
             ++inVert;
         }
     } else {
-       size_t vsize = GrDrawState::VertexSize(layout);
+       size_t vsize = drawState->getVertexSize();
        size_t copySize = vsize*vertCount;
        memcpy(geo.vertices(), vertices.getBuffer(), copySize);
     }
diff --git a/experimental/StrokePathRenderer/GrStrokePathRenderer.cpp b/experimental/StrokePathRenderer/GrStrokePathRenderer.cpp
index 03c135d..a8ae917 100644
--- a/experimental/StrokePathRenderer/GrStrokePathRenderer.cpp
+++ b/experimental/StrokePathRenderer/GrStrokePathRenderer.cpp
@@ -111,11 +111,11 @@
 
     // Allocate vertices
     const int nbQuads     = origPath.countPoints() + 1; // Could be "-1" if path is not closed
-    GrVertexLayout layout = 0; // Just 3D points
     const int extraVerts  = isMiter || isBevel ? 1 : 0;
     const int maxVertexCount = nbQuads * (4 + extraVerts);
     const int maxIndexCount  = nbQuads * (6 + extraVerts * 3); // Each extra vert adds a triangle
-    GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxVertexCount, maxIndexCount);
+    target->drawState()->setDefaultVertexAttribs();
+    GrDrawTarget::AutoReleaseGeometry arg(target, maxVertexCount, maxIndexCount);
     if (!arg.succeeded()) {
         return false;
     }
@@ -126,7 +126,7 @@
     // Transform the path into a list of triangles
     SkPath::Iter iter(origPath, false);
     SkPoint pts[4];
-    const SkScalar radius = SkScalarMul(width, 0.5);
+    const SkScalar radius = SkScalarMul(width, 0.5f);
     SkPoint *firstPt = verts, *lastPt = NULL;
     SkVector firstDir, dir;
     firstDir.set(0, 0);
diff --git a/include/core/SkTArray.h b/include/core/SkTArray.h
index 3489de0..89f4c9d 100644
--- a/include/core/SkTArray.h
+++ b/include/core/SkTArray.h
@@ -223,7 +223,20 @@
         }
     }
 
-    /**
+    T* begin() {
+        return fItemArray;
+    }
+    const T* begin() const {
+        return fItemArray;
+    }
+    T* end() {
+        return fItemArray ? fItemArray + fCount : NULL;
+    }
+    const T* end() const {
+        return fItemArray ? fItemArray + fCount : NULL;;
+    }
+
+   /**
      * Get the i^th element.
      */
     T& operator[] (int i) {
diff --git a/include/gpu/GrTextContext.h b/include/gpu/GrTextContext.h
index f329fde..348f3ab 100644
--- a/include/gpu/GrTextContext.h
+++ b/include/gpu/GrTextContext.h
@@ -32,7 +32,6 @@
 
 private:
     GrPaint         fPaint;
-    GrVertexLayout  fVertexLayout;
     GrContext*      fContext;
     GrDrawTarget*   fDrawTarget;
 
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index d79e0c3..2ba499a 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -195,12 +195,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- * Type used to describe format of vertices in arrays
- * Values are defined in GrDrawTarget
- */
-typedef int GrVertexLayout;
-
-/**
 * Geometric primitives used for drawing.
 */
 enum GrPrimitiveType {
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 98eaab8..46e75a0 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -453,9 +453,6 @@
     }
     const SkMatrix* vm = &adcd.getOriginalMatrix();
 
-    GrVertexLayout layout = 0;
-    layout |= GrDrawState::kEdge_VertexLayoutBit;
-
     // We use the fact that SkPath::transform path does subdivision based on
     // perspective. Otherwise, we apply the view matrix when copying to the
     // segment representation.
@@ -481,11 +478,22 @@
         return false;
     }
 
-    drawState->setVertexLayout(layout);
+    // position + edge
+    static const GrVertexAttrib kAttribs[] = {
+        GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+        GrVertexAttrib(kVec4f_GrVertexAttribType, sizeof(GrPoint))
+    };
+    static const GrAttribBindings bindings = GrDrawState::kEdge_AttribBindingsBit;
+
+    drawState->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
+    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
+    drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
+    drawState->setAttribBindings(bindings);
     GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
     if (!arg.succeeded()) {
         return false;
     }
+    GrAssert(sizeof(QuadVertex) == drawState->getVertexSize());
     verts = reinterpret_cast<QuadVertex*>(arg.vertices());
     idxs = reinterpret_cast<uint16_t*>(arg.indices());
 
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 00982ee..a2ad9e3 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -495,15 +495,20 @@
             int* lineCnt,
             int* quadCnt,
             GrDrawTarget::AutoReleaseGeometry* arg) {
-    const GrDrawState& drawState = target->getDrawState();
-    int rtHeight = drawState.getRenderTarget()->height();
+    GrDrawState* drawState = target->drawState();
+    int rtHeight = drawState->getRenderTarget()->height();
 
     GrIRect devClipBounds;
-    target->getClip()->getConservativeBounds(drawState.getRenderTarget(),
+    target->getClip()->getConservativeBounds(drawState->getRenderTarget(),
                                              &devClipBounds);
 
-    GrVertexLayout layout = GrDrawState::kEdge_VertexLayoutBit;
-    SkMatrix viewM = drawState.getViewMatrix();
+    // position + edge
+    static const GrVertexAttrib kAttribs[] = {
+        GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+        GrVertexAttrib(kVec4f_GrVertexAttribType, sizeof(GrPoint))
+    };
+    static const GrAttribBindings kBindings = GrDrawState::kEdge_AttribBindingsBit;
+    SkMatrix viewM = drawState->getViewMatrix();
 
     PREALLOC_PTARRAY(128) lines;
     PREALLOC_PTARRAY(128) quads;
@@ -514,7 +519,10 @@
     *lineCnt = lines.count() / 2;
     int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt;
 
-    target->drawState()->setVertexLayout(layout);
+    target->drawState()->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
+    target->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
+    target->drawState()->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
+    target->drawState()->setAttribBindings(kBindings);
     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 d23c4b4..741b83d 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -13,14 +13,15 @@
 
 namespace {
 
-static GrVertexLayout aa_rect_layout(bool useCoverage) {
-    GrVertexLayout layout = 0;
+static void aa_rect_attributes(bool useCoverage, GrAttribBindings* bindings, 
+                               GrDrawState::AttribIndex* index) {
     if (useCoverage) {
-        layout |= GrDrawState::kCoverage_VertexLayoutBit;
+        *bindings = GrDrawState::kCoverage_AttribBindingsBit;
+        *index = GrDrawState::kCoverage_AttribIndex;
     } else {
-        layout |= GrDrawState::kColor_VertexLayoutBit;
+        *bindings = GrDrawState::kColor_AttribBindingsBit;
+        *index = GrDrawState::kColor_AttribIndex;
     }
-    return layout;
 }
 
 static void set_inset_fan(GrPoint* pts, size_t stride,
@@ -29,6 +30,12 @@
                     r.fRight - dx, r.fBottom - dy, stride);
 }
 
+// position + color/coverage
+static const GrVertexAttrib kVertexAttribs[] = {
+    GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+    GrVertexAttrib(kVec4ub_GrVertexAttribType, sizeof(GrPoint))
+};
+
 };
 
 void GrAARectRenderer::reset() {
@@ -125,8 +132,15 @@
                                   GrDrawTarget* target,
                                   const GrRect& devRect,
                                   bool useVertexCoverage) {
-    GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
-    target->drawState()->setVertexLayout(layout);
+    GrDrawState* drawState = target->drawState();
+
+    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);
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
     if (!geo.succeeded()) {
@@ -141,7 +155,8 @@
     }
 
     intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
-    size_t vsize = target->getDrawState().getVertexSize();
+    size_t vsize = drawState->getVertexSize();
+    GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
 
     GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
     GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
@@ -177,6 +192,8 @@
                                     const GrRect& devRect,
                                     const GrVec& devStrokeSize,
                                     bool useVertexCoverage) {
+    GrDrawState* drawState = target->drawState();
+
     const SkScalar& dx = devStrokeSize.fX;
     const SkScalar& dy = devStrokeSize.fY;
     const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
@@ -195,8 +212,14 @@
         this->fillAARect(gpu, target, r, useVertexCoverage);
         return;
     }
-    GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
-    target->drawState()->setVertexLayout(layout);
+    
+    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);
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
     if (!geo.succeeded()) {
@@ -210,7 +233,8 @@
     }
 
     intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
-    size_t vsize = target->getDrawState().getVertexSize();
+    size_t vsize = drawState->getVertexSize();
+    GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
 
     // We create vertices for four nested rectangles. There are two ramps from 0 to full
     // coverage, one on the exterior of the stroke and the other on the interior.
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 0f6fa16..3b77b73 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -352,8 +352,16 @@
         GrTextureParams params(SkShader::kClamp_TileMode, needsFiltering);
         drawState->createTextureEffect(0, clampedTexture, SkMatrix::I(), params);
 
-        static const GrVertexLayout layout = GrDrawState::StageTexCoordVertexLayoutBit(0);
-        drawState->setVertexLayout(layout);
+        // position + texture coordinate
+        static const GrVertexAttrib kVertexAttribs[] = {
+            GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+            GrVertexAttrib(kVec2f_GrVertexAttribType, sizeof(GrPoint))
+        };
+        static const GrAttribBindings kAttribBindings = GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
+        drawState->setAttribBindings(kAttribBindings);
+        drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
+        drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
+        drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, 1);
         GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0);
 
         if (arg.succeeded()) {
@@ -778,7 +786,7 @@
         // unitSquareVertexBuffer()
 
         static const int worstCaseVertCount = 10;
-        target->drawState()->setVertexLayout(GrDrawState::kDefault_VertexLayout);
+        target->drawState()->setDefaultVertexAttribs();
         GrDrawTarget::AutoReleaseGeometry geo(target, worstCaseVertCount, 0);
 
         if (!geo.succeeded()) {
@@ -821,7 +829,7 @@
             }
 
             GrDrawState* drawState = target->drawState();
-            drawState->setVertexLayout(GrDrawState::kDefault_VertexLayout);
+            target->drawState()->setDefaultVertexAttribs();
             target->setVertexSourceToBuffer(sqVB);
             SkMatrix m;
             m.setAll(rect.width(),    0,             rect.fLeft,
@@ -887,7 +895,7 @@
         GrPrintf("Failed to create static rect vb.\n");
         return;
     }
-    drawState->setVertexLayout(GrDrawState::kDefault_VertexLayout);
+    drawState->setDefaultVertexAttribs();
     target->setVertexSourceToBuffer(sqVB);
     target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
 #else
@@ -912,37 +920,55 @@
     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
     GrDrawState::AutoStageDisable atr(fDrawState);
 
-    GrVertexLayout layout = 0;
-    if (NULL != texCoords) {
-        layout |= GrDrawState::StageTexCoordVertexLayoutBit(0);
-    }
-    if (NULL != colors) {
-        layout |= GrDrawState::kColor_VertexLayoutBit;
-    }
-    target->drawState()->setVertexLayout(layout);
+    GrDrawState* drawState = target->drawState();
 
-    int vertexSize = target->getDrawState().getVertexSize();
+    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());
+    attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, currentOffset));
+    currentOffset += sizeof(GrPoint);
+
+    // set up optional texture coordinate attributes
+    if (NULL != texCoords) {
+        bindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
+        drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, attribs.count());
+        attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, currentOffset));
+        texOffset = currentOffset;
+        currentOffset += sizeof(GrPoint);
+    }
+
+    // set up optional color attributes
+    if (NULL != colors) {
+        bindings |= GrDrawState::kColor_AttribBindingsBit;
+        drawState->setAttribIndex(GrDrawState::kColor_AttribIndex, attribs.count());
+        attribs.push_back(GrVertexAttrib(kVec4ub_GrVertexAttribType, currentOffset));
+        colorOffset = currentOffset;
+        currentOffset += sizeof(GrColor);
+    }
+
+    drawState->setVertexAttribs(attribs.begin(), attribs.count());
+    drawState->setAttribBindings(bindings);
+
+    size_t vertexSize = drawState->getVertexSize();
+    GrAssert(vertexSize == currentOffset);
     if (sizeof(GrPoint) != vertexSize) {
         if (!geo.set(target, vertexCount, 0)) {
             GrPrintf("Failed to get space for vertices!\n");
             return;
         }
-        int texOffset;
-        int colorOffset;
-        GrDrawState::VertexSizeAndOffsets(layout,
-                                          &texOffset,
-                                          &colorOffset,
-                                          NULL,
-                                          NULL);
         void* curVertex = geo.vertices();
 
         for (int i = 0; i < vertexCount; ++i) {
             *((GrPoint*)curVertex) = positions[i];
 
-            if (texOffset > 0) {
+            if (texOffset >= 0) {
                 *(GrPoint*)((intptr_t)curVertex + texOffset) = texCoords[i];
             }
-            if (colorOffset > 0) {
+            if (colorOffset >= 0) {
                 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
             }
             curVertex = (void*)((intptr_t)curVertex + vertexSize);
@@ -1045,8 +1071,17 @@
         return;
     }
 
-    GrVertexLayout layout = GrDrawState::kEdge_VertexLayoutBit;
-    drawState->setVertexLayout(layout);
+    // position + edge
+    static const GrVertexAttrib kVertexAttribs[] = {
+        GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+        GrVertexAttrib(kVec4f_GrVertexAttribType, sizeof(GrPoint))
+    };
+    static const GrAttribBindings kAttributeBindings = GrDrawState::kEdge_AttribBindingsBit;
+
+    drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
+    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
+    drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
+    drawState->setAttribBindings(kAttributeBindings);
     GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index d5ebaaa..7ca478e 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -211,7 +211,6 @@
         return false;
     }
 
-    GrVertexLayout layout = 0;
     bool indexed = contourCnt > 1;
 
     const bool isHairline = stroke.isHairlineStyle();
@@ -233,7 +232,7 @@
         }
     }
 
-    target->drawState()->setVertexLayout(layout);
+    target->drawState()->setDefaultVertexAttribs();
     if (!arg->set(target, maxPts, maxIdxs)) {
         return false;
     }
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 3925bd9..6b00913 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -57,270 +57,150 @@
  * they were just a series of immediate->memory moves.)
  *
  */
-void gen_tex_coord_mask(GrVertexLayout* texCoordMask) {
+void gen_tex_coord_mask(GrAttribBindings* texCoordMask) {
     *texCoordMask = 0;
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        *texCoordMask |= GrDrawState::StageTexCoordVertexLayoutBit(s);
+        *texCoordMask |= GrDrawState::ExplicitTexCoordAttribBindingsBit(s);
     }
 }
 
-const GrVertexLayout kTexCoordMask = (1 << GrDrawState::kNumStages)-1;
-
-inline int num_tex_coords(GrVertexLayout layout) {
-    return (kTexCoordMask & layout) ? 1 : 0;
-}
+const GrAttribBindings kTexCoord_AttribBindingsMask = (1 << GrDrawState::kNumStages)-1;
 
 } //unnamed namespace
 
-static const size_t kVec2Size = sizeof(GrPoint);
+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
+};
 
-size_t GrDrawState::VertexSize(GrVertexLayout vertexLayout) {
-    size_t size = kVec2Size; // position
-    size += num_tex_coords(vertexLayout) * kVec2Size;
-    if (vertexLayout & kColor_VertexLayoutBit) {
-        size += sizeof(GrColor);
-    }
-    if (vertexLayout & kCoverage_VertexLayoutBit) {
-        size += sizeof(GrColor);
-    }
-    if (vertexLayout & kEdge_VertexLayoutBit) {
-        size += 4 * sizeof(SkScalar);
+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::kAttribIndexCount);
+    size_t size = 0;
+    for (int index = 0; index < count; ++index) {
+        size_t attribSize = GrDrawState::kVertexAttribSizes[attribs[index].fType];
+        size += attribSize;
+#if GR_DEBUG
+        size_t dwordCount = attribSize >> 2;
+        uint32_t mask = (1 << dwordCount)-1;
+        size_t offsetShift = attribs[index].fOffset >> 2;
+        GrAssert(!(overlapCheck & (mask << offsetShift)));
+        overlapCheck |= (mask << offsetShift);
+#endif
     }
     return size;
 }
 
+size_t GrDrawState::getVertexSize() const {
+    return vertex_size(fVertexAttribs.begin(), fVertexAttribs.count());
+}
+
+const GrAttribBindings GrDrawState::kAttribIndexMasks[kAttribIndexCount] = {
+    0,                            // position is not reflected in the bindings
+    kColor_AttribBindingsBit,
+    kCoverage_AttribBindingsBit,
+    kEdge_AttribBindingsBit,
+    kTexCoord_AttribBindingsMask
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
- * Functions for computing offsets of various components from the layout
- * bitfield.
- *
- * Order of vertex components:
- * Position
- * Tex Coord
- * Color
- * Coverage
- */
-
-int GrDrawState::VertexStageCoordOffset(int stageIdx, GrVertexLayout vertexLayout) {
-    if (!StageUsesTexCoords(vertexLayout, stageIdx)) {
-        return 0;
+void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
+    GrAssert(count <= GrDrawState::kAttribIndexCount);
+    fVertexAttribs.reset();
+    for (int index = 0; index < count; ++index) {
+        fVertexAttribs.push_back(attribs[index]);
     }
-
-    return kVec2Size;
-}
-
-int GrDrawState::VertexColorOffset(GrVertexLayout vertexLayout) {
-    if (vertexLayout & kColor_VertexLayoutBit) {
-        return kVec2Size * (num_tex_coords(vertexLayout) + 1); //+1 for pos
-    }
-    return -1;
-}
-
-int GrDrawState::VertexCoverageOffset(GrVertexLayout vertexLayout) {
-    if (vertexLayout & kCoverage_VertexLayoutBit) {
-        int offset =  kVec2Size * (num_tex_coords(vertexLayout) + 1);
-        if (vertexLayout & kColor_VertexLayoutBit) {
-            offset += sizeof(GrColor);
-        }
-        return offset;
-    }
-    return -1;
-}
-
-int GrDrawState::VertexEdgeOffset(GrVertexLayout vertexLayout) {
-    // edge pts are after the pos, tex coords, and color
-    if (vertexLayout & kEdge_VertexLayoutBit) {
-        int offset = kVec2Size * (num_tex_coords(vertexLayout) + 1); //+1 for pos
-        if (vertexLayout & kColor_VertexLayoutBit) {
-            offset += sizeof(GrColor);
-        }
-        if (vertexLayout & kCoverage_VertexLayoutBit) {
-            offset += sizeof(GrColor);
-        }
-        return offset;
-    }
-    return -1;
-}
-
-int GrDrawState::VertexSizeAndOffsets(
-        GrVertexLayout vertexLayout,
-        int* texCoordOffset,
-        int* colorOffset,
-        int* coverageOffset,
-        int* edgeOffset) {
-    int size = kVec2Size; // position
-
-    if (kTexCoordMask & vertexLayout) {
-        if (NULL != texCoordOffset) {
-            *texCoordOffset = size;
-        }
-        size += kVec2Size;
-    } else {
-        if (NULL != texCoordOffset) {
-            *texCoordOffset = -1;
-        }
-    }
-    if (kColor_VertexLayoutBit & vertexLayout) {
-        if (NULL != colorOffset) {
-            *colorOffset = size;
-        }
-        size += sizeof(GrColor);
-    } else {
-        if (NULL != colorOffset) {
-            *colorOffset = -1;
-        }
-    }
-    if (kCoverage_VertexLayoutBit & vertexLayout) {
-        if (NULL != coverageOffset) {
-            *coverageOffset = size;
-        }
-        size += sizeof(GrColor);
-    } else {
-        if (NULL != coverageOffset) {
-            *coverageOffset = -1;
-        }
-    }
-    if (kEdge_VertexLayoutBit & vertexLayout) {
-        if (NULL != edgeOffset) {
-            *edgeOffset = size;
-        }
-        size += 4 * sizeof(SkScalar);
-    } else {
-        if (NULL != edgeOffset) {
-            *edgeOffset = -1;
-        }
-    }
-    return size;
-}
-
-int GrDrawState::VertexSizeAndOffsetsByStage(
-        GrVertexLayout vertexLayout,
-        int texCoordOffsetsByStage[GrDrawState::kNumStages],
-        int* colorOffset,
-        int* coverageOffset,
-        int* edgeOffset) {
-
-    int texCoordOffset;
-    int size = VertexSizeAndOffsets(vertexLayout,
-                                    &texCoordOffset,
-                                    colorOffset,
-                                    coverageOffset,
-                                    edgeOffset);
-    if (NULL != texCoordOffsetsByStage) {
-        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-            texCoordOffsetsByStage[s] = StageUsesTexCoords(vertexLayout, s) ?
-                                                           texCoordOffset : 0;
-        }
-    }
-    return size;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrDrawState::VertexUsesTexCoords(GrVertexLayout vertexLayout) {
-    return SkToBool(kTexCoordMask & vertexLayout);
+void GrDrawState::setDefaultVertexAttribs() {
+    fVertexAttribs.reset();
+    fVertexAttribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, 0));
+    
+    fCommon.fAttribBindings = kDefault_AttribBindings;
+
+    fAttribIndices[kPosition_AttribIndex] = 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrDrawState::VertexLayoutUnitTest() {
+bool GrDrawState::AttributesBindExplicitTexCoords(GrAttribBindings attribBindings) {
+    return SkToBool(kTexCoord_AttribBindingsMask & attribBindings);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawState::VertexAttributesUnitTest() {
     // Ensure that our tex coord mask is correct
-    GrVertexLayout texCoordMask;
+    GrAttribBindings texCoordMask;
     gen_tex_coord_mask(&texCoordMask);
-    GrAssert(texCoordMask == kTexCoordMask);
+    GrAssert(texCoordMask == kTexCoord_AttribBindingsMask);
 
     // not necessarily exhaustive
     static bool run;
     if (!run) {
         run = true;
-        GrVertexLayout tcMask = 0;
-        GrAssert(!VertexUsesTexCoords(0));
+
+        GrVertexAttribArray<6> attribs;
+        GrAssert(0 == vertex_size(attribs.begin(), attribs.count()));
+ 
+        attribs.push_back(GrVertexAttrib(kFloat_GrVertexAttribType, 0));
+        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()));
+
+        attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, attribs[0].fOffset + 4*sizeof(char)));
+        GrAssert(4*sizeof(char) + 2*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
+        attribs.push_back(GrVertexAttrib(kVec3f_GrVertexAttribType, attribs[1].fOffset + 2*sizeof(float)));
+        GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) == 
+                 vertex_size(attribs.begin(), attribs.count()));
+        attribs.push_back(GrVertexAttrib(kFloat_GrVertexAttribType, attribs[2].fOffset + 3*sizeof(float)));
+        GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) + sizeof(float) == 
+                 vertex_size(attribs.begin(), attribs.count()));
+        attribs.push_back(GrVertexAttrib(kVec4f_GrVertexAttribType, attribs[3].fOffset + sizeof(float)));
+        GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) + sizeof(float) + 4*sizeof(float) == 
+                 vertex_size(attribs.begin(), attribs.count()));
+
+        GrAttribBindings tcMask = 0;
+        GrAssert(!AttributesBindExplicitTexCoords(0));
         for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-            tcMask |= StageTexCoordVertexLayoutBit(s);
-            GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
-            GrAssert(VertexUsesTexCoords(tcMask));
-            GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask));
-            GrAssert(StageUsesTexCoords(tcMask, s));
+            tcMask |= ExplicitTexCoordAttribBindingsBit(s);
+            GrAssert(AttributesBindExplicitTexCoords(tcMask));
+            GrAssert(StageBindsExplicitTexCoords(tcMask, s));
             for (int s2 = s + 1; s2 < GrDrawState::kNumStages; ++s2) {
-                GrAssert(!StageUsesTexCoords(tcMask, s2));
-
-            #if GR_DEBUG
-                GrVertexLayout posAsTex = tcMask;
-            #endif
-                GrAssert(0 == VertexStageCoordOffset(s2, posAsTex));
-                GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
-                GrAssert(!StageUsesTexCoords(posAsTex, s2));
-                GrAssert(-1 == VertexEdgeOffset(posAsTex));
+                GrAssert(!StageBindsExplicitTexCoords(tcMask, s2));
             }
-            GrAssert(-1 == VertexEdgeOffset(tcMask));
-            GrAssert(-1 == VertexColorOffset(tcMask));
-            GrAssert(-1 == VertexCoverageOffset(tcMask));
-        #if GR_DEBUG
-            GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
-        #endif
-            GrAssert(-1 == VertexCoverageOffset(withColor));
-            GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
-            GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
-        #if GR_DEBUG
-            GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit;
-        #endif
-            GrAssert(-1 == VertexColorOffset(withEdge));
-            GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge));
-            GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge));
-        #if GR_DEBUG
-            GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit;
-        #endif
-            GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge));
-            GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge));
-            GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge));
-        #if GR_DEBUG
-            GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit;
-        #endif
-            GrAssert(-1 == VertexColorOffset(withCoverage));
-            GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage));
-            GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage));
-        #if GR_DEBUG
-            GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit |
-                                                    kColor_VertexLayoutBit;
-        #endif
-            GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor));
-            GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor));
-            GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor));
         }
-        GrAssert(kTexCoordMask == tcMask);
-
-        int stageOffsets[GrDrawState::kNumStages];
-        int colorOffset;
-        int edgeOffset;
-        int coverageOffset;
-        int size;
-        size = VertexSizeAndOffsetsByStage(tcMask,
-                                           stageOffsets, &colorOffset,
-                                           &coverageOffset, &edgeOffset);
-        GrAssert(2*sizeof(GrPoint) == size);
-        GrAssert(-1 == colorOffset);
-        GrAssert(-1 == coverageOffset);
-        GrAssert(-1 == edgeOffset);
-        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-            GrAssert(sizeof(GrPoint) == stageOffsets[s]);
-            GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
-        }
+        GrAssert(kTexCoord_AttribBindingsMask == tcMask);
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrDrawState::StageUsesTexCoords(GrVertexLayout layout, int stageIdx) {
-    return SkToBool(layout & StageTexCoordVertexLayoutBit(stageIdx));
+bool GrDrawState::StageBindsExplicitTexCoords(GrAttribBindings bindings, int stageIdx) {
+    return SkToBool(bindings & ExplicitTexCoordAttribBindingsBit(stageIdx));
 }
 
-bool GrDrawState::srcAlphaWillBeOne(GrVertexLayout layout) const {
+bool GrDrawState::srcAlphaWillBeOne(GrAttribBindings bindings) const {
 
     uint32_t validComponentFlags;
     GrColor color;
     // Check if per-vertex or constant color may have partial alpha
-    if (layout & kColor_VertexLayoutBit) {
+    if (bindings & kColor_AttribBindingsBit) {
         validComponentFlags = 0;
         color = 0; // not strictly necessary but we get false alarms from tools about uninit.
     } else {
@@ -366,7 +246,7 @@
     return (GrEffect::kA_ValidComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
 }
 
-bool GrDrawState::hasSolidCoverage(GrVertexLayout layout) const {
+bool GrDrawState::hasSolidCoverage(GrAttribBindings bindings) const {
     // If we're drawing coverage directly then coverage is effectively treated as color.
     if (this->isCoverageDrawing()) {
         return true;
@@ -375,7 +255,7 @@
     GrColor coverage;
     uint32_t validComponentFlags;
     // Initialize to an unknown starting coverage if per-vertex coverage is specified.
-    if (layout & kCoverage_VertexLayoutBit) {
+    if (bindings & kCoverage_AttribBindingsBit) {
         validComponentFlags = 0;
     } else {
         coverage = fCommon.fCoverage;
@@ -417,7 +297,7 @@
 GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
                                                      GrBlendCoeff* srcCoeff,
                                                      GrBlendCoeff* dstCoeff) const {
-    GrVertexLayout layout = this->getVertexLayout();
+    GrAttribBindings bindings = this->getAttribBindings();
 
     GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
     if (NULL == srcCoeff) {
@@ -435,14 +315,14 @@
         *dstCoeff = kOne_GrBlendCoeff;
     }
 
-    bool srcAIsOne = this->srcAlphaWillBeOne(layout);
+    bool srcAIsOne = this->srcAlphaWillBeOne(bindings);
     bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
                          (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
     bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
                          (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
 
     bool covIsZero = !this->isCoverageDrawing() &&
-                     !(layout & GrDrawState::kCoverage_VertexLayoutBit) &&
+                     !(bindings & GrDrawState::kCoverage_AttribBindingsBit) &&
                      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
@@ -460,8 +340,8 @@
     // edge aa or coverage stage
     bool hasCoverage = forceCoverage ||
                        0xffffffff != this->getCoverage() ||
-                       (layout & GrDrawState::kCoverage_VertexLayoutBit) ||
-                       (layout & GrDrawState::kEdge_VertexLayoutBit);
+                       (bindings & GrDrawState::kCoverage_AttribBindingsBit) ||
+                       (bindings & GrDrawState::kEdge_AttribBindingsBit);
     for (int s = this->getFirstCoverageStage();
          !hasCoverage && s < GrDrawState::kNumStages;
          ++s) {
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 05492a7..53c575d 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -23,6 +23,41 @@
 
 class GrPaint;
 
+/**
+ * Types used to describe format of vertices in arrays
+  */
+enum GrVertexAttribType {
+    kFloat_GrVertexAttribType = 0,
+    kVec2f_GrVertexAttribType,
+    kVec3f_GrVertexAttribType,
+    kVec4f_GrVertexAttribType,
+    kVec4ub_GrVertexAttribType,   // vector of 4 unsigned bytes, e.g. colors
+
+    kLast_GrVertexAttribType = kVec4ub_GrVertexAttribType
+};
+static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1;
+
+struct GrVertexAttrib {
+    GrVertexAttrib() {}
+    GrVertexAttrib(GrVertexAttribType type, size_t offset) :
+        fType(type), fOffset(offset) {}
+    bool operator==(const GrVertexAttrib& other) const {
+        return fType == other.fType && fOffset == other.fOffset;
+    };
+    bool operator!=(const GrVertexAttrib& other) const { return !(*this == other); }
+
+    GrVertexAttribType fType;
+    size_t             fOffset;
+};
+
+template <int N>
+class GrVertexAttribArray : public SkSTArray<N, GrVertexAttrib, true> {};
+
+/**
+ * Type used to describe how attributes bind to program usage
+ */
+typedef int GrAttribBindings;
+
 class GrDrawState : public GrRefCnt {
 public:
     SK_DECLARE_INST_COUNT(GrDrawState)
@@ -32,7 +67,7 @@
      * GrEffect. The effect produces an output color in the fragment shader. It's inputs are the
      * output from the previous enabled stage and a position. The position is either derived from
      * the interpolated vertex positions or explicit per-vertex coords, depending upon the
-     * GrVertexLayout used to draw.
+     * GrAttribBindings used to draw.
      *
      * The stages are divided into two sets, color-computing and coverage-computing. The final color
      * stage produces the final pixel color. The coverage-computing stages function exactly as the
@@ -40,7 +75,7 @@
      * 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 GrVertexLayout. The input to the first coverage stage is
+     * per-vertex colors, depending upon GrAttribBindings. The input to the first coverage stage is
      * either a constant coverage (usually full-coverage), interpolated per-vertex coverage, or
      * edge-AA computed coverage. (This latter is going away as soon as it can be rewritten as a
      * GrEffect).
@@ -59,7 +94,7 @@
 
     GrDrawState() {
 #if GR_DEBUG
-        VertexLayoutUnitTest();
+        VertexAttributesUnitTest();
 #endif
         this->reset();
     }
@@ -82,8 +117,9 @@
 
         fRenderTarget.reset(NULL);
 
+        this->setDefaultVertexAttribs();
+
         fCommon.fColor = 0xffffffff;
-        fCommon.fVertexLayout = kDefault_VertexLayout;
         fCommon.fViewMatrix.reset();
         fCommon.fSrcBlend = kOne_GrBlendCoeff;
         fCommon.fDstBlend = kZero_GrBlendCoeff;
@@ -107,193 +143,50 @@
     void setFromPaint(const GrPaint& paint);
 
     ///////////////////////////////////////////////////////////////////////////
-    /// @name Vertex Layout
+    /// @name Vertex Attributes
     ////
 
-    /**
-     * The format of vertices is represented as a bitfield of flags.
-     * Flags that indicate the layout of vertex data. Vertices always contain
-     * positions and may also contain texture coordinates, per-vertex colors,
-     * and per-vertex coverage. Each stage can use any texture coordinates as
-     * its input texture coordinates or it may use the positions as texture
-     * coordinates.
-     *
-     * If no texture coordinates are specified for a stage then the stage is
-     * disabled.
-     *
-     * The order in memory is always (position, texture coords, color, coverage)
-     * with any unused fields omitted.
-     */
-
-    /**
-     * Generates a bit indicating that a texture stage uses texture coordinates
-     *
-     * @param stageIdx    the stage that will use texture coordinates.
-     *
-     * @return the bit to add to a GrVertexLayout bitfield.
-     */
-    static int StageTexCoordVertexLayoutBit(int stageIdx) {
-        GrAssert(stageIdx < kNumStages);
-        return (1 << stageIdx);
-    }
-
-    static bool StageUsesTexCoords(GrVertexLayout layout, int stageIdx);
-
-private:
-    // non-stage bits start at this index.
-    static const int STAGE_BIT_CNT = kNumStages;
-public:
-
-    /**
-     * Additional Bits that can be specified in GrVertexLayout.
-     */
-    enum VertexLayoutBits {
-        /* vertices have colors (GrColor) */
-        kColor_VertexLayoutBit              = 1 << (STAGE_BIT_CNT + 0),
-        /* vertices have coverage (GrColor)
-         */
-        kCoverage_VertexLayoutBit           = 1 << (STAGE_BIT_CNT + 1),
-        /* Each vertex specificies an edge. Distance to the edge is used to
-         * compute a coverage. See GrDrawState::setVertexEdgeType().
-         */
-        kEdge_VertexLayoutBit               = 1 << (STAGE_BIT_CNT + 2),
-        // for below assert
-        kDummyVertexLayoutBit,
-        kHighVertexLayoutBit = kDummyVertexLayoutBit - 1
-    };
-    // make sure we haven't exceeded the number of bits in GrVertexLayout.
-    GR_STATIC_ASSERT(kHighVertexLayoutBit < ((uint64_t)1 << 8*sizeof(GrVertexLayout)));
-
-    enum VertexLayout {
-        kDefault_VertexLayout = 0
+    enum {
+        kVertexAttribCnt = 6,
     };
 
-    /**
-     *  Sets vertex layout for next draw.
+   /**
+     * 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). 
      *
-     *  @param layout    the vertex layout to set.
+     * 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.
      */
-    void setVertexLayout(GrVertexLayout layout) { fCommon.fVertexLayout = layout; }
 
-    GrVertexLayout getVertexLayout() const { return fCommon.fVertexLayout; }
-    size_t getVertexSize() const { return VertexSize(fCommon.fVertexLayout); }
+    /**
+     *  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. 
+     */
+    void setVertexAttribs(const GrVertexAttrib attribs[], int count);
 
+    const GrVertexAttrib* getVertexAttribs() const { return fVertexAttribs.begin(); }
+    int getVertexAttribCount() const { return fVertexAttribs.count(); }
+
+    size_t getVertexSize() const;
+
+    /**
+     *  Sets default vertex attributes for next draw. 
+     *
+     *  This will also set default vertex attribute indices and bindings
+     */
+    void setDefaultVertexAttribs();
 
     ////////////////////////////////////////////////////////////////////////////
-    // Helpers for picking apart vertex layouts
+    // Helpers for picking apart vertex attributes
 
-    /**
-     * Helper function to compute the size of a vertex from a vertex layout
-     * @return size of a single vertex.
-     */
-    static size_t VertexSize(GrVertexLayout vertexLayout);
-
-    /**
-     * Helper function to compute the offset of texture coordinates in a vertex
-     * @return offset of texture coordinates in vertex layout or 0 if positions
-     *         are used as texture coordinates for the stage.
-     */
-    static int VertexStageCoordOffset(int stageIdx, GrVertexLayout vertexLayout);
-
-    /**
-     * Helper function to compute the offset of the color in a vertex
-     * @return offset of color in vertex layout or -1 if the
-     *         layout has no color.
-     */
-    static int VertexColorOffset(GrVertexLayout vertexLayout);
-
-    /**
-     * Helper function to compute the offset of the coverage in a vertex
-     * @return offset of coverage in vertex layout or -1 if the
-     *         layout has no coverage.
-     */
-    static int VertexCoverageOffset(GrVertexLayout vertexLayout);
-
-     /**
-      * Helper function to compute the offset of the edge pts in a vertex
-      * @return offset of edge in vertex layout or -1 if the
-      *         layout has no edge.
-      */
-     static int VertexEdgeOffset(GrVertexLayout vertexLayout);
-
-    /**
-     * Helper function to determine if vertex layout contains explicit texture
-     * coordinates.
-     *
-     * @param vertexLayout  layout to query
-     *
-     * @return true if vertex specifies texture coordinates,
-     *         false otherwise.
-     */
-    static bool VertexUsesTexCoords(GrVertexLayout vertexLayout);
-
-    /**
-     * Helper function to compute the size of each vertex and the offsets of
-     * texture coordinates and color.
-     *
-     * @param vertexLayout          the layout to query
-     * @param texCoordOffset        after return it is the offset of the
-     *                              tex coord index in the vertex or -1 if
-     *                              tex coords aren't used. (optional)
-     * @param colorOffset           after return it is the offset of the
-     *                              color field in each vertex, or -1 if
-     *                              there aren't per-vertex colors. (optional)
-     * @param coverageOffset        after return it is the offset of the
-     *                              coverage field in each vertex, or -1 if
-     *                              there aren't per-vertex coeverages.
-     *                              (optional)
-     * @param edgeOffset            after return it is the offset of the
-     *                              edge eq field in each vertex, or -1 if
-     *                              there aren't per-vertex edge equations.
-     *                              (optional)
-     * @return size of a single vertex
-     */
-    static int VertexSizeAndOffsets(GrVertexLayout vertexLayout,
-                   int *texCoordOffset,
-                   int *colorOffset,
-                   int *coverageOffset,
-                   int* edgeOffset);
-
-    /**
-     * Helper function to compute the size of each vertex and the offsets of
-     * texture coordinates and color. Determines tex coord offsets by stage
-     * rather than by index. (Each stage can be mapped to any t.c. index
-     * by StageTexCoordVertexLayoutBit.) If a stage uses positions for
-     * tex coords then that stage's offset will be 0 (positions are always at 0).
-     *
-     * @param vertexLayout              the layout to query
-     * @param texCoordOffsetsByStage    after return it is the offset of each
-     *                                  tex coord index in the vertex or -1 if
-     *                                  index isn't used. (optional)
-     * @param colorOffset               after return it is the offset of the
-     *                                  color field in each vertex, or -1 if
-     *                                  there aren't per-vertex colors.
-     *                                  (optional)
-     * @param coverageOffset            after return it is the offset of the
-     *                                  coverage field in each vertex, or -1 if
-     *                                  there aren't per-vertex coeverages.
-     *                                  (optional)
-     * @param edgeOffset                after return it is the offset of the
-     *                                  edge eq field in each vertex, or -1 if
-     *                                  there aren't per-vertex edge equations.
-     *                                  (optional)
-     * @return size of a single vertex
-     */
-    static int VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
-                   int texCoordOffsetsByStage[kNumStages],
-                   int* colorOffset,
-                   int* coverageOffset,
-                   int* edgeOffset);
-
-    /**
-     * Determines whether src alpha is guaranteed to be one for all src pixels
-     */
-    bool srcAlphaWillBeOne(GrVertexLayout) const;
-
-    /**
-     * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw.
-     */
-    bool hasSolidCoverage(GrVertexLayout) const;
+    // 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
@@ -304,7 +197,7 @@
     /**
      * Gets a pointer to a GrPoint of a vertex's position or texture
      * coordinate.
-     * @param vertices      the vetex array
+     * @param vertices      the vertex array
      * @param vertexIndex   the index of the vertex in the array
      * @param vertexSize    the size of each vertex in the array
      * @param offset        the offset in bytes of the vertex component.
@@ -353,7 +246,140 @@
                                        vertexIndex * vertexSize);
     }
 
-    static void VertexLayoutUnitTest();
+    /// @}
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// @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. Each 
+     * stage can use the explicit texture coordinates as its input texture 
+     * coordinates or it may use the positions as texture coordinates.
+     */
+
+    /**
+     * Generates a bit indicating that a texture stage uses texture coordinates
+     *
+     * @param stageIdx    the stage that will use texture coordinates.
+     *
+     * @return the bit to add to a GrAttribBindings bitfield.
+     */
+    static int ExplicitTexCoordAttribBindingsBit(int stageIdx) {
+        GrAssert(stageIdx < kNumStages);
+        return (1 << stageIdx);
+    }
+
+    static bool StageBindsExplicitTexCoords(GrAttribBindings bindings, int stageIdx);
+
+    /**
+     * Additional Bits that can be specified in GrAttribBindings.
+     */
+    enum AttribBindingsBits {
+        /* program uses colors (GrColor) */
+        kColor_AttribBindingsBit              = 1 << (kNumStages + 0),
+        /* program uses coverage (GrColor)
+         */
+        kCoverage_AttribBindingsBit           = 1 << (kNumStages + 1),
+        /* program uses edge data. Distance to the edge is used to
+         * compute a coverage. See GrDrawState::setVertexEdgeType().
+         */
+        kEdge_AttribBindingsBit               = 1 << (kNumStages + 2),
+        // 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
+
+    /**
+     * Helper function to determine if program uses explicit texture
+     * coordinates.
+     *
+     * @param  bindings  attribute bindings to query
+     *
+     * @return true if program uses texture coordinates,
+     *         false otherwise.
+     */
+    static bool AttributesBindExplicitTexCoords(GrAttribBindings bindings);
+
+    /**
+     * Determines whether src alpha is guaranteed to be one for all src pixels
+     */
+    bool srcAlphaWillBeOne(GrAttribBindings) 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,
+        kEdge_AttribIndex,
+        kTexCoord_AttribIndex,
+
+        kLast_AttribIndex = kTexCoord_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]; }
 
     /// @}
 
@@ -1004,7 +1030,7 @@
 
     /**
      * Determines the interpretation per-vertex edge data when the
-     * kEdge_VertexLayoutBit is set (see GrDrawTarget). When per-vertex edges
+     * kEdge_AttribBindingsBit is set (see GrDrawTarget). When per-vertex edges
      * are not specified the value of this setting has no effect.
      */
     void setVertexEdgeType(VertexEdgeType type) {
@@ -1159,13 +1185,25 @@
         return (NULL != fStages[s].getEffect());
     }
 
-    // Most stages are usually not used, so conditionals here
-    // reduce the expected number of bytes touched by 50%.
     bool operator ==(const GrDrawState& s) const {
         if (fRenderTarget.get() != s.fRenderTarget.get() || fCommon != s.fCommon) {
             return false;
         }
-
+        if (fVertexAttribs.count() != s.fVertexAttribs.count()) {
+            return false;
+        }
+        for (int i = 0; i < fVertexAttribs.count(); ++i) {
+            if (fVertexAttribs[i] != s.fVertexAttribs[i]) {
+                return false;
+            }
+        }
+        for (int i = 0; i < kAttribIndexCount; ++i) {
+            if ((i == kPosition_AttribIndex || 
+                    s.fCommon.fAttribBindings & kAttribIndexMasks[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)) {
@@ -1182,6 +1220,10 @@
     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];
@@ -1196,7 +1238,7 @@
     struct CommonState {
         // These fields are roughly sorted by decreasing likelihood of being different in op==
         GrColor                         fColor;
-        GrVertexLayout                  fVertexLayout;
+        GrAttribBindings                fAttribBindings;
         SkMatrix                        fViewMatrix;
         GrBlendCoeff                    fSrcBlend;
         GrBlendCoeff                    fDstBlend;
@@ -1211,7 +1253,7 @@
         DrawFace                        fDrawFace;
         bool operator== (const CommonState& other) const {
             return fColor == other.fColor &&
-                   fVertexLayout == other.fVertexLayout &&
+                   fAttribBindings == other.fAttribBindings &&
                    fViewMatrix.cheapEqualTo(other.fViewMatrix) &&
                    fSrcBlend == other.fSrcBlend &&
                    fDstBlend == other.fDstBlend &&
@@ -1256,6 +1298,10 @@
             // 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).
@@ -1269,6 +1315,10 @@
             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]);
             }
@@ -1278,6 +1328,20 @@
             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.count() != state.fVertexAttribs.count()) {
+                return false;
+            }
+            for (int i = 0; i < fVertexAttribs.count(); ++i) 
+                if (fVertexAttribs[i] != state.fVertexAttribs[i]) {
+                    return false;
+            }
             for (int i = 0; i < kNumStages; ++i) {
                 if (!fStages[i].isEqual(state.fStages[i])) {
                     return false;
@@ -1287,17 +1351,25 @@
         }
 
     private:
-        GrRenderTarget*                 fRenderTarget;
-        CommonState                     fCommon;
-        GrEffectStage::DeferredStage    fStages[kNumStages];
+        GrRenderTarget*                       fRenderTarget;
+        CommonState                           fCommon;
+        int                                   fAttribIndices[kAttribIndexCount];
+        GrVertexAttribArray<kVertexAttribCnt> fVertexAttribs;
+        GrEffectStage::DeferredStage          fStages[kNumStages];
 
         GR_DEBUGCODE(bool fInitialized;)
     };
 
 private:
-    SkAutoTUnref<GrRenderTarget>    fRenderTarget;
-    CommonState                     fCommon;
-    GrEffectStage                   fStages[kNumStages];
+    // 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 2c2d949..dab2965 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -530,11 +530,19 @@
                             const GrRect* srcRect,
                             const SkMatrix* srcMatrix,
                             int stage) {
-    GrVertexLayout layout = 0;
+    GrAttribBindings bindings = 0;
     uint32_t explicitCoordMask = 0;
+    // position + (optional) texture coord
+    static const GrVertexAttrib kAttribs[] = {
+        GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+        GrVertexAttrib(kVec2f_GrVertexAttribType, sizeof(GrPoint))
+    };
+    int attribCount = 1;
 
     if (NULL != srcRect) {
-        layout |= GrDrawState::StageTexCoordVertexLayoutBit(stage);
+        bindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(stage);
+        attribCount = 2;
+        this->drawState()->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, 1);
         explicitCoordMask = (1 << stage);
     }
 
@@ -543,30 +551,26 @@
         avmr.set(this->drawState(), *matrix, explicitCoordMask);
     }
 
-    this->drawState()->setVertexLayout(layout);
+    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");
         return;
     }
 
-    int stageOffsets[GrDrawState::kNumStages];
-    int vsize = GrDrawState::VertexSizeAndOffsetsByStage(layout, stageOffsets,  NULL, NULL, NULL);
+    size_t vsize = this->drawState()->getVertexSize();
     geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize);
-
-    for (int i = 0; i < GrDrawState::kNumStages; ++i) {
-        if (explicitCoordMask & (1 << i)) {
-            GrAssert(0 != stageOffsets[i]);
-            GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
-                                                stageOffsets[i]);
-            coords->setRectFan(srcRect->fLeft, srcRect->fTop,
-                               srcRect->fRight, srcRect->fBottom,
-                               vsize);
-            if (NULL != srcMatrix) {
-                srcMatrix->mapPointsWithStride(coords, vsize, 4);
-            }
-        } else {
-            GrAssert(0 == stageOffsets[i]);
+    if (NULL != srcRect) {
+        GrAssert(attribCount == 2);
+        GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
+                                            kAttribs[1].fOffset);
+        coords->setRectFan(srcRect->fLeft, srcRect->fTop,
+                            srcRect->fRight, srcRect->fBottom,
+                            vsize);
+        if (NULL != srcMatrix) {
+            srcMatrix->mapPointsWithStride(coords, vsize, 4);
         }
     }
 
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 00aaadb..b2705a4 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -78,9 +78,20 @@
                                    const SkMatrix* srcMatrix,
                                    int stage) {
 
-    GrVertexLayout layout = 0;
+    GrAttribBindings bindings = GrDrawState::kDefault_AttribBindings;
     GrDrawState::AutoColorRestore acr;
-    GrColor color = this->drawState()->getColor();
+
+    GrDrawState* drawState = this->drawState();
+
+    GrColor color = drawState->getColor();
+    GrVertexAttribArray<3> attribs;
+    size_t currentOffset = 0;
+    int colorOffset = -1, texOffset = -1;
+
+    // set position attrib
+    drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, attribs.count());
+    attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, currentOffset));
+    currentOffset += sizeof(GrPoint);
 
     // 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
@@ -89,22 +100,31 @@
     // 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->getCaps().dualSourceBlendingSupport() ||
-        this->getDrawState().hasSolidCoverage(this->getDrawState().getVertexLayout())) {
-        layout |= GrDrawState::kColor_VertexLayoutBit;;
+        drawState->hasSolidCoverage(drawState->getAttribBindings())) {
+        bindings |= GrDrawState::kColor_AttribBindingsBit;
+        drawState->setAttribIndex(GrDrawState::kColor_AttribIndex, attribs.count());
+        attribs.push_back(GrVertexAttrib(kVec4ub_GrVertexAttribType, currentOffset));
+        colorOffset = currentOffset;
+        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
         // mismatch. TODO: Once vertex layout is owned by GrDrawState it should skip comparing the
         // constant color in its op== when the kColor layout bit is set and then we can remove this.
-        acr.set(this->drawState(), 0xFFFFFFFF);
+        acr.set(drawState, 0xFFFFFFFF);
     }
 
     uint32_t explicitCoordMask = 0;
     if (NULL != srcRect) {
-        layout |= GrDrawState::StageTexCoordVertexLayoutBit(stage);
+        bindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(stage);
+        drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, attribs.count());
+        attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, currentOffset));
+        texOffset = currentOffset;
+        currentOffset += sizeof(GrPoint);
         explicitCoordMask = (1 << stage);
     }
 
-    this->drawState()->setVertexLayout(layout);
+    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");
@@ -118,18 +138,17 @@
     } else {
         combinedMatrix.reset();
     }
-    combinedMatrix.postConcat(this->drawState()->getViewMatrix());
+    combinedMatrix.postConcat(drawState->getViewMatrix());
     // When the caller has provided an explicit source rect for a stage then we don't want to
     // modify that stage's matrix. Otherwise if the effect is generating its source rect from
     // the vertex positions then we have to account for the view matrix change.
-    GrDrawState::AutoDeviceCoordDraw adcd(this->drawState(), explicitCoordMask);
+    GrDrawState::AutoDeviceCoordDraw adcd(drawState, explicitCoordMask);
     if (!adcd.succeeded()) {
         return;
     }
 
-    int stageOffsets[GrDrawState::kNumStages], colorOffset;
-    int vsize = GrDrawState::VertexSizeAndOffsetsByStage(layout, stageOffsets,
-                                                         &colorOffset, NULL, NULL);
+    size_t vsize = drawState->getVertexSize();
+    GrAssert(vsize == currentOffset);
 
     geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize);
     combinedMatrix.mapPointsWithStride(geo.positions(), vsize, 4);
@@ -139,19 +158,15 @@
     // unnecessary clipping in our onDraw().
     get_vertex_bounds(geo.vertices(), vsize, 4, &devBounds);
 
-    for (int i = 0; i < GrDrawState::kNumStages; ++i) {
-        if (explicitCoordMask & (1 << i)) {
-            GrAssert(0 != stageOffsets[i]);
-            GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
-                                                stageOffsets[i]);
-            coords->setRectFan(srcRect->fLeft, srcRect->fTop,
-                               srcRect->fRight, srcRect->fBottom,
-                               vsize);
-            if (NULL != srcMatrix) {
-                srcMatrix->mapPointsWithStride(coords, vsize, 4);
-            }
-        } else {
-            GrAssert(0 == stageOffsets[i]);
+    if (texOffset >= 0) {
+        GrAssert(explicitCoordMask != 0);
+        GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
+                                            texOffset);
+        coords->setRectFan(srcRect->fLeft, srcRect->fTop,
+                            srcRect->fRight, srcRect->fBottom,
+                            vsize);
+        if (NULL != srcMatrix) {
+            srcMatrix->mapPointsWithStride(coords, vsize, 4);
         }
     }
 
@@ -165,6 +180,9 @@
 
     this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer());
     this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds);
+
+    // to ensure that stashing the drawState ptr is valid
+    GrAssert(this->drawState() == drawState);
 }
 
 bool GrInOrderDrawBuffer::quickInsideClip(const SkRect& devBounds) {
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index e599fc9..e77bf93 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -92,8 +92,6 @@
 
     fVertices = NULL;
     fMaxVertices = 0;
-
-    fVertexLayout =  GrDrawState::StageTexCoordVertexLayoutBit(kGlyphMaskStage);
 }
 
 GrTextContext::~GrTextContext() {
@@ -189,13 +187,20 @@
     }
 
     if (NULL == fVertices) {
-        // If we need to reserve vertices allow the draw target to suggest
+        // position + texture coord
+        static const GrVertexAttrib kVertexAttribs[] = {
+            GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
+            GrVertexAttrib(kVec2f_GrVertexAttribType, sizeof(GrPoint))
+        };
+        static const GrAttribBindings kAttribBindings = GrDrawState::ExplicitTexCoordAttribBindingsBit(kGlyphMaskStage);
+
+       // If we need to reserve vertices allow the draw target to suggest
         // a number of verts to reserve and whether to perform a flush.
         fMaxVertices = kMinRequestedVerts;
         bool flush = false;
         fDrawTarget = fContext->getTextTarget(fPaint);
         if (NULL != fDrawTarget) {
-            fDrawTarget->drawState()->setVertexLayout(fVertexLayout);
+            fDrawTarget->drawState()->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
             flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
         }
         if (flush) {
@@ -203,8 +208,11 @@
             fContext->flush();
             // flushGlyphs() will reset fDrawTarget to NULL.
             fDrawTarget = fContext->getTextTarget(fPaint);
-            fDrawTarget->drawState()->setVertexLayout(fVertexLayout);
+            fDrawTarget->drawState()->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
         }
+        fDrawTarget->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
+        fDrawTarget->drawState()->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, 1);
+        fDrawTarget->drawState()->setAttribBindings(kAttribBindings);
         fMaxVertices = kDefaultRequestedVerts;
         // ignore return, no point in flushing again.
         fDrawTarget->geometryHints(&fMaxVertices, NULL);
@@ -222,6 +230,7 @@
                                                    GrTCast<void**>(&fVertices),
                                                    NULL);
         GrAlwaysAssert(success);
+        GrAssert(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
     }
 
     GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 0ca84bc..781e15f 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -35,6 +35,14 @@
 inline const char* dual_source_output_name() { return "dualSourceOut"; }
 }
 
+const GrGLProgram::AttribLayout GrGLProgram::kAttribLayouts[kGrVertexAttribTypeCount] = {
+    {1, GR_GL_FLOAT, false},         // kFloat_GrVertexAttribType
+    {2, GR_GL_FLOAT, false},         // kVec2f_GrVertexAttribType
+    {3, GR_GL_FLOAT, false},         // kVec3f_GrVertexAttribType
+    {4, GR_GL_FLOAT, false},         // kVec4f_GrVertexAttribType
+    {4, GR_GL_UNSIGNED_BYTE, true},  // kVec4ub_GrVertexAttribType
+};
+
 void GrGLProgram::BuildDesc(const GrDrawState& drawState,
                             bool isPoints,
                             GrDrawState::BlendOptFlags blendOpts,
@@ -52,24 +60,24 @@
                                            GrDrawState::kEmitCoverage_BlendOptFlag));
 
     // The descriptor is used as a cache key. Thus when a field of the
-    // descriptor will not affect program generation (because of the vertex
-    // layout in use or other descriptor field settings) it should be set
+    // descriptor will not affect program generation (because of the attribute
+    // 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->fVertexLayout = drawState.getVertexLayout();
+    desc->fAttribBindings = drawState.getAttribBindings();
 
     desc->fEmitsPointSize = isPoints;
 
     bool requiresAttributeColors = !skipColor &&
-                                   SkToBool(desc->fVertexLayout & GrDrawState::kColor_VertexLayoutBit);
+                                   SkToBool(desc->fAttribBindings & GrDrawState::kColor_AttribBindingsBit);
     bool requiresAttributeCoverage = !skipCoverage &&
-                                     SkToBool(desc->fVertexLayout & GrDrawState::kCoverage_VertexLayoutBit);
+                                     SkToBool(desc->fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit);
 
     // fColorInput/fCoverageInput records how colors are specified for the program So we strip the
-    // bits from the layout to avoid false negatives when searching for an existing program in the
+    // bits from the bindings to avoid false negatives when searching for an existing program in the
     // cache.
-    desc->fVertexLayout &= ~(GrDrawState::kColor_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit);
+    desc->fAttribBindings &= ~(GrDrawState::kColor_AttribBindingsBit | GrDrawState::kCoverage_AttribBindingsBit);
 
     desc->fColorFilterXfermode = skipColor ?
                                 SkXfermode::kDst_Mode :
@@ -77,8 +85,8 @@
 
     // no reason to do edge aa or look at per-vertex coverage if coverage is ignored
     if (skipCoverage) {
-        desc->fVertexLayout &= ~(GrDrawState::kEdge_VertexLayoutBit |
-                                 GrDrawState::kCoverage_VertexLayoutBit);
+        desc->fAttribBindings &= ~(GrDrawState::kEdge_AttribBindingsBit |
+                                   GrDrawState::kCoverage_AttribBindingsBit);
     }
 
     bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
@@ -108,7 +116,7 @@
 
     int lastEnabledStage = -1;
 
-    if (!skipCoverage && (desc->fVertexLayout & GrDrawState::kEdge_VertexLayoutBit)) {
+    if (!skipCoverage && (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit)) {
         desc->fVertexEdgeType = drawState.getVertexEdgeType();
         desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
     } else {
@@ -155,7 +163,7 @@
     // other coverage inputs
     if (!hasCoverage) {
         hasCoverage = requiresAttributeCoverage ||
-                      (desc->fVertexLayout & GrDrawState::kEdge_VertexLayoutBit);
+                      (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit);
     }
 
     if (hasCoverage) {
@@ -182,6 +190,43 @@
             }
         }
     }
+
+    desc->fPositionAttributeIndex = drawState.getAttribIndex(GrDrawState::kPosition_AttribIndex);
+    if (requiresAttributeColors) {
+        desc->fColorAttributeIndex = drawState.getAttribIndex(GrDrawState::kColor_AttribIndex);
+    } else {
+        desc->fColorAttributeIndex = GrDrawState::kColorOverrideAttribIndexValue;
+    } 
+    if (requiresAttributeCoverage) {
+        desc->fCoverageAttributeIndex = drawState.getAttribIndex(GrDrawState::kCoverage_AttribIndex);
+    } else {
+        desc->fCoverageAttributeIndex = GrDrawState::kCoverageOverrideAttribIndexValue;
+    }
+    desc->fEdgeAttributeIndex     = drawState.getAttribIndex(GrDrawState::kEdge_AttribIndex);
+    desc->fTexCoordAttributeIndex = drawState.getAttribIndex(GrDrawState::kTexCoord_AttribIndex);
+
+#if GR_DEBUG
+    // verify valid vertex attribute state
+    const GrVertexAttrib* vertexAttribs = drawState.getVertexAttribs();
+    GrAssert(desc->fPositionAttributeIndex < GrDrawState::kVertexAttribCnt);
+    GrAssert(kAttribLayouts[vertexAttribs[desc->fPositionAttributeIndex].fType].fCount == 2);
+    if (requiresAttributeColors) {
+        GrAssert(desc->fColorAttributeIndex < GrDrawState::kVertexAttribCnt);
+        GrAssert(kAttribLayouts[vertexAttribs[desc->fColorAttributeIndex].fType].fCount == 4);
+    }
+    if (requiresAttributeCoverage) {
+        GrAssert(desc->fCoverageAttributeIndex < GrDrawState::kVertexAttribCnt);
+        GrAssert(kAttribLayouts[vertexAttribs[desc->fCoverageAttributeIndex].fType].fCount == 4);
+    }
+    if (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
+        GrAssert(desc->fEdgeAttributeIndex < GrDrawState::kVertexAttribCnt);
+        GrAssert(kAttribLayouts[vertexAttribs[desc->fEdgeAttributeIndex].fType].fCount == 4);
+     }
+    if (GrDrawState::AttributesBindExplicitTexCoords(desc->fAttribBindings)) {
+        GrAssert(desc->fTexCoordAttributeIndex < GrDrawState::kVertexAttribCnt);
+        GrAssert(kAttribLayouts[vertexAttribs[desc->fTexCoordAttributeIndex].fType].fCount == 2);
+    }
+#endif
 }
 
 GrGLProgram* GrGLProgram::Create(const GrGLContext& gl,
@@ -366,7 +411,7 @@
 
 bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
                                   GrGLShaderBuilder* builder) const {
-    if (fDesc.fVertexLayout & GrDrawState::kEdge_VertexLayoutBit) {
+    if (fDesc.fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
         const char *vsName, *fsName;
         builder->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName);
         builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
@@ -645,7 +690,7 @@
     GrAssert(0 == fProgramID);
 
     GrGLShaderBuilder builder(fContext.info(), fUniformManager);
-    const uint32_t& layout = fDesc.fVertexLayout;
+    const GrAttribBindings& attribBindings = fDesc.fAttribBindings;
 
 #if GR_GL_EXPERIMENTAL_GS
     builder.fUsesGS = fDesc.fExperimentalGS;
@@ -726,7 +771,7 @@
     }
 
     // add texture coordinates that are used to the list of vertex attr decls
-    if (GrDrawState::VertexUsesTexCoords(layout)) {
+    if (GrDrawState::AttributesBindExplicitTexCoords(attribBindings)) {
         builder.fVSAttrs.push_back().set(kVec2f_GrSLType,
             GrGLShaderVar::kAttribute_TypeModifier,
             TEX_ATTR_NAME);
@@ -748,7 +793,7 @@
 
                 const char* inCoords;
                 // figure out what our input coords are
-                if (!GrDrawState::StageUsesTexCoords(layout, s)) {
+                if (!GrDrawState::StageBindsExplicitTexCoords(attribBindings, s)) {
                     inCoords = builder.positionAttribute().c_str();
                 } else {
                     // must have input tex coordinates if stage is enabled.
@@ -842,7 +887,7 @@
 
                     const char* inCoords;
                     // figure out what our input coords are
-                    if (!GrDrawState::StageUsesTexCoords(layout, s)) {
+                    if (!GrDrawState::StageBindsExplicitTexCoords(attribBindings, s)) {
                         inCoords = builder.positionAttribute().c_str();
                     } else {
                         // must have input tex coordinates if stage is
@@ -966,13 +1011,18 @@
 
     // Bind the attrib locations to same values for all shaders
     GL_CALL(BindAttribLocation(fProgramID,
-                               kPositionAttributeIndex,
+                               fDesc.fPositionAttributeIndex,
                                builder.positionAttribute().c_str()));
-    GL_CALL(BindAttribLocation(fProgramID, kTexCoordAttributeIndex, TEX_ATTR_NAME));
-    GL_CALL(BindAttribLocation(fProgramID, kColorAttributeIndex, COL_ATTR_NAME));
-    GL_CALL(BindAttribLocation(fProgramID, kCoverageAttributeIndex, COV_ATTR_NAME));
-    GL_CALL(BindAttribLocation(fProgramID, kEdgeAttributeIndex, EDGE_ATTR_NAME));
-
+    GL_CALL(BindAttribLocation(fProgramID, fDesc.fColorAttributeIndex, COL_ATTR_NAME));
+    GL_CALL(BindAttribLocation(fProgramID, fDesc.fCoverageAttributeIndex, COV_ATTR_NAME));
+ 
+    if (fDesc.fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
+        GL_CALL(BindAttribLocation(fProgramID, fDesc.fEdgeAttributeIndex, EDGE_ATTR_NAME));
+    }
+    if (GrDrawState::AttributesBindExplicitTexCoords(fDesc.fAttribBindings)) {
+        GL_CALL(BindAttribLocation(fProgramID, fDesc.fTexCoordAttributeIndex, TEX_ATTR_NAME));
+    }
+    
     GL_CALL(LinkProgram(fProgramID));
 
     GrGLint linked = GR_GL_INIT_ZERO;
@@ -1060,14 +1110,14 @@
 void GrGLProgram::setColor(const GrDrawState& drawState,
                            GrColor color,
                            SharedGLState* sharedState) {
-    if (!(drawState.getVertexLayout() & GrDrawState::kColor_VertexLayoutBit)) {
+    if (!(drawState.getAttribBindings() & GrDrawState::kColor_AttribBindingsBit)) {
         switch (fDesc.fColorInput) {
             case GrGLProgram::Desc::kAttribute_ColorInput:
                 if (sharedState->fConstAttribColor != color) {
                     // OpenGL ES only supports the float varieties of glVertexAttrib
                     GrGLfloat c[4];
                     GrColorToRGBAFloat(color, c);
-                    GL_CALL(VertexAttrib4fv(kColorAttributeIndex, c));
+                    GL_CALL(VertexAttrib4fv(fDesc.fColorAttributeIndex, c));
                     sharedState->fConstAttribColor = color;
                 }
                 break;
@@ -1094,14 +1144,14 @@
 void GrGLProgram::setCoverage(const GrDrawState& drawState,
                               GrColor coverage,
                               SharedGLState* sharedState) {
-    if (!(drawState.getVertexLayout() & GrDrawState::kCoverage_VertexLayoutBit)) {
+    if (!(drawState.getAttribBindings() & GrDrawState::kCoverage_AttribBindingsBit)) {
         switch (fDesc.fCoverageInput) {
             case Desc::kAttribute_ColorInput:
                 if (sharedState->fConstAttribCoverage != coverage) {
                     // OpenGL ES only supports the float varieties of  glVertexAttrib
                     GrGLfloat c[4];
                     GrColorToRGBAFloat(coverage, c);
-                    GL_CALL(VertexAttrib4fv(kCoverageAttributeIndex, c));
+                    GL_CALL(VertexAttrib4fv(fDesc.fCoverageAttributeIndex, c));
                     sharedState->fConstAttribCoverage = coverage;
                 }
                 break;
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index a2958e7..cde918b 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -79,17 +79,6 @@
     GrGLuint programID() const { return fProgramID; }
 
     /**
-     * Attribute indices. These should not overlap.
-     */
-    enum {
-        kPositionAttributeIndex = 0,
-        kColorAttributeIndex = 1,
-        kCoverageAttributeIndex = 2,
-        kEdgeAttributeIndex = 3,
-        kTexCoordAttributeIndex = 4,
-    };
-
-    /**
      * 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.
@@ -182,7 +171,7 @@
         bool                        fDiscardIfOutsideEdge;
 
         // stripped of bits that don't affect program generation
-        GrVertexLayout              fVertexLayout;
+        GrAttribBindings            fAttribBindings;
 
         /** Non-zero if this stage has an effect */
         GrGLEffect::EffectKey       fEffectKeys[GrDrawState::kNumStages];
@@ -199,9 +188,23 @@
         SkBool8                     fEmitsPointSize;
         uint8_t                     fColorFilterXfermode;   // casts to enum SkXfermode::Mode
 
+        int8_t                      fPositionAttributeIndex;
+        int8_t                      fColorAttributeIndex;
+        int8_t                      fCoverageAttributeIndex;
+        int8_t                      fEdgeAttributeIndex;
+        int8_t                      fTexCoordAttributeIndex;
+
         friend class GrGLProgram;
     };
 
+    // Layout information for OpenGL vertex attributes
+    struct AttribLayout {
+        GrGLint     fCount;
+        GrGLenum    fType;
+        GrGLboolean fNormalized;
+    };
+    static const AttribLayout kAttribLayouts[kGrVertexAttribTypeCount];
+
 private:
     GrGLProgram(const GrGLContext& gl,
                 const Desc& desc,
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index f9c94c4..42e83b0 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -182,6 +182,10 @@
 
     fHWGeometryState.setMaxAttribArrays(this->glCaps().maxVertexAttributes());
 
+    GrAssert(this->glCaps().maxVertexAttributes() >= GrDrawState::kVertexAttribCnt);
+    GrAssert(this->glCaps().maxVertexAttributes() > GrDrawState::kColorOverrideAttribIndexValue);
+    GrAssert(this->glCaps().maxVertexAttributes() > GrDrawState::kCoverageOverrideAttribIndexValue);
+
     fLastSuccessfulStencilFmtIdx = 0;
     if (false) { // avoid bit rot, suppress warning
         fbo_test(this->glInterface(), 0, 0);
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 93af1b9..e5a7183 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -215,83 +215,30 @@
 
 void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) {
 
-    int colorOffset;
-    int coverageOffset;
-    int texCoordOffset;
-    int edgeOffset;
-
-    GrVertexLayout currLayout = this->getDrawState().getVertexLayout();
-
-    GrGLsizei stride = GrDrawState::VertexSizeAndOffsets(currLayout,
-                                                         &texCoordOffset,
-                                                         &colorOffset,
-                                                         &coverageOffset,
-                                                         &edgeOffset);
+    GrGLsizei stride = this->getDrawState().getVertexSize();
 
     size_t vertexOffset;
     GrGLVertexBuffer* vb= this->setBuffers(info.isIndexed(), &vertexOffset, indexOffsetInBytes);
     vertexOffset += stride * info.startVertex();
 
-    uint32_t usedAttribArraysMask = (1 << GrGLProgram::kPositionAttributeIndex);
-    fHWGeometryState.setAttribArray(this,
-                                    GrGLProgram::kPositionAttributeIndex,
-                                    vb,
-                                    2,
-                                    GR_GL_FLOAT,
-                                    false,
-                                    stride,
-                                    reinterpret_cast<GrGLvoid*>(vertexOffset));
-    if (texCoordOffset > 0) {
-        usedAttribArraysMask |= (1 << GrGLProgram::kTexCoordAttributeIndex);
-        GrGLvoid* texCoordPtr = reinterpret_cast<GrGLvoid*>(vertexOffset + texCoordOffset);
-        fHWGeometryState.setAttribArray(this,
-                                        GrGLProgram::kTexCoordAttributeIndex,
-                                        vb,
-                                        2,
-                                        GR_GL_FLOAT,
-                                        false,
-                                        stride,
-                                        texCoordPtr);
-    }
+    uint32_t usedAttribArraysMask = 0;
+    const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs();
+    int vertexAttribCount = this->getDrawState().getVertexAttribCount();
+    for (int vertexAttribIndex = 0; vertexAttribIndex < vertexAttribCount; 
+         ++vertexAttribIndex, ++vertexAttrib) {
 
-    if (colorOffset > 0) {
-        usedAttribArraysMask |= (1 << GrGLProgram::kColorAttributeIndex);
-        GrGLvoid* colorPtr = reinterpret_cast<GrGLvoid*>(vertexOffset + colorOffset);
+        usedAttribArraysMask |= (1 << vertexAttribIndex);
+        GrVertexAttribType attribType = vertexAttrib->fType;
         fHWGeometryState.setAttribArray(this,
-                                        GrGLProgram::kColorAttributeIndex,
+                                        vertexAttribIndex,
                                         vb,
-                                        4,
-                                        GR_GL_UNSIGNED_BYTE,
-                                        true,
+                                        GrGLProgram::kAttribLayouts[attribType].fCount,
+                                        GrGLProgram::kAttribLayouts[attribType].fType,
+                                        GrGLProgram::kAttribLayouts[attribType].fNormalized,
                                         stride,
-                                        colorPtr);
-    }
-
-    if (coverageOffset > 0) {
-        usedAttribArraysMask |= (1 << GrGLProgram::kCoverageAttributeIndex);
-        GrGLvoid* coveragePtr = reinterpret_cast<GrGLvoid*>(vertexOffset + coverageOffset);
-        fHWGeometryState.setAttribArray(this,
-                                        GrGLProgram::kCoverageAttributeIndex,
-                                        vb,
-                                        4,
-                                        GR_GL_UNSIGNED_BYTE,
-                                        true,
-                                        stride,
-                                        coveragePtr);
-    }
-
-    if (edgeOffset > 0) {
-        usedAttribArraysMask |= (1 << GrGLProgram::kEdgeAttributeIndex);
-        GrGLvoid* edgePtr = reinterpret_cast<GrGLvoid*>(vertexOffset + edgeOffset);
-        fHWGeometryState.setAttribArray(this,
-                                        GrGLProgram::kEdgeAttributeIndex,
-                                        vb,
-                                        4,
-                                        GR_GL_FLOAT,
-                                        false,
-                                        stride,
-                                        edgePtr);
-    }
+                                        reinterpret_cast<GrGLvoid*>(
+                                         vertexOffset + vertexAttrib->fOffset));
+     }
 
     fHWGeometryState.disableUnusedAttribArrays(this, usedAttribArraysMask);
 }
diff --git a/src/gpu/gr_unittests.cpp b/src/gpu/gr_unittests.cpp
index 7f5c7e9..c7daf77 100644
--- a/src/gpu/gr_unittests.cpp
+++ b/src/gpu/gr_unittests.cpp
@@ -75,5 +75,5 @@
     test_bsearch();
     test_binHashKey();
     GrRedBlackTree<int>::UnitTest();
-    GrDrawState::VertexLayoutUnitTest();
+    GrDrawState::VertexAttributesUnitTest();
 }
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index bc148f1..45c5f2d 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -23,7 +23,7 @@
 void GrGLProgram::Desc::setRandom(SkMWCRandom* random,
                                   const GrGpuGL* gpu,
                                   const GrEffectStage stages[GrDrawState::kNumStages]) {
-    fVertexLayout = 0;
+    fAttribBindings = 0;
     fEmitsPointSize = random->nextBool();
     fColorInput = random->nextULessThan(kColorInputCnt);
     fCoverageInput = random->nextULessThan(kColorInputCnt);
@@ -32,7 +32,7 @@
 
     fFirstCoverageStage = random->nextULessThan(GrDrawState::kNumStages);
 
-    fVertexLayout |= random->nextBool() ? GrDrawState::kCoverage_VertexLayoutBit : 0;
+    fAttribBindings |= random->nextBool() ? GrDrawState::kCoverage_AttribBindingsBit : 0;
 
 #if GR_GL_EXPERIMENTAL_GS
     fExperimentalGS = gpu->getCaps().geometryShaderSupport() && random->nextBool();
@@ -40,7 +40,7 @@
 
     bool edgeAA = random->nextBool();
     if (edgeAA) {
-        fVertexLayout |= GrDrawState::kEdge_VertexLayoutBit;
+        fAttribBindings |= GrDrawState::kEdge_AttribBindingsBit;
         if (gpu->getCaps().shaderDerivativeSupport()) {
             fVertexEdgeType = (GrDrawState::VertexEdgeType)
                               random->nextULessThan(GrDrawState::kVertexEdgeTypeCnt);
@@ -64,11 +64,31 @@
             fEffectKeys[s] = factory.glEffectKey(stages[s], gpu->glCaps());
             // use separate tex coords?
             if (!useOnce && random->nextBool()) {
-                fVertexLayout |= GrDrawState::StageTexCoordVertexLayoutBit(s);
+                fAttribBindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(s);
                 useOnce = true;
             }
         }
     }
+
+    int attributeIndex = 0;
+    fPositionAttributeIndex = attributeIndex;
+    ++attributeIndex;
+    if (fColorInput || (fAttribBindings & GrDrawState::kColor_AttribBindingsBit)) {
+        fColorAttributeIndex = attributeIndex;
+        ++attributeIndex;
+    }
+    if (fCoverageInput || (fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit)) {
+        fCoverageAttributeIndex = attributeIndex;
+        ++attributeIndex;
+    }
+    if (fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
+        fEdgeAttributeIndex = attributeIndex;
+        ++attributeIndex;
+    }
+    if (GrDrawState::AttributesBindExplicitTexCoords(fAttribBindings)) {
+        fTexCoordAttributeIndex = attributeIndex;
+        ++attributeIndex;
+    }
 }
 
 bool GrGpuGL::programUnitTest(int maxStages) {