Use vertexless shaders when NVpr is available

Adds support for vertexless shaders and enables them when
NV_path_rendering is available. This takes a
GrGLFragmentOnlyShaderBuilder class, a GrGLTexGenEffectArray class,
support for setting TexGen and the projection matrix in GrGpuGL, and
code for setting the GL fixed function state where necessary.

R=bsalomon@google.com, kkinnunen@nvidia.com

Author: cdalton@nvidia.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11620 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp
index d5826ab..17c666a 100644
--- a/src/gpu/gl/GrGLProgramEffects.cpp
+++ b/src/gpu/gl/GrGLProgramEffects.cpp
@@ -37,7 +37,6 @@
     kMatrixTypeKeyMask   = (1 << kMatrixTypeKeyBits) - 1,
     kPositionCoords_Flag = (1 << kMatrixTypeKeyBits),
     kTransformKeyBits    = kMatrixTypeKeyBits + 1,
-    kTransformKeyMask    = (1 << kTransformKeyBits) - 1,
 };
 
 namespace {
@@ -69,8 +68,78 @@
     return false;
 }
 
+/**
+ * Retrieves the matrix type from transformKey for the transform at transformIdx.
+ */
+MatrixType get_matrix_type(EffectKey transformKey, int transformIdx) {
+    return static_cast<MatrixType>(
+               (transformKey >> (kTransformKeyBits * transformIdx)) & kMatrixTypeKeyMask);
 }
 
+/**
+ * Retrieves the source coords from transformKey for the transform at transformIdx. It may not be
+ * the same coordinate set as the original GrCoordTransform if the position and local coords are
+ * identical for this program.
+ */
+GrCoordSet get_source_coords(EffectKey transformKey, int transformIdx) {
+    return (transformKey >> (kTransformKeyBits * transformIdx)) & kPositionCoords_Flag ?
+               kPosition_GrCoordSet :
+               kLocal_GrCoordSet;
+}
+
+/**
+ * Retrieves the final translation that a transform needs to apply to its source coords (and
+ * verifies that a translation is all it needs).
+ */
+void get_transform_translation(const GrDrawEffect& drawEffect,
+                               int transformIdx,
+                               GrGLfloat* tx,
+                               GrGLfloat* ty) {
+    const GrCoordTransform& coordTransform = (*drawEffect.effect())->coordTransform(transformIdx);
+    SkASSERT(!coordTransform.reverseY());
+    const SkMatrix& matrix = coordTransform.getMatrix();
+    if (kLocal_GrCoordSet == coordTransform.sourceCoords() &&
+        !drawEffect.programHasExplicitLocalCoords()) {
+        const SkMatrix& coordChangeMatrix = drawEffect.getCoordChangeMatrix();
+        SkASSERT(SkMatrix::kTranslate_Mask == (matrix.getType() | coordChangeMatrix.getType()));
+        *tx = SkScalarToFloat(matrix[SkMatrix::kMTransX] + coordChangeMatrix[SkMatrix::kMTransX]);
+        *ty = SkScalarToFloat(matrix[SkMatrix::kMTransY] + coordChangeMatrix[SkMatrix::kMTransY]);
+    } else {
+        SkASSERT(SkMatrix::kTranslate_Mask == matrix.getType());
+        *tx = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
+        *ty = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
+    }
+}
+
+/**
+ * Retrieves the final matrix that a transform needs to apply to its source coords.
+ */
+SkMatrix get_transform_matrix(const GrDrawEffect& drawEffect, int transformIdx) {
+    const GrCoordTransform& coordTransform = (*drawEffect.effect())->coordTransform(transformIdx);
+    SkMatrix combined;
+    if (kLocal_GrCoordSet == coordTransform.sourceCoords() &&
+        !drawEffect.programHasExplicitLocalCoords()) {
+        combined.setConcat(coordTransform.getMatrix(), drawEffect.getCoordChangeMatrix());
+    } else {
+        combined = coordTransform.getMatrix();
+    }
+    if (coordTransform.reverseY()) {
+        // combined.postScale(1,-1);
+        // combined.postTranslate(0,1);
+        combined.set(SkMatrix::kMSkewY,
+            combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
+        combined.set(SkMatrix::kMScaleY,
+            combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
+        combined.set(SkMatrix::kMTransY,
+            combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
+    }
+    return combined;
+}
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 EffectKey GrGLProgramEffects::GenAttribKey(const GrDrawEffect& drawEffect) {
     EffectKey key = 0;
     int numAttributes = drawEffect.getVertexAttribIndexCount();
@@ -144,6 +213,23 @@
     }
 }
 
+void GrGLProgramEffects::emitSamplers(GrGLShaderBuilder* builder,
+                                      const GrEffectRef& effect,
+                                      TextureSamplerArray* outSamplers) {
+    SkTArray<Sampler, true>& samplers = fSamplers.push_back();
+    int numTextures = effect->numTextures();
+    samplers.push_back_n(numTextures);
+    SkString name;
+    for (int t = 0; t < numTextures; ++t) {
+        name.printf("Sampler%d", t);
+        samplers[t].fUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                                   kSampler2D_GrSLType,
+                                                   name.c_str());
+        SkNEW_APPEND_TO_TARRAY(outSamplers, TextureSampler,
+                               (samplers[t].fUniform, effect->textureAccess(t)));
+    }
+}
+
 void GrGLProgramEffects::initSamplers(const GrGLUniformManager& uniformManager, int* texUnitIdx) {
     int numEffects = fGLEffects.count();
     SkASSERT(numEffects == fSamplers.count());
@@ -158,77 +244,6 @@
     }
 }
 
