Introduce GrGLShaderBuilder::TextureSampler

Review URL: https://codereview.appspot.com/6495099/



git-svn-id: http://skia.googlecode.com/svn/trunk@5422 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp
index 8257677..94896a8 100644
--- a/src/effects/SkBlendImageFilter.cpp
+++ b/src/effects/SkBlendImageFilter.cpp
@@ -133,7 +133,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     virtual void emitVS(GrGLShaderBuilder* builder,
                         const char* vertexCoords) SK_OVERRIDE {}
@@ -258,12 +258,12 @@
 void GrGLBlendEffect::emitFS(GrGLShaderBuilder* builder,
                              const char* outputColor,
                              const char* inputColor,
-                             const char* samplerName) {
+                             const TextureSamplerArray& samplers) {
     SkString* code = &builder->fFSCode;
     const char* bgColor = inputColor;
     const char* fgColor = "fgColor";
     code->appendf("\t\tvec4 %s = ", fgColor);
-    builder->appendTextureLookup(code, samplerName);
+    builder->appendTextureLookup(code, samplers[0]);
     code->append(";\n");
     code->appendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", outputColor, bgColor, fgColor);
     switch (fMode) {
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 8eb28bb..36bb60b 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -950,7 +950,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
 
@@ -1092,7 +1092,7 @@
 void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
                                 const char* outputColor,
                                 const char* inputColor,
-                                const char* samplerName) {
+                                const TextureSamplerArray& samplers) {
     SkString* code = &builder->fFSCode;
     fLight->emitFuncs(builder);
     SkString lightFunc;
@@ -1160,7 +1160,7 @@
             SkString texCoords;
             texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
             code->appendf("\t\tm[%d] = ", index++);
-            builder->appendTextureLookup(code, samplerName, texCoords.c_str());
+            builder->appendTextureLookup(code, samplers[0], texCoords.c_str());
             code->appendf(".a;\n");
         }
     }
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index 6b8324a..4eed177 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -83,7 +83,7 @@
     virtual void emitFS(GrGLShaderBuilder* state,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     virtual void setData(const GrGLUniformManager& uman,
                          const GrCustomStage& data,
@@ -131,7 +131,7 @@
 void GrGLMagnifierEffect::emitFS(GrGLShaderBuilder* state,
                                  const char* outputColor,
                                  const char* inputColor,
-                                 const char* samplerName) {
+                                 const TextureSamplerArray& samplers) {
     SkString* code = &state->fFSCode;
 
     code->appendf("\t\tvec2 coord = %s;\n", state->defaultTexCoordsName());
@@ -159,7 +159,7 @@
 
     code->appendf("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n");
     code->appendf("\t\tvec4 output_color = ");
-    state->appendTextureLookup(code, samplerName, "mix_coord");
+    state->appendTextureLookup(code, samplers[0], "mix_coord");
     code->append(";\n");
 
     code->appendf("\t\t%s = output_color;", outputColor);
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 04dc227..4123ca8 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -277,7 +277,7 @@
     virtual void emitFS(GrGLShaderBuilder* state,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
 
@@ -313,7 +313,7 @@
 void GrGLMorphologyEffect::emitFS(GrGLShaderBuilder* builder,
                                   const char* outputColor,
                                   const char* inputColor,
-                                  const char* samplerName) {
+                                  const TextureSamplerArray& samplers) {
     SkString* code = &builder->fFSCode;
 
     const char* func;
@@ -337,7 +337,7 @@
                    builder->defaultTexCoordsName(), fRadius, imgInc);
     code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
     code->appendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
-    builder->appendTextureLookup(&builder->fFSCode, samplerName, "coord");
+    builder->appendTextureLookup(&builder->fFSCode, samplers[0], "coord");
     code->appendf(");\n");
     code->appendf("\t\t\tcoord += %s;\n", imgInc);
     code->appendf("\t\t}\n");
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 3d989b7..d7b4f13 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -702,7 +702,7 @@
                                         const char* gradientTValue,
                                         const char* outputColor,
                                         const char* inputColor,
-                                        const char* samplerName) {
+                                        const GrGLShaderBuilder::TextureSampler& sampler) {
 
     SkString* code = &builder->fFSCode;
     code->appendf("\tvec2 coord = vec2(%s, %s);\n",
@@ -710,7 +710,7 @@
                   builder->getUniformVariable(fFSYUni).c_str());
     GrGLSLMulVarBy4f(code, 1, outputColor, inputColor);
     code->appendf("\t%s = ", outputColor);
-    builder->appendTextureLookupAndModulate(code, inputColor, samplerName, "coord");
+    builder->appendTextureLookupAndModulate(code, inputColor, sampler, "coord");
     code->append(";\n");
 }
 
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 2b584f3..8c86326 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -291,7 +291,7 @@
                          const char* gradientTValue,
                          const char* outputColor,
                          const char* inputColor,
-                         const char* samplerName);
+                         const GrGLShaderBuilder::TextureSampler&);
 
 private:
 
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 6415927..bcebc26 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -490,7 +490,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
     static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; }
 
 private:
