This patch implements the diffuse and specular lighting filters in Ganesh. 
There are three light types for each:  distant, point and spot, whose code
generation lives in a GrGLLight class hierarchy.  This similar to the CPU
implementation, where each light type provides a function to compute the vector
from the surface plane to the light (surfaceToLight) and to compute the light
colour (emitLightColour).  Instead of templated member functions, as in the CPU
implementation, these are virtual functions to emit the light-specific GLSL
code.

All of the code for the GPU path lives in the same file as that for the CPU
path, SkLightingImageFilter.cpp.  In order to provide Ganesh a hook to access
it, SkImageFilter now has a asNewCustomStage() virtual, which allows an image
filter to return a GrCustomStage representing that filter.

Note that this patch does not handle the border conditions correctly (the
[top|bottom][Left|Right]Normal() functions in the CPU implementation).  That
will come in a future patch.

Review URL: http://codereview.appspot.com/6345081/



git-svn-id: http://skia.googlecode.com/svn/trunk@4535 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 5625d03..ef45968 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -8,6 +8,14 @@
 #include "SkLightingImageFilter.h"
 #include "SkBitmap.h"
 #include "SkColorPriv.h"
+#include "GrProgramStageFactory.h"
+#include "gl/GrGLProgramStage.h"
+#include "gl/GrGLSL.h"
+#include "gl/GrGLTexture.h"
+#include "GrCustomStage.h"
+
+class GrGLDiffuseLightingEffect;
+class GrGLSpecularLightingEffect;
 
 // FIXME:  Eventually, this should be implemented properly, and put in
 // SkScalar.h.
@@ -19,6 +27,13 @@
 const SkScalar gOneHalf = SkFloatToScalar(0.5f);
 const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
 
+void setUniformPoint3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
+    float x = SkScalarToFloat(point.fX);
+    float y = SkScalarToFloat(point.fY);
+    float z = SkScalarToFloat(point.fZ);
+    GR_GL_CALL(gl, Uniform3f(location, x, y, z));
+}
+
 // Shift matrix components to the left, as we advance pixels to the right.
 inline void shiftMatrixLeft(int m[9]) {
     m[0] = m[1];
@@ -236,6 +251,7 @@
     SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
 
+    virtual bool asNewCustomStage(GrCustomStage** stage) const SK_OVERRIDE;
     SkScalar kd() const { return fKD; }
 
 protected:
@@ -255,6 +271,10 @@
     SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
 
+    virtual bool asNewCustomStage(GrCustomStage** stage) const SK_OVERRIDE;
+    SkScalar ks() const { return fKS; }
+    SkScalar shininess() const { return fShininess; }
+
 protected:
     explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
     virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
@@ -267,8 +287,144 @@
     SkScalar fShininess;
 };
 
+
+class GrLightingEffect : public GrCustomStage {
+public:
+    GrLightingEffect(const SkLight* light, SkScalar surfaceScale);
+    virtual ~GrLightingEffect();
+
+    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
+
+    const SkLight* light() const { return fLight; }
+    SkScalar surfaceScale() const { return fSurfaceScale; }
+private:
+    typedef GrCustomStage INHERITED;
+    const SkLight* fLight;
+    SkScalar fSurfaceScale;
 };
 