-void GrGLVertexProgramEffects::setData(GrGpuGL* gpu,
-                                       const GrGLUniformManager& uniformManager,
-                                       const GrEffectStage* effectStages[]) {
-    int numEffects = fGLEffects.count();
-    SkASSERT(numEffects == fTransforms.count());
-    SkASSERT(numEffects == fSamplers.count());
-    for (int e = 0; e < numEffects; ++e) {
-        GrDrawEffect drawEffect(*effectStages[e], fHasExplicitLocalCoords);
-        fGLEffects[e]->setData(uniformManager, drawEffect);
-        this->setTransformData(uniformManager, drawEffect, e);
-        this->bindTextures(gpu, *drawEffect.effect(), e);
-    }
-}
-
-void GrGLVertexProgramEffects::setTransformData(const GrGLUniformManager& uniformManager,
-                                                const GrDrawEffect& drawEffect,
-                                                int effectIdx) {
-    SkTArray<Transform, true>& transforms = fTransforms[effectIdx];
-    int numTransforms = transforms.count();
-    SkASSERT(numTransforms == (*drawEffect.effect())->numTransforms());
-    for (int t = 0; t < numTransforms; ++t) {
-        const GrCoordTransform& coordTransform = (*drawEffect.effect())->coordTransform(t);
-        const SkMatrix& matrix = coordTransform.getMatrix();
-        const SkMatrix& coordChangeMatrix = kLocal_GrCoordSet == coordTransform.sourceCoords() ?
-                                                drawEffect.getCoordChangeMatrix() :
-                                                SkMatrix::I();
-        SkASSERT(transforms[t].fHandle.isValid() != (kVoid_GrSLType == transforms[t].fType));
-        switch (transforms[t].fType) {
-            case kVoid_GrSLType:
-                SkASSERT(matrix.isIdentity());
-                SkASSERT(coordChangeMatrix.isIdentity());
-                SkASSERT(!coordTransform.reverseY());
-                return;
-            case kVec2f_GrSLType: {
-                SkASSERT(SkMatrix::kTranslate_Mask == (matrix.getType() | coordChangeMatrix.getType()));
-                SkASSERT(!coordTransform.reverseY());
-                SkScalar tx = matrix[SkMatrix::kMTransX] + (coordChangeMatrix)[SkMatrix::kMTransX];
-                SkScalar ty = matrix[SkMatrix::kMTransY] + (coordChangeMatrix)[SkMatrix::kMTransY];
-                if (transforms[t].fCurrentValue.get(SkMatrix::kMTransX) != tx ||
-                    transforms[t].fCurrentValue.get(SkMatrix::kMTransY) != ty) {
-                    uniformManager.set2f(transforms[t].fHandle, tx, ty);
-                    transforms[t].fCurrentValue.set(SkMatrix::kMTransX, tx);
-                    transforms[t].fCurrentValue.set(SkMatrix::kMTransY, ty);
-                }
-                break;
-            }
-            case kMat33f_GrSLType: {
-                SkMatrix combined;
-                combined.setConcat(matrix, coordChangeMatrix);
-                if (coordTransform.reverseY()) {
-                    // combined.postScale(1,-1);
-                    // combined.postTranslate(0,1);
-                    combined.set(SkMatrix::kMSkewY,
-                        combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
-                    combined.set(SkMatrix::kMScaleY,
-                        combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
-                    combined.set(SkMatrix::kMTransY,
-                        combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
-                }
-                if (!transforms[t].fCurrentValue.cheapEqualTo(combined)) {
-                    uniformManager.setSkMatrix(transforms[t].fHandle, combined);
-                    transforms[t].fCurrentValue = combined;
-                }
-                break;
-            }
-            default:
-                GrCrash("Unexpected uniform type.");
-        }
-    }
-}
-
 void GrGLProgramEffects::bindTextures(GrGpuGL* gpu, const GrEffectRef& effect, int effectIdx) {
     const SkTArray<Sampler, true>& samplers = fSamplers[effectIdx];
     int numSamplers = samplers.count();
@@ -244,75 +259,67 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder* builder,
-                                                                 int reserveCount)
-    : fBuilder(builder)
-    , fProgramEffects(SkNEW_ARGS(GrGLVertexProgramEffects,
-                                 (reserveCount, fBuilder->hasExplicitLocalCoords()))) {
-}
-
-void GrGLVertexProgramEffectsBuilder::emitEffect(const GrEffectStage& stage,
-                                                 EffectKey key,
-                                                 const char* outColor,
-                                                 const char* inColor,
-                                                 int stageIndex) {
-    SkASSERT(NULL != fProgramEffects.get());
-
-    GrDrawEffect drawEffect(stage, fProgramEffects->fHasExplicitLocalCoords);
+void GrGLVertexProgramEffects::emitEffect(GrGLFullShaderBuilder* builder,
+                                          const GrEffectStage& stage,
+                                          EffectKey key,
+                                          const char* outColor,
+                                          const char* inColor,
+                                          int stageIndex) {
+    GrDrawEffect drawEffect(stage, fHasExplicitLocalCoords);
     const GrEffectRef& effect = *stage.getEffect();
     SkSTArray<2, TransformedCoords> coords(effect->numTransforms());
     SkSTArray<4, TextureSampler> samplers(effect->numTextures());
 
-    this->emitAttributes(stage);
-    this->emitTransforms(effect, key, &coords);
-    INHERITED::emitSamplers(fBuilder, fProgramEffects.get(), effect, &samplers);
+    this->emitAttributes(builder, stage);
+    this->emitTransforms(builder, effect, key, &coords);
+    this->emitSamplers(builder, effect, &samplers);
 
     GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
-    fProgramEffects->fGLEffects.push_back(glEffect);
+    fGLEffects.push_back(glEffect);
 
     // Enclose custom code in a block to avoid namespace conflicts
     SkString openBrace;
     openBrace.printf("\t{ // Stage %d: %s\n", stageIndex, glEffect->name());
-    fBuilder->vsCodeAppend(openBrace.c_str());
-    fBuilder->fsCodeAppend(openBrace.c_str());
+    builder->vsCodeAppend(openBrace.c_str());
+    builder->fsCodeAppend(openBrace.c_str());
 
     if (glEffect->isVertexEffect()) {
         GrGLVertexEffect* vertexEffect = static_cast<GrGLVertexEffect*>(glEffect);
-        vertexEffect->emitCode(fBuilder, drawEffect, key, outColor, inColor, coords, samplers);
+        vertexEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers);
     } else {
-        glEffect->emitCode(fBuilder, drawEffect, key, outColor, inColor, coords, samplers);
+        glEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers);
     }
 
-    fBuilder->vsCodeAppend("\t}\n");
-    fBuilder->fsCodeAppend("\t}\n");
+    builder->vsCodeAppend("\t}\n");
+    builder->fsCodeAppend("\t}\n");
 }
 
-void GrGLVertexProgramEffectsBuilder::emitAttributes(const GrEffectStage& stage) {
+void GrGLVertexProgramEffects::emitAttributes(GrGLFullShaderBuilder* builder,
+                                              const GrEffectStage& stage) {
     int numAttributes = stage.getVertexAttribIndexCount();
     const int* attributeIndices = stage.getVertexAttribIndices();
     for (int a = 0; a < numAttributes; ++a) {
         // TODO: Make addAttribute mangle the name.
         SkString attributeName("aAttr");
         attributeName.appendS32(attributeIndices[a]);
-        fBuilder->addEffectAttribute(attributeIndices[a],
-                                     (*stage.getEffect())->vertexAttribType(a),
-                                     attributeName);
+        builder->addEffectAttribute(attributeIndices[a],
+                                    (*stage.getEffect())->vertexAttribType(a),
+                                    attributeName);
     }
 }
 
-void GrGLVertexProgramEffectsBuilder::emitTransforms(const GrEffectRef& effect,
-                                                     EffectKey effectKey,
-                                                     TransformedCoordsArray* outCoords) {
-    typedef GrGLVertexProgramEffects::Transform Transform;
-    SkTArray<Transform, true>& transforms = fProgramEffects->fTransforms.push_back();
+void GrGLVertexProgramEffects::emitTransforms(GrGLFullShaderBuilder* builder,
+                                              const GrEffectRef& effect,
+                                              EffectKey effectKey,
+                                              TransformedCoordsArray* outCoords) {
+    SkTArray<Transform, true>& transforms = fTransforms.push_back();
     EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey);
     int numTransforms = effect->numTransforms();
     transforms.push_back_n(numTransforms);
     for (int t = 0; t < numTransforms; t++) {
-        EffectKey key = (totalKey >> (kTransformKeyBits * t)) & kTransformKeyMask;
         GrSLType varyingType = kVoid_GrSLType;
         const char* uniName;
-        switch (key & kMatrixTypeKeyMask) {
+        switch (get_matrix_type(totalKey, t)) {
             case kIdentity_MatrixType:
                 transforms[t].fType = kVoid_GrSLType;
                 uniName = NULL;
@@ -343,10 +350,10 @@
                 suffixedUniName.appendf("_%i", t);
                 uniName = suffixedUniName.c_str();
             }
-            transforms[t].fHandle = fBuilder->addUniform(GrGLShaderBuilder::kVertex_Visibility,
-                                                         transforms[t].fType,
-                                                         uniName,
-                                                         &uniName);
+            transforms[t].fHandle = builder->addUniform(GrGLShaderBuilder::kVertex_Visibility,
+                                                        transforms[t].fType,
+                                                        uniName,
+                                                        &uniName);
         }
 
         const char* varyingName = "MatrixCoord";
@@ -358,55 +365,222 @@
         }
         const char* vsVaryingName;
         const char* fsVaryingName;
-        fBuilder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
+        builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
 
-        const GrGLShaderVar& coords = (kPositionCoords_Flag & key) ?
-                                          fBuilder->positionAttribute() :
-                                          fBuilder->localCoordsAttribute();
+        const GrGLShaderVar& coords = kPosition_GrCoordSet == get_source_coords(totalKey, t) ?
+                                          builder->positionAttribute() :
+                                          builder->localCoordsAttribute();
         // varying = matrix * coords (logically)
         switch (transforms[t].fType) {
             case kVoid_GrSLType:
                 SkASSERT(kVec2f_GrSLType == varyingType);
-                fBuilder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, coords.c_str());
+                builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, coords.c_str());
                 break;
             case kVec2f_GrSLType:
                 SkASSERT(kVec2f_GrSLType == varyingType);
-                fBuilder->vsCodeAppendf("\t%s = %s + %s;\n",
-                                        vsVaryingName, uniName, coords.c_str());
+                builder->vsCodeAppendf("\t%s = %s + %s;\n",
+                                       vsVaryingName, uniName, coords.c_str());
                 break;
             case kMat33f_GrSLType: {
                 SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
                 if (kVec2f_GrSLType == varyingType) {
-                    fBuilder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
-                                            vsVaryingName, uniName, coords.c_str());
+                    builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
+                                           vsVaryingName, uniName, coords.c_str());
                 } else {
-                    fBuilder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
-                                            vsVaryingName, uniName, coords.c_str());
+                    builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
+                                           vsVaryingName, uniName, coords.c_str());
                 }
                 break;
             }
             default:
                 GrCrash("Unexpected uniform type.");
         }