@@ -550,10 +550,10 @@
 void GrGLLinearGradient::emitFS(GrGLShaderBuilder* builder,
                                 const char* outputColor,
                                 const char* inputColor,
-                                const char* samplerName) {
+                                const TextureSamplerArray& samplers) {
     SkString t;
     t.printf("%s.x", builder->defaultTexCoordsName());
-    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplerName);
+    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 98433e2..799e548 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -485,7 +485,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; }
 
@@ -550,10 +550,10 @@
 void GrGLRadialGradient::emitFS(GrGLShaderBuilder* builder,
                                 const char* outputColor,
                                 const char* inputColor,
-                                const char* samplerName) {
+                                const TextureSamplerArray& samplers) {
     SkString t;
     t.printf("length(%s.xy)", builder->defaultTexCoordsName());
-    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplerName);
+    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 22b2118..843d1aa 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -394,7 +394,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     static StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps) { return 0; }
 
@@ -455,11 +455,11 @@
 void GrGLSweepGradient::emitFS(GrGLShaderBuilder* builder,
                               const char* outputColor,
                               const char* inputColor,
-                              const char* samplerName) {
+                              const TextureSamplerArray& samplers) {
     SkString t;
     t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
         builder->defaultTexCoordsName(), builder->defaultTexCoordsName());
-    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplerName);
+    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index 38733f3..3466d2c 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -332,7 +332,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
     virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
@@ -506,7 +506,7 @@
 void GrGLConical2Gradient::emitFS(GrGLShaderBuilder* builder,
                                   const char* outputColor,
                                   const char* inputColor,
-                                  const char* samplerName) {
+                                  const TextureSamplerArray& samplers) {
     SkString* code = &builder->fFSCode;
 
     SkString cName("c");
@@ -591,7 +591,7 @@
                       p5.c_str(), p3.c_str());
 
         code->appendf("\t\t");
-        this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplerName);
+        this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
 
         // otherwise, if r(t) for the larger root was <= 0, try the other root
         code->appendf("\t\t} else {\n");
@@ -603,7 +603,7 @@
                       tName.c_str(), p5.c_str(), p3.c_str());
 
         code->appendf("\t\t\t");
-        this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplerName);
+        this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
 
         // end if (r(t) > 0) for smaller root
         code->appendf("\t\t\t}\n");
@@ -621,7 +621,7 @@
         code->appendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
                       p5.c_str(), p3.c_str());
         code->appendf("\t");
-        this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplerName);
+        this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
         code->appendf("\t}\n");
     }
 }
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 2192707..9362ded 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -367,7 +367,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
     virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
@@ -539,7 +539,7 @@
 void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* builder,
                                  const char* outputColor,
                                  const char* inputColor,
-                                 const char* samplerName) {
+                                 const TextureSamplerArray& samplers) {
     SkString* code = &builder->fFSCode;
     SkString cName("c");
     SkString ac4Name("ac4");
@@ -601,7 +601,7 @@
         t.printf("-%s / %s", cName.c_str(), bVar.c_str());
     }
 
-    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplerName);
+    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
 }
 
 void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman,