+class GrDiffuseLightingEffect : public GrLightingEffect {
+public:
+    GrDiffuseLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar kd);
+
+    static const char* Name() { return "DiffuseLighting"; }
+
+    typedef GrGLDiffuseLightingEffect GLProgramStage;
+
+    virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
+    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
+    SkScalar kd() const { return fKD; }
+private:
+    typedef GrLightingEffect INHERITED;
+    SkScalar fKD;
+};
+
+class GrSpecularLightingEffect : public GrLightingEffect {
+public:
+    GrSpecularLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
+
+    static const char* Name() { return "SpecularLighting"; }
+
+    typedef GrGLSpecularLightingEffect GLProgramStage;
+
+    virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
+    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
+    SkScalar ks() const { return fKS; }
+    SkScalar shininess() const { return fShininess; }
+
+private:
+    typedef GrLightingEffect INHERITED;
+    SkScalar fKS;
+    SkScalar fShininess;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLLight {
+public:
+    virtual void setupVariables(GrGLShaderBuilder* state, int stage);
+    virtual void emitVS(SkString* builder) const {}
+    virtual void emitFuncs(SkString* builder) const {}
+    virtual void emitSurfaceToLight(SkString* builder, const char* z) const = 0;
+    virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
+    virtual void initUniforms(const GrGLInterface* gl, int programID);
+    virtual void setData(const GrGLInterface*, const SkLight* light) const;
+
+private:
+    typedef SkRefCnt INHERITED;
+
+protected:
+    const GrGLShaderVar* fColorVar;
+    int fColorVarLocation;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLDistantLight : public GrGLLight {
+public:
+    virtual void setupVariables(GrGLShaderBuilder* state, int stage) SK_OVERRIDE;
+    virtual void initUniforms(const GrGLInterface* gl, int programID) SK_OVERRIDE;
+    virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
+    virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
+
+private:
+    typedef GrGLLight INHERITED;
+    const GrGLShaderVar* fDirectionVar;
+    int fDirectionLocation;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLPointLight : public GrGLLight {
+public:
+    virtual void setupVariables(GrGLShaderBuilder* state, int stage);
+    virtual void initUniforms(const GrGLInterface* gl, int programID);
+    virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
+    virtual void emitVS(SkString* builder) const;
+    virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
+
+private:
+    typedef GrGLLight INHERITED;
+    SkPoint3 fLocation;
+    const GrGLShaderVar* fLocationVar;
+    int fLocationLocation;
+    const char* fHeightVaryingName;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLSpotLight : public GrGLLight {
+public:
+    virtual void setupVariables(GrGLShaderBuilder* state, int stage);
+    virtual void initUniforms(const GrGLInterface* gl, int programID);
+    virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
+    virtual void emitVS(SkString* builder) const;
+    virtual void emitFuncs(SkString* builder) const;
+    virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
+    virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
+
+private:
+    typedef GrGLLight INHERITED;
+
+    const GrGLShaderVar* fLocationVar;
+    int                  fLocationLocation;
+    const GrGLShaderVar* fExponentVar;
+    int                  fExponentLocation;
+    const GrGLShaderVar* fCosOuterConeAngleVar;
+    int                  fCosOuterConeAngleLocation;
+    const GrGLShaderVar* fCosInnerConeAngleVar;
+    int                  fCosInnerConeAngleLocation;
+    const GrGLShaderVar* fConeScaleVar;
+    int                  fConeScaleLocation;
+    const GrGLShaderVar* fSVar;
+    int                  fSLocation;
+    const char*          fHeightVaryingName;
+};
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
 class SkLight : public SkFlattenable {
 public:
     SK_DECLARE_INST_COUNT(SkLight)
@@ -280,6 +436,10 @@
     };
     virtual LightType type() const = 0;
     const SkPoint3& color() const { return fColor; }
+    virtual GrGLLight* createGLLight() const = 0;
+    virtual bool isEqual(const SkLight& other) const {
+        return fColor == other.fColor;
+    }
 
 protected:
     SkLight(SkColor color)
@@ -302,6 +462,8 @@
 
 SK_DEFINE_INST_COUNT(SkLight)
 
+///////////////////////////////////////////////////////////////////////////////
+
 class SkDistantLight : public SkLight {
 public:
     SkDistantLight(const SkPoint3& direction, SkColor color)
@@ -313,7 +475,8 @@
     };
     SkPoint3 lightColor(const SkPoint3&) const { return color(); }
     virtual LightType type() const { return kDistant_LightType; }
-    SkPoint3 direction() const { return fDirection; }
+    const SkPoint3& direction() const { return fDirection; }
+    virtual GrGLLight* createGLLight() const SK_OVERRIDE;
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
 
@@ -331,6 +494,8 @@
     SkPoint3 fDirection;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+
 class SkPointLight : public SkLight {
 public:
     SkPointLight(const SkPoint3& location, SkColor color)
@@ -345,6 +510,18 @@
     };
     SkPoint3 lightColor(const SkPoint3&) const { return color(); }
     virtual LightType type() const { return kPoint_LightType; }
+    const SkPoint3& location() const { return fLocation; }
+    virtual GrGLLight* createGLLight() const SK_OVERRIDE {
+        return new GrGLPointLight();
+    }
+    bool isEqual(const SkLight& other) SK_OVERRIDE {
+        if (other.type() != kPoint_LightType) {
+            return false;
+        }
+        const SkPointLight& o = static_cast<const SkPointLight&>(other);
+        return INHERITED::isEqual(other) &&
+               fLocation == o.fLocation;
+    }
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
 
@@ -362,6 +539,8 @@
     SkPoint3 fLocation;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+
 class SkSpotLight : public SkLight {
 public:
     SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
@@ -397,8 +576,17 @@
         }
         return color() * scale;
     }
-
+    virtual GrGLLight* createGLLight() const SK_OVERRIDE {
+        return new GrGLSpotLight();
+    }
     virtual LightType type() const { return kSpot_LightType; }
+    const SkPoint3& location() const { return fLocation; }
+    const SkPoint3& target() const { return fTarget; }
+    SkScalar specularExponent() const { return fSpecularExponent; }
+    SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
+    SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
+    SkScalar coneScale() const { return fConeScale; }
+    SkPoint3 s() const { return fS; }
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
 
@@ -423,6 +611,19 @@
         writePoint3(fS, buffer);
     }
 
+    virtual bool isEqual(const SkLight& other) SK_OVERRIDE {
+        if (other.type() != kSpot_LightType) {
+            return false;
+        }
+
+        const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
+        return INHERITED::isEqual(other) &&
+               fLocation == o.fLocation &&
+               fTarget == o.fTarget &&
+               fSpecularExponent == o.fSpecularExponent &&
+               fCosOuterConeAngle == o.fCosOuterConeAngle;
+    }
+
 private:
     typedef SkLight INHERITED;
     SkPoint3 fLocation;
@@ -434,6 +635,8 @@
     SkPoint3 fS;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+
 SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
   : fLight(light),
     fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
@@ -507,6 +710,8 @@
     buffer.writeScalar(fSurfaceScale);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
 SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
   : SkLightingImageFilter(light, surfaceScale),
     fKD(kd)
@@ -557,6 +762,16 @@
     return true;
 }
 
+bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage) const {
+    if (stage) {
+        SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
+        *stage = new GrDiffuseLightingEffect(light(), scale, kd());
+    }
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
   : SkLightingImageFilter(light, surfaceScale),
     fKS(ks),
@@ -610,6 +825,517 @@
     return true;
 }
 
+bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage) const {
+    if (stage) {
+        SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
+        *stage = new GrSpecularLightingEffect(light(), scale, ks(), shininess());
+    }
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLLightingEffect  : public GrGLProgramStage {
+public:
+    GrGLLightingEffect(const GrProgramStageFactory& factory,
+                       const GrCustomStage& stage);
+    virtual ~GrGLLightingEffect();
+
+    virtual void setupVariables(GrGLShaderBuilder* state,
+                                int stage) SK_OVERRIDE;
+    virtual void emitVS(GrGLShaderBuilder* state,
+                        const char* vertexCoords) SK_OVERRIDE;
+    virtual void emitFS(GrGLShaderBuilder* state,
+                        const char* outputColor,
+                        const char* inputColor,
+                        const char* samplerName) SK_OVERRIDE;
+
+    virtual void emitLightFunc(SkString* funcs) = 0;
+
+    static inline StageKey GenKey(const GrCustomStage& s);
+
+    virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
+    virtual void setData(const GrGLInterface*, 
+                         const GrGLTexture&,
+                         const GrCustomStage&,
+                         int stageNum) SK_OVERRIDE;
+
+private:
+    typedef GrGLProgramStage INHERITED;
+
+    const GrGLShaderVar*               fImageIncrementVar;
+    GrGLint                            fImageIncrementLocation;
+    const GrGLShaderVar*               fSurfaceScaleVar;
+    GrGLint                            fSurfaceScaleLocation;
+    GrGLLight*                         fLight;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLDiffuseLightingEffect  : public GrGLLightingEffect {
+public:
+    GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
+                              const GrCustomStage& stage);
+    virtual void setupVariables(GrGLShaderBuilder* state,
+                                int stage) SK_OVERRIDE;
+    virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
+    virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
+    virtual void setData(const GrGLInterface*, 
+                         const GrGLTexture&,
+                         const GrCustomStage&,
+                         int stageNum) SK_OVERRIDE;
+
+private:
+    typedef GrGLLightingEffect INHERITED;
+
+    const GrGLShaderVar*               fKDVar;
+    GrGLint                            fKDLocation;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLSpecularLightingEffect  : public GrGLLightingEffect {
+public:
+    GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
+                               const GrCustomStage& stage);
+    virtual void setupVariables(GrGLShaderBuilder* state,
+                                int stage) SK_OVERRIDE;
+    virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
+    virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
+    virtual void setData(const GrGLInterface*, 
+                         const GrGLTexture&,
+                         const GrCustomStage&,
+                         int stageNum) SK_OVERRIDE;
+
+private:
+    typedef GrGLLightingEffect INHERITED;
+
+    const GrGLShaderVar*               fKSVar;
+    GrGLint                            fKSLocation;
+    const GrGLShaderVar*               fShininessVar;
+    GrGLint                            fShininessLocation;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrLightingEffect::GrLightingEffect(const SkLight* light, SkScalar surfaceScale)
+    : fLight(light)
+    , fSurfaceScale(surfaceScale) {
+    fLight->ref();
+}
+
+GrLightingEffect::~GrLightingEffect() {
+    fLight->unref();
+}
+
+bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
+    const GrLightingEffect& s =
+        static_cast<const GrLightingEffect&>(sBase);
+    return fLight->isEqual(*s.fLight) &&
+           fSurfaceScale == s.fSurfaceScale;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrDiffuseLightingEffect::GrDiffuseLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar kd)
+    : INHERITED(light, surfaceScale), fKD(kd) {
+}
+
+const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
+    return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
+}
+
+bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
+    const GrDiffuseLightingEffect& s =
+        static_cast<const GrDiffuseLightingEffect&>(sBase);
+    return INHERITED::isEqual(sBase) &&
+            this->kd() == s.kd();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
+                                       const GrCustomStage& stage)
+    : GrGLProgramStage(factory)
+    , fImageIncrementVar(NULL)
+    , fImageIncrementLocation(0)
+    , fSurfaceScaleVar(NULL)
+    , fSurfaceScaleLocation(0) {
+    const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
+    fLight = m.light()->createGLLight();
+}
+
+GrGLLightingEffect::~GrGLLightingEffect() {
+    delete fLight;
+}
+
+void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
+    fImageIncrementVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kVec2f_GrSLType, "uImageIncrement", stage);
+    fSurfaceScaleVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uSurfaceScale", stage);
+    fLight->setupVariables(state, stage);
+}
+
+void GrGLLightingEffect::emitVS(GrGLShaderBuilder* state,
+                                    const char* vertexCoords) {
+    fLight->emitVS(&state->fVSCode);
+}
+
+void GrGLLightingEffect::initUniforms(const GrGLInterface* gl,
+                                        int programID) {
+    GR_GL_CALL_RET(gl, fSurfaceScaleLocation,
+        GetUniformLocation(programID,
+            fSurfaceScaleVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fImageIncrementLocation,
+        GetUniformLocation(programID,
+            fImageIncrementVar->getName().c_str()));
+    fLight->initUniforms(gl, programID);
+}
+
+void GrGLLightingEffect::emitFS(GrGLShaderBuilder* state,
+                                       const char* outputColor,
+                                       const char* inputColor,
+                                       const char* samplerName) {
+    SkString* code = &state->fFSCode;
+    SkString* funcs = &state->fFSFunctions;
+    fLight->emitFuncs(funcs);
+    emitLightFunc(funcs);
+    funcs->appendf("float sobel(float a, float b, float c, float d, float e, float f, float scale) {\n");
+    funcs->appendf("\treturn (-a + b - 2 * c + 2 * d -e + f) * scale;\n");
+    funcs->appendf("}\n");
+    funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
+    funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
+    funcs->appendf("}\n");
+    funcs->append("\n\
+vec3 interiorNormal(float m[9], float surfaceScale) {\n\
+    return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
+                         sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
+                         surfaceScale);\n}\n");
+
+    code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
+    code->appendf("\t\tfloat m[9];\n");
+    int index = 0;
+    for (int dy = -1; dy <= 1; dy++) {
+        for (int dx = -1; dx <= 1; dx++) {
+            SkString texCoords;
+            texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, fImageIncrementVar->getName().c_str());
+            code->appendf("\t\tm[%d] = ", index++);
+            state->emitTextureLookup(samplerName, texCoords.c_str());
+            code->appendf(".a;\n");
+        }
+    }
+    code->appendf("\t\tvec3 surfaceToLight = ");
+    SkString arg;
+    arg.appendf("%s * m[4]", fSurfaceScaleVar->getName().c_str());
+    fLight->emitSurfaceToLight(code, arg.c_str());
+    code->appendf(";\n");
+    code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, fSurfaceScaleVar->getName().c_str());
+    fLight->emitLightColor(code, "surfaceToLight");
+    code->appendf(")%s;\n", state->fModulate.c_str());
+}
+
+GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
+  const GrCustomStage& s) {
+    return static_cast<const GrLightingEffect&>(s).light()->type();
+}
+
+void GrGLLightingEffect::setData(const GrGLInterface* gl,
+                                 const GrGLTexture& texture,
+                                 const GrCustomStage& data,
+                                 int stageNum) {
+    const GrLightingEffect& effect =
+        static_cast<const GrLightingEffect&>(data);
+    GR_GL_CALL(gl, Uniform2f(fImageIncrementLocation, 1.0f / texture.width(), 1.0f / texture.height()));
+    GR_GL_CALL(gl, Uniform1f(fSurfaceScaleLocation, effect.surfaceScale()));
+    fLight->setData(gl, effect.light());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
+                                            const GrCustomStage& stage)
+    : INHERITED(factory, stage)
+    , fKDVar(NULL)
+    , fKDLocation(0) {
+}
+
+void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
+    INHERITED::setupVariables(state, stage);
+    fKDVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uKD", stage);
+}
+
+void GrGLDiffuseLightingEffect::initUniforms(const GrGLInterface* gl,
+                                             int programID) {
+    INHERITED::initUniforms(gl, programID);
+    GR_GL_CALL_RET(gl, fKDLocation,
+        GetUniformLocation(programID,
+            fKDVar->getName().c_str()));
+}
+
+void GrGLDiffuseLightingEffect::emitLightFunc(SkString* funcs) {
+    funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
+    funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", fKDVar->getName().c_str());
+    funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0, 1), 1);\n");
+    funcs->appendf("}\n");
+}
+
+void GrGLDiffuseLightingEffect::setData(const GrGLInterface* gl,
+                                        const GrGLTexture& texture,
+                                        const GrCustomStage& data,
+                                        int stageNum) {
+    INHERITED::setData(gl, texture, data, stageNum);
+    const GrDiffuseLightingEffect& effect =
+        static_cast<const GrDiffuseLightingEffect&>(data);
+    GR_GL_CALL(gl, Uniform1f(fKDLocation, effect.kd()));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrSpecularLightingEffect::GrSpecularLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
+    : INHERITED(light, surfaceScale),
+      fKS(ks),
+      fShininess(shininess) {
+}
+
+const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
+    return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
+}
+
+bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
+    const GrSpecularLightingEffect& s =
+        static_cast<const GrSpecularLightingEffect&>(sBase);
+    return INHERITED::isEqual(sBase) &&
+           this->ks() == s.ks() &&
+           this->shininess() == s.shininess();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
+                                            const GrCustomStage& stage)
+    : GrGLLightingEffect(factory, stage)
+    , fKSVar(NULL)
+    , fKSLocation(0)
+    , fShininessVar(NULL)
+    , fShininessLocation(0) {
+}
+
+void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
+    INHERITED::setupVariables(state, stage);
+    fKSVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uKS", stage);
+    fShininessVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uShininess", stage);
+}
+
+void GrGLSpecularLightingEffect::initUniforms(const GrGLInterface* gl,
+                                        int programID) {
+    INHERITED::initUniforms(gl, programID);
+    GR_GL_CALL_RET(gl, fKSLocation,
+        GetUniformLocation(programID, fKSVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fShininessLocation,
+        GetUniformLocation(programID, fShininessVar->getName().c_str()));
+}
+
+void GrGLSpecularLightingEffect::emitLightFunc(SkString* funcs) {
+    funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
+    funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
+
+    funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n",
+        fKSVar->getName().c_str(), fShininessVar->getName().c_str());
+    funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0, 1), 1);\n");
+    funcs->appendf("}\n");
+}
+
+void GrGLSpecularLightingEffect::setData(const GrGLInterface* gl,
+                                        const GrGLTexture& texture,
+                                        const GrCustomStage& data,
+                                        int stageNum) {
+    INHERITED::setData(gl, texture, data, stageNum);
+    const GrSpecularLightingEffect& effect =
+        static_cast<const GrSpecularLightingEffect&>(data);
+    GR_GL_CALL(gl, Uniform1f(fKSLocation, effect.ks()));
+    GR_GL_CALL(gl, Uniform1f(fShininessLocation, effect.shininess()));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGLLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
+    builder->append(fColorVar->getName().c_str());
+}
+
+void GrGLLight::setupVariables(GrGLShaderBuilder* state, int stage) {
+    fColorVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kVec3f_GrSLType, "uLightColor", stage);
+}
+
+void GrGLLight::initUniforms(const GrGLInterface* gl, int programID) {
+    GR_GL_CALL_RET(gl, fColorVarLocation,
+        GetUniformLocation(programID, fColorVar->getName().c_str()));
+}
+
+void GrGLLight::setData(const GrGLInterface* gl, const SkLight* light) const {
+    setUniformPoint3(gl, fColorVarLocation, light->color() * SkScalarInvert(SkIntToScalar(255)));
+}
+
+GrGLLight* SkDistantLight::createGLLight() const {
+    return new GrGLDistantLight();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGLDistantLight::setupVariables(GrGLShaderBuilder* state, int stage) {
+    INHERITED::setupVariables(state, stage);
+    fDirectionVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
+        "uLightDirection", stage);
+}
+
+void GrGLDistantLight::initUniforms(const GrGLInterface* gl, int programID) {
+    INHERITED::initUniforms(gl, programID);
+    GR_GL_CALL_RET(gl, fDirectionLocation,
+        GetUniformLocation(programID, fDirectionVar->getName().c_str()));
+}
+
+void GrGLDistantLight::setData(const GrGLInterface* gl, const SkLight* light) const {
+    INHERITED::setData(gl, light);
+    SkASSERT(light->type() == SkLight::kDistant_LightType);
+    const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
+    setUniformPoint3(gl, fDirectionLocation, distantLight->direction());
+}
+
+void GrGLDistantLight::emitSurfaceToLight(SkString* builder,
+                                          const char* z) const {
+    builder->append(fDirectionVar->getName().c_str());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGLPointLight::setupVariables(GrGLShaderBuilder* state, int stage) {
+    INHERITED::setupVariables(state, stage);
+    fLocationVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
+        "uLightLocation", stage);
+    state->addVarying(kFloat_GrSLType, "Height", stage, &fHeightVaryingName);
+}
+
+void GrGLPointLight::initUniforms(const GrGLInterface* gl, int programID) {
+    INHERITED::initUniforms(gl, programID);
+    GR_GL_CALL_RET(gl, fLocationLocation,
+        GetUniformLocation(programID, fLocationVar->getName().c_str()));
+}
+
+void GrGLPointLight::setData(const GrGLInterface* gl, const SkLight* light) const {
+    INHERITED::setData(gl, light);
+    SkASSERT(light->type() == SkLight::kPoint_LightType);
+    const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
+    setUniformPoint3(gl, fLocationLocation, pointLight->location());
+}
+
+void GrGLPointLight::emitVS(SkString* builder) const {
+    // Compute viewport height from the Y scale of the matrix.
+    builder->appendf("\t\t%s = -2.0 / uViewM[1][1];\n", fHeightVaryingName);
+}
+
+void GrGLPointLight::emitSurfaceToLight(SkString* builder,
+                                      const char* z) const {
+    builder->appendf(
+        "normalize(%s - vec3(gl_FragCoord.x, %s - gl_FragCoord.y, %s))",
+        fLocationVar->getName().c_str(), fHeightVaryingName, z);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGLSpotLight::setupVariables(GrGLShaderBuilder* state, int stage) {
+    INHERITED::setupVariables(state, stage);
+    fLocationVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kVec3f_GrSLType, "uLightLocation", stage);
+    fExponentVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uExponent", stage);
+    fCosInnerConeAngleVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uCosInnerConeAngle", stage);
+    fCosOuterConeAngleVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uCosOuterConeAngle", stage);
+    fConeScaleVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kFloat_GrSLType, "uConeScale", stage);
+    fSVar = &state->addUniform(
+        GrGLShaderBuilder::kFragment_ShaderType,
+        kVec3f_GrSLType, "uS", stage);
+    state->addVarying(kFloat_GrSLType, "Height", stage, &fHeightVaryingName);
+}
+
+void GrGLSpotLight::initUniforms(const GrGLInterface* gl, int programID) {
+    INHERITED::initUniforms(gl, programID);
+    GR_GL_CALL_RET(gl, fLocationLocation,
+        GetUniformLocation(programID, fLocationVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fExponentLocation,
+        GetUniformLocation(programID, fExponentVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fCosInnerConeAngleLocation,
+        GetUniformLocation(programID, fCosInnerConeAngleVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation,
+        GetUniformLocation(programID, fCosOuterConeAngleVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation,
+        GetUniformLocation(programID, fCosOuterConeAngleVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fConeScaleLocation,
+        GetUniformLocation(programID, fConeScaleVar->getName().c_str()));
+    GR_GL_CALL_RET(gl, fSLocation,
+        GetUniformLocation(programID, fSVar->getName().c_str()));
+}
+
+void GrGLSpotLight::setData(const GrGLInterface* gl, const SkLight* light) const {
+    INHERITED::setData(gl, light);
+    SkASSERT(light->type() == SkLight::kSpot_LightType);
+    const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
+    setUniformPoint3(gl, fLocationLocation, spotLight->location());
+    GR_GL_CALL(gl, Uniform1f(fExponentLocation, spotLight->specularExponent()));
+    GR_GL_CALL(gl, Uniform1f(fCosInnerConeAngleLocation, spotLight->cosInnerConeAngle()));
+    GR_GL_CALL(gl, Uniform1f(fCosOuterConeAngleLocation, spotLight->cosOuterConeAngle()));
+    GR_GL_CALL(gl, Uniform1f(fConeScaleLocation, spotLight->coneScale()));
+    setUniformPoint3(gl, fSLocation, spotLight->s());
+}
+
+void GrGLSpotLight::emitVS(SkString* builder) const {
+    // Compute viewport height from the Y scale of the matrix.
+    builder->appendf("\t\t%s = -2.0 / uViewM[1][1];\n", fHeightVaryingName);
+}
+
+void GrGLSpotLight::emitFuncs(SkString* builder) const {
+    builder->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
+    builder->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", fSVar->getName().c_str());
+    builder->appendf("\tif (cosAngle < %s) {\n", fCosOuterConeAngleVar->getName().c_str());
+    builder->appendf("\t\treturn vec3(0);\n");
+    builder->appendf("\t}\n");
+    builder->appendf("\tfloat scale = pow(cosAngle, %s);\n", fExponentVar->getName().c_str());
+    builder->appendf("\tif (cosAngle < %s) {\n", fCosInnerConeAngleVar->getName().c_str());
+    builder->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", fColorVar->getName().c_str(), fCosOuterConeAngleVar->getName().c_str(), fConeScaleVar->getName().c_str());
+    builder->appendf("\t}\n");
+    builder->appendf("\treturn %s;\n", fColorVar->getName().c_str());
+    builder->appendf("}\n");
+}
+
+void GrGLSpotLight::emitSurfaceToLight(SkString* builder, const char* z) const {
+    builder->appendf("normalize(%s - vec3(gl_FragCoord.x, %s - gl_FragCoord.y, %s))", fLocationVar->getName().c_str(), fHeightVaryingName, z);
+}
+
+void GrGLSpotLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
+    builder->appendf("lightColor(%s)", surfaceToLight);
+}
+
 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)