-        SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (fsVaryingName, varyingType));
+        SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords,
+                               (SkString(fsVaryingName), varyingType));
     }
 }
 
-void GrGLProgramEffectsBuilder::emitSamplers(GrGLShaderBuilder* builder,
-                                             GrGLProgramEffects* programEffects,
-                                             const GrEffectRef& effect,
-                                             TextureSamplerArray* outSamplers) {
-    typedef GrGLProgramEffects::Sampler Sampler;
-    SkTArray<Sampler, true>& samplers = programEffects->fSamplers.push_back();
-    int numTextures = effect->numTextures();
-    samplers.push_back_n(numTextures);
-    SkString name;
-    for (int t = 0; t < numTextures; ++t) {
-        name.printf("Sampler%d", t);
-        samplers[t].fUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                                   kSampler2D_GrSLType,
-                                                   name.c_str());
-        SkNEW_APPEND_TO_TARRAY(outSamplers, TextureSampler,
-                               (samplers[t].fUniform, effect->textureAccess(t)));
+void GrGLVertexProgramEffects::setData(GrGpuGL* gpu,
+                                       const GrGLUniformManager& uniformManager,
+                                       const GrEffectStage* effectStages[]) {
+    int numEffects = fGLEffects.count();
+    SkASSERT(numEffects == fTransforms.count());
+    SkASSERT(numEffects == fSamplers.count());
+    for (int e = 0; e < numEffects; ++e) {
+        GrDrawEffect drawEffect(*effectStages[e], fHasExplicitLocalCoords);
+        fGLEffects[e]->setData(uniformManager, drawEffect);
+        this->setTransformData(uniformManager, drawEffect, e);
+        this->bindTextures(gpu, *drawEffect.effect(), e);
     }
 }
+
+void GrGLVertexProgramEffects::setTransformData(const GrGLUniformManager& uniformManager,
+                                                const GrDrawEffect& drawEffect,
+                                                int effectIdx) {
+    SkTArray<Transform, true>& transforms = fTransforms[effectIdx];
+    int numTransforms = transforms.count();
+    SkASSERT(numTransforms == (*drawEffect.effect())->numTransforms());
+    for (int t = 0; t < numTransforms; ++t) {
+        SkASSERT(transforms[t].fHandle.isValid() != (kVoid_GrSLType == transforms[t].fType));
+        switch (transforms[t].fType) {
+            case kVoid_GrSLType:
+                SkASSERT(get_transform_matrix(drawEffect, t).isIdentity());
+                return;
+            case kVec2f_GrSLType: {
+                GrGLfloat tx, ty;
+                get_transform_translation(drawEffect, t, &tx, &ty);
+                if (transforms[t].fCurrentValue.get(SkMatrix::kMTransX) != tx ||
+                    transforms[t].fCurrentValue.get(SkMatrix::kMTransY) != ty) {
+                    uniformManager.set2f(transforms[t].fHandle, tx, ty);
+                    transforms[t].fCurrentValue.set(SkMatrix::kMTransX, tx);
+                    transforms[t].fCurrentValue.set(SkMatrix::kMTransY, ty);
+                }
+                break;
+            }
+            case kMat33f_GrSLType: {
+                const SkMatrix& matrix = get_transform_matrix(drawEffect, t);
+                if (!transforms[t].fCurrentValue.cheapEqualTo(matrix)) {
+                    uniformManager.setSkMatrix(transforms[t].fHandle, matrix);
+                    transforms[t].fCurrentValue = matrix;
+                }
+                break;
+            }
+            default:
+                GrCrash("Unexpected uniform type.");
+        }
+    }
+}
+
+GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder* builder,
+                                                                 int reserveCount)
+    : fBuilder(builder)
+    , fProgramEffects(SkNEW_ARGS(GrGLVertexProgramEffects,
+                                 (reserveCount, fBuilder->hasExplicitLocalCoords()))) {
+}
+
+void GrGLVertexProgramEffectsBuilder::emitEffect(const GrEffectStage& stage,
+                                                 GrGLProgramEffects::EffectKey key,
+                                                 const char* outColor,
+                                                 const char* inColor,
+                                                 int stageIndex) {
+    SkASSERT(NULL != fProgramEffects.get());
+    fProgramEffects->emitEffect(fBuilder, stage, key, outColor, inColor, stageIndex);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrGLTexGenProgramEffects::emitEffect(GrGLFragmentOnlyShaderBuilder* builder,
+                                          const GrEffectStage& stage,
+                                          EffectKey key,
+                                          const char* outColor,
+                                          const char* inColor,
+                                          int stageIndex) {
+    GrDrawEffect drawEffect(stage, false);
+    const GrEffectRef& effect = *stage.getEffect();
+    SkSTArray<2, TransformedCoords> coords(effect->numTransforms());
+    SkSTArray<4, TextureSampler> samplers(effect->numTextures());
+
+    SkASSERT(0 == stage.getVertexAttribIndexCount());
+    this->setupTexGen(builder, effect, key, &coords);
+    this->emitSamplers(builder, effect, &samplers);
+
+    GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
+    fGLEffects.push_back(glEffect);
+
+    // Enclose custom code in a block to avoid namespace conflicts
+    SkString openBrace;
+    openBrace.printf("\t{ // Stage %d: %s\n", stageIndex, glEffect->name());
+    builder->fsCodeAppend(openBrace.c_str());
+
+    SkASSERT(!glEffect->isVertexEffect());
+    glEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers);
+
+    builder->fsCodeAppend("\t}\n");
+}
+
+void GrGLTexGenProgramEffects::setupTexGen(GrGLFragmentOnlyShaderBuilder* builder,
+                                           const GrEffectRef& effect,
+                                           EffectKey effectKey,
+                                           TransformedCoordsArray* outCoords) {
+    int numTransforms = effect->numTransforms();
+    EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey);
+    int texCoordIndex = builder->addTexCoordSets(numTransforms);
+    SkNEW_APPEND_TO_TARRAY(&fTransforms, Transforms, (totalKey, texCoordIndex));
+    SkString name;
+    for (int t = 0; t < numTransforms; ++t) {
+        GrSLType type = kGeneral_MatrixType == get_matrix_type(totalKey, t) ?
+                            kVec3f_GrSLType :
+                            kVec2f_GrSLType;
+        name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++);
+        SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (name, type));
+    }
+}
+
+void GrGLTexGenProgramEffects::setData(GrGpuGL* gpu,
+                                       const GrGLUniformManager& uniformManager,
+                                       const GrEffectStage* effectStages[]) {
+    int numEffects = fGLEffects.count();
+    SkASSERT(numEffects == fTransforms.count());
+    SkASSERT(numEffects == fSamplers.count());
+    for (int e = 0; e < numEffects; ++e) {
+        GrDrawEffect drawEffect(*effectStages[e], false);
+        fGLEffects[e]->setData(uniformManager, drawEffect);
+        this->setTexGenState(gpu, drawEffect, e);
+        this->bindTextures(gpu, *drawEffect.effect(), e);
+    }
+}
+
+void GrGLTexGenProgramEffects::setTexGenState(GrGpuGL* gpu,
+                                              const GrDrawEffect& drawEffect,
+                                              int effectIdx) {
+    EffectKey totalKey = fTransforms[effectIdx].fTransformKey;
+    int texCoordIndex = fTransforms[effectIdx].fTexCoordIndex;
+    int numTransforms = (*drawEffect.effect())->numTransforms();
+    for (int t = 0; t < numTransforms; ++t) {
+        switch (get_matrix_type(totalKey, t)) {
+            case kIdentity_MatrixType: {
+                SkASSERT(get_transform_matrix(drawEffect, t).isIdentity());
+                GrGLfloat identity[] = {1, 0, 0,
+                                        0, 1, 0};
+                gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, identity);
+                break;
+            }
+            case kTrans_MatrixType: {
+                GrGLfloat tx, ty;
+                get_transform_translation(drawEffect, t, &tx, &ty);
+                GrGLfloat translate[] = {1, 0, tx,
+                                         0, 1, ty};
+                gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, translate);
+                break;
+            }
+            case kNoPersp_MatrixType: {
+                const SkMatrix& transform = get_transform_matrix(drawEffect, t);
+                gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, transform);
+                break;
+            }
+            case kGeneral_MatrixType: {
+                const SkMatrix& transform = get_transform_matrix(drawEffect, t);
+                gpu->enableTexGen(texCoordIndex++, GrGpuGL::kSTR_TexGenComponents, transform);
+                break;
+            }
+            default:
+                GrCrash("Unexpected matrixs type.");
+        }
+    }
+}
+
+GrGLTexGenProgramEffectsBuilder::GrGLTexGenProgramEffectsBuilder(
+        GrGLFragmentOnlyShaderBuilder* builder,
+        int reserveCount)
+    : fBuilder(builder)
+    , fProgramEffects(SkNEW_ARGS(GrGLTexGenProgramEffects, (reserveCount))) {
+}
+
+void GrGLTexGenProgramEffectsBuilder::emitEffect(const GrEffectStage& stage,
+                                                 GrGLProgramEffects::EffectKey key,
+                                                 const char* outColor,
+                                                 const char* inColor,
+                                                 int stageIndex) {
+    SkASSERT(NULL != fProgramEffects.get());
+    fProgramEffects->emitEffect(fBuilder, stage, key, outColor, inColor, stageIndex);
+}