diff --git a/src/gpu/effects/GrColorTableEffect.cpp b/src/gpu/effects/GrColorTableEffect.cpp
index 46e42603..56c5109 100644
--- a/src/gpu/effects/GrColorTableEffect.cpp
+++ b/src/gpu/effects/GrColorTableEffect.cpp
@@ -23,7 +23,7 @@
     virtual void emitFS(GrGLShaderBuilder* state,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
@@ -34,21 +34,18 @@
 
 private:
 
-    const GrCustomStage& fCustomStage;
-
     typedef GrGLProgramStage INHERITED;
 };
 
 GrGLColorTableEffect::GrGLColorTableEffect(
     const GrProgramStageFactory& factory, const GrCustomStage& stage)
-    : INHERITED(factory)
-    , fCustomStage(stage) {
+    : INHERITED(factory) {
  }
 
 void GrGLColorTableEffect::emitFS(GrGLShaderBuilder* builder,
                                   const char* outputColor,
                                   const char* inputColor,
-                                  const char* samplerName) {
+                                  const TextureSamplerArray& samplers) {
     static const float kColorScaleFactor = 255.0f / 256.0f;
     static const float kColorOffsetFactor = 1.0f / 512.0f;
     SkString* code = &builder->fFSCode;
@@ -67,25 +64,20 @@
                       kColorOffsetFactor, kColorOffsetFactor);
     }
 
-    const GrTextureAccess& access = *fCustomStage.textureAccess(0);
     code->appendf("\t\t%s.a = ", outputColor);
-    builder->emitCustomTextureLookup(access,
-                                     samplerName,
+    builder->emitCustomTextureLookup(samplers[0],
                                      "vec2(coord.a, 0.125)");
 
     code->appendf("\t\t%s.r = ", outputColor);
-    builder->emitCustomTextureLookup(access,
-                                     samplerName,
+    builder->emitCustomTextureLookup(samplers[0],
                                      "vec2(coord.r, 0.375)");
 
     code->appendf("\t\t%s.g = ", outputColor);
-    builder->emitCustomTextureLookup(access,
-                                     samplerName,
+    builder->emitCustomTextureLookup(samplers[0],
                                      "vec2(coord.g, 0.625)");
 
     code->appendf("\t\t%s.b = ", outputColor);
-    builder->emitCustomTextureLookup(access,
-                                     samplerName,
+    builder->emitCustomTextureLookup(samplers[0],
                                      "vec2(coord.b, 0.875)");
 
     code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 318c03e..ffaab35 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -22,9 +22,9 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE {
+                        const TextureSamplerArray& samplers) SK_OVERRIDE {
         builder->fFSCode.appendf("\t\t%s = ", outputColor);
-        builder->appendTextureLookup(&builder->fFSCode, samplerName);
+        builder->appendTextureLookup(&builder->fFSCode, samplers[0]);
         builder->fFSCode.appendf("%s;\n", builder->fSwizzle.c_str());
         if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) {
             GrAssert(fSwapRedAndBlue);
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 635064f..c189ec0 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -26,7 +26,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     virtual void setData(const GrGLUniformManager& uman,
                          const GrCustomStage&,
@@ -65,7 +65,7 @@
 void GrGLConvolutionEffect::emitFS(GrGLShaderBuilder* builder,
                                    const char* outputColor,
                                    const char* inputColor,
-                                   const char* samplerName) {
+                                   const TextureSamplerArray& samplers) {
     SkString* code = &builder->fFSCode;
 
     code->appendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
@@ -84,7 +84,7 @@
         index.appendS32(i);
         kernel.appendArrayAccess(index.c_str(), &kernelIndex);
         code->appendf("\t\t%s += ", outputColor);
-        builder->appendTextureLookup(&builder->fFSCode, samplerName, "coord");
+        builder->appendTextureLookup(&builder->fFSCode, samplers[0], "coord");
         code->appendf(" * %s;\n", kernelIndex.c_str());
         code->appendf("\t\tcoord += %s;\n", imgInc);
     }
diff --git a/src/gpu/effects/GrSingleTextureEffect.cpp b/src/gpu/effects/GrSingleTextureEffect.cpp
index dc91a68..b2fe0cc 100644
--- a/src/gpu/effects/GrSingleTextureEffect.cpp
+++ b/src/gpu/effects/GrSingleTextureEffect.cpp
@@ -22,9 +22,9 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE {
+                        const TextureSamplerArray& samplers) SK_OVERRIDE {
         builder->fFSCode.appendf("\t%s = ", outputColor);
-        builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplerName);
+        builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplers[0]);
         builder->fFSCode.append(";\n");
     }
 
diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp
index f5306c7..279e481 100644
--- a/src/gpu/effects/GrTextureDomainEffect.cpp
+++ b/src/gpu/effects/GrTextureDomainEffect.cpp
@@ -20,7 +20,7 @@
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
+                        const TextureSamplerArray&) SK_OVERRIDE;
 
     virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
@@ -49,14 +49,17 @@
 void GrGLTextureDomainEffect::emitFS(GrGLShaderBuilder* builder,
                                      const char* outputColor,
                                      const char* inputColor,
-                                     const char* samplerName) {
+                                     const TextureSamplerArray& samplers) {
     builder->fFSCode.appendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n",
                            builder->defaultTexCoordsName(),
                            builder->getUniformCStr(fNameUni),
                            builder->getUniformCStr(fNameUni));
 
     builder->fFSCode.appendf("\t%s = ", outputColor);
-    builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplerName, "clampCoord");
+    builder->appendTextureLookupAndModulate(&builder->fFSCode,
+                                            inputColor,
+                                            samplers[0],
+                                            "clampCoord");
     builder->fFSCode.append(";\n");
 }
 
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 664f1c0..934c4fc 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -629,15 +629,15 @@
                     inCoords = texCoordAttrs[tcIdx].c_str();
                 }
 
-                if (NULL != customStages[s]) {
-                    const GrProgramStageFactory& factory = customStages[s]->getFactory();
-                    fProgramStage[s] = factory.createGLInstance(*customStages[s]);
-                }
-                this->genStageCode(s,
-                                   inColor.size() ? inColor.c_str() : NULL,
-                                   outColor.c_str(),
-                                   inCoords,
-                                   &builder);
+                builder.setCurrentStage(s);
+                fProgramStage[s] = GenStageCode(customStages[s],
+                                                fDesc.fStages[s],
+                                                &fUniforms.fStages[s],
+                                                inColor.size() ? inColor.c_str() : NULL,
+                                                outColor.c_str(),
+                                                inCoords,
+                                                &builder);
+                builder.setNonStage();
                 inColor = outColor;
             }
         }
@@ -744,10 +744,6 @@
                         inCoords = texCoordAttrs[tcIdx].c_str();
                     }
 
-                    if (NULL != customStages[s]) {
-                        const GrProgramStageFactory& factory = customStages[s]->getFactory();
-                        fProgramStage[s] = factory.createGLInstance(*customStages[s]);
-                    }
                     // stages don't know how to deal with a scalar input. (Maybe they should. We
                     // could pass a GrGLShaderVar)
                     if (inCoverageIsScalar) {
@@ -755,11 +751,15 @@
                                                 inCoverage.c_str(), inCoverage.c_str());
                         inCoverage.append("4");
                     }
-                    this->genStageCode(s,
-                                       inCoverage.size() ? inCoverage.c_str() : NULL,
-                                       outCoverage.c_str(),
-                                       inCoords,
-                                       &builder);
+                    builder.setCurrentStage(s);
+                    fProgramStage[s] = GenStageCode(customStages[s],
+                                                    fDesc.fStages[s],
+                                                    &fUniforms.fStages[s],
+                                                    inCoverage.size() ? inCoverage.c_str() : NULL,
+                                                    outCoverage.c_str(),
+                                                    inCoords,
+                                                    &builder);
+                    builder.setNonStage();
                     inCoverage = outCoverage;
                 }
             }
@@ -920,22 +920,19 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Stage code generation
 
-void GrGLProgram::genStageCode(int stageNum,
-                               const char* fsInColor, // NULL means no incoming color
-                               const char* fsOutColor,
-                               const char* vsInCoord,
-                               GrGLShaderBuilder* builder) {
-    GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages);
+// TODO: Move this function to GrGLShaderBuilder
+GrGLProgramStage* GrGLProgram::GenStageCode(const GrCustomStage* stage,
+                                            const StageDesc& desc,
+                                            StageUniforms* uniforms,
+                                            const char* fsInColor, // NULL means no incoming color
+                                            const char* fsOutColor,
+                                            const char* vsInCoord,
+                                            GrGLShaderBuilder* builder) {
 
-    const GrGLProgram::StageDesc& desc = fDesc.fStages[stageNum];
-    StageUniforms& uniforms = fUniforms.fStages[stageNum];
-    GrGLProgramStage* customStage = fProgramStage[stageNum];
-    GrAssert(NULL != customStage);
+    GrGLProgramStage* glStage = stage->getFactory().createGLInstance(*stage);
 
     GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) == desc.fInConfigFlags);
 
-    builder->setCurrentStage(stageNum);
-
     /// Vertex Shader Stuff
 
     // decide whether we need a matrix to transform texture coords and whether the varying needs a
@@ -945,9 +942,9 @@
     if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
         texCoordVaryingType = kVec2f_GrSLType;
     } else {
-        uniforms.fTextureMatrixUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
+        uniforms->fTextureMatrixUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
                                                          kMat33f_GrSLType, "TexM", &matName);
-        builder->getUniformVariable(uniforms.fTextureMatrixUni);
+        builder->getUniformVariable(uniforms->fTextureMatrixUni);
 
         if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
             texCoordVaryingType = kVec2f_GrSLType;
@@ -963,13 +960,22 @@
     builder->setupTextureAccess(varyingFSName, texCoordVaryingType);
 
     // Must setup variables after calling setupTextureAccess
-    customStage->setupVariables(builder);
+    glStage->setupVariables(builder);
 
-    const char* samplerName;
-    uniforms.fSamplerUniforms.push_back(builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                                                            kSampler2D_GrSLType,
-                                                            "Sampler",
-                                                            &samplerName));
+    int numTextures = stage->numTextures();
+    SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
+    textureSamplers.push_back_n(numTextures);
+    for (int i = 0; i < numTextures; ++i) {
+        // Right now we don't require a texture access for every texture. This will change soon.
+        const GrTextureAccess* access = stage->textureAccess(i);
+        if (NULL != access) {
+            GrAssert(access->getTexture() == stage->texture(i));
+            textureSamplers[i].init(builder, access);
+        } else {
+            textureSamplers[i].init(builder, stage->texture(i));
+        }
+        uniforms->fSamplerUniforms.push_back(textureSamplers[i].fSamplerUniform);
+    }
 
     if (!matName) {
         GrAssert(kVec2f_GrSLType == texCoordVaryingType);
@@ -981,18 +987,16 @@
                                   vector_all_coords(GrSLTypeToVecLength(texCoordVaryingType)));
     }
 
-    builder->fVSCode.appendf("\t{ // stage %d %s\n",
-                                stageNum, customStage->name());
-    customStage->emitVS(builder, varyingVSName);
+    builder->fVSCode.appendf("\t{ // %s\n", glStage->name());
+    glStage->emitVS(builder, varyingVSName);
     builder->fVSCode.appendf("\t}\n");
 
     builder->computeSwizzle(desc.fInConfigFlags);
 
     // Enclose custom code in a block to avoid namespace conflicts
-    builder->fFSCode.appendf("\t{ // stage %d %s \n",
-                                stageNum, customStage->name());
-    customStage->emitFS(builder, fsOutColor, fsInColor,
-                        samplerName);
+    builder->fFSCode.appendf("\t{ // %s \n", glStage->name());
+    glStage->emitFS(builder, fsOutColor, fsInColor, textureSamplers);
     builder->fFSCode.appendf("\t}\n");
-    builder->setNonStage();
+
+    return glStage;
 }
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 0d0f8b0..e32238b 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -196,6 +196,8 @@
     typedef Desc::StageDesc StageDesc;
 
 private:
+    struct StageUniforms;
+
     GrGLProgram(const GrGLContextInfo& gl,
                 const Desc& desc,
                 const GrCustomStage** customStages);
@@ -209,12 +211,13 @@
 
     void genInputColor(GrGLShaderBuilder* builder, SkString* inColor);
 
-    // Determines which uniforms will need to be bound.
-    void genStageCode(int stageNum,
-                      const char* fsInColor, // NULL means no incoming color
-                      const char* fsOutColor,
-                      const char* vsInCoord,
-                      GrGLShaderBuilder* builder);
+    static GrGLProgramStage* GenStageCode(const GrCustomStage* stage,
+                                          const StageDesc& desc, // TODO: Eliminate this
+                                          StageUniforms* stageUniforms, // TODO: Eliminate this
+                                          const char* fsInColor, // NULL means no incoming color
+                                          const char* fsOutColor,
+                                          const char* vsInCoord,
+                                          GrGLShaderBuilder* builder);
 
     void genGeometryShader(GrGLShaderBuilder* segments) const;
 
diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h
index 69095b6..28d3f49 100644
--- a/src/gpu/gl/GrGLProgramStage.h
+++ b/src/gpu/gl/GrGLProgramStage.h
@@ -25,7 +25,6 @@
 
     These objects are created by a factory function on the
     GrCustomStage.
-    TODO: lifetime management.
 */
 
 class GrGLProgramStage {
@@ -37,6 +36,8 @@
         kProgramStageKeyBits = GrProgramStageFactory::kProgramStageKeyBits,
     };
 
+    typedef GrGLShaderBuilder::TextureSamplerArray TextureSamplerArray;
+
     GrGLProgramStage(const GrProgramStageFactory&);
 
     virtual ~GrGLProgramStage();
@@ -63,14 +64,10 @@
         trans black, known to be opaque, etc.) that allows the custom stage
         to communicate back similar known info about its output.
         */
-    /* TODO: don't give them the samplerName, just a handle; then give
-       a function here for them to call into that'll apply any texture
-       domain - but do we force them to be honest about texture domain
-       parameters? */
     virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         const char* inputColor,
-                        const char* samplerName) = 0;
+                        const TextureSamplerArray&) = 0;
 
     /** A GrGLCustomStage instance can be reused with any GrCustomStage
         that produces the same stage key; this function reads data from
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 5d870dd..b10f4e6 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -123,36 +123,41 @@
 }
 
 void GrGLShaderBuilder::appendTextureLookup(SkString* out,
-                                            const char* samplerName,
+                                            const GrGLShaderBuilder::TextureSampler& sampler,
                                             const char* coordName,
                                             GrSLType varyingType) const {
     if (NULL == coordName) {
         coordName = fDefaultTexCoordsName.c_str();
         varyingType = kVec2f_GrSLType;
     }
-    out->appendf("%s(%s, %s)", sample_function_name(varyingType), samplerName, coordName);
+    out->appendf("%s(%s, %s)",
+                 sample_function_name(varyingType),
+                 this->getUniformCStr(sampler.fSamplerUniform),
+                 coordName);
 }
 
-void GrGLShaderBuilder::appendTextureLookupAndModulate(SkString* out,
-                                                       const char* modulation,
-                                                       const char* samplerName,
-                                                       const char* coordName,
-                                                       GrSLType varyingType) const {
+void GrGLShaderBuilder::appendTextureLookupAndModulate(
+                                            SkString* out,
+                                            const char* modulation,
+                                            const GrGLShaderBuilder::TextureSampler& sampler,
+                                            const char* coordName,
+                                            GrSLType varyingType) const {
     GrAssert(NULL != out);
     SkString lookup;
-    this->appendTextureLookup(&lookup, samplerName, coordName, varyingType);
+    this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
     lookup.append(fSwizzle.c_str());
     GrGLSLModulate4f(out, modulation, lookup.c_str());
 }
 
-void GrGLShaderBuilder::emitCustomTextureLookup(const GrTextureAccess& textureAccess,
-                                                const char* samplerName,
+void GrGLShaderBuilder::emitCustomTextureLookup(const GrGLShaderBuilder::TextureSampler& sampler,
                                                 const char* coordName,
                                                 GrSLType varyingType) {
-    GrAssert(samplerName && coordName);
-    SkString swizzle = build_swizzle_string(textureAccess, fContext.caps());
+    GrAssert(NULL != sampler.textureAccess());
+    SkString swizzle = build_swizzle_string(*sampler.textureAccess(), fContext.caps());
 
-    fFSCode.appendf("%s( %s, %s)%s;\n", sample_function_name(varyingType), samplerName,
+    fFSCode.appendf("%s( %s, %s)%s;\n",
+                    sample_function_name(varyingType),
+                    this->getUniformCStr(sampler.fSamplerUniform),
                     coordName, swizzle.c_str());
 }
 
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index bc10892..c5ac078 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -21,8 +21,74 @@
   manipulate that state.
 */
 class GrGLShaderBuilder {
-
 public:
+    /**
+     * Used by GrGLProgramStages to add texture reads to their shader code.
+     */
+    class TextureSampler {
+    public:
+        TextureSampler()
+            : fTextureAccess(NULL)
+            , fTexture(NULL)
+            , fSamplerUniform(GrGLUniformManager::kInvalidUniformHandle) {}
+
+        TextureSampler(const TextureSampler& other) { *this = other; }
+
+        TextureSampler& operator= (const TextureSampler& other) {
+            GrAssert(NULL == fTextureAccess);
+            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
+
+            fTexture = other.fTexture;
+            fTextureAccess = other.fTextureAccess;
+            fSamplerUniform = other.fSamplerUniform;
+            return *this;
+        }
+
+        const GrTextureAccess* textureAccess() const { return fTextureAccess; }
+
+    private:
+        void init(GrGLShaderBuilder* builder, const GrTextureAccess* access) {
+            GrAssert(NULL == fTextureAccess);
+            GrAssert(NULL == fTexture);
+            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
+
+            GrAssert(NULL != builder);
+            GrAssert(NULL != access);
+            fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                  kSampler2D_GrSLType,
+                                                  "Sampler");
+            GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform);
+
+            fTextureAccess = access;
+            fTexture = access->getTexture();
+        }
+
+        // TODO: Remove once GrTextureAccess is required.
+        void init(GrGLShaderBuilder* builder, const GrTexture* texture) {
+            GrAssert(NULL == fTextureAccess);
+            GrAssert(NULL == fTexture);
+            GrAssert(GrGLUniformManager::kInvalidUniformHandle == fSamplerUniform);
+
+            GrAssert(NULL != builder);
+            GrAssert(NULL != texture);
+            fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                  kSampler2D_GrSLType,
+                                                  "Sampler");
+            GrAssert(GrGLUniformManager::kInvalidUniformHandle != fSamplerUniform);
+
+            fTexture = texture;
+        }
+
+        const GrTextureAccess*            fTextureAccess;
+        const GrTexture*                  fTexture; // TODO: remove once tex access cannot be NULL
+        GrGLUniformManager::UniformHandle fSamplerUniform;
+
+        friend class GrGLShaderBuilder; // to access fSamplerUniform
+        friend class GrGLProgram;       // to construct these and access fSamplerUniform.
+    };
+
+    typedef SkTArray<TextureSampler> TextureSamplerArray;
+
     enum ShaderType {
         kVertex_ShaderType   = 0x1,
         kGeometry_ShaderType = 0x2,
@@ -38,11 +104,11 @@
         initialize it. This should only be called by GrGLProgram.*/
     void setupTextureAccess(const char* varyingFSName, GrSLType varyingType);
 
-    /** texture2D(samplerName, coordName), with projection if necessary; if coordName is not
+    /** appends a texture sample with projection if necessary; if coordName is not
         specified, uses fSampleCoords. coordType must either be Vec2f or Vec3f. The latter is
         interpreted as projective texture coords. */
     void appendTextureLookup(SkString* out,
-                             const char* samplerName,
+                             const TextureSampler&,
                              const char* coordName = NULL,
                              GrSLType coordType = kVec2f_GrSLType) const;
 
@@ -52,7 +118,7 @@
         be expression that evaluates to a float or vec4. */
     void appendTextureLookupAndModulate(SkString* out,
                                         const char* modulation,
-                                        const char* samplerName,
+                                        const TextureSampler&,
                                         const char* coordName = NULL,
                                         GrSLType varyingType = kVec2f_GrSLType) const;
 
@@ -71,8 +137,7 @@
         The generated swizzle state is built based on the format of the texture and the requested
         swizzle access pattern.  coordType must either be Vec2f or Vec3f. The latter is interpreted
         as projective texture coords.*/
-    void emitCustomTextureLookup(const GrTextureAccess& textureAccess,
-                                 const char* samplerName,
+    void emitCustomTextureLookup(const TextureSampler&,
                                  const char* coordName,
                                  GrSLType coordType = kVec2f_GrSLType);