uniquely name FS functions, add lighting effects to unit test
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 7 Aug 2012 17:36:29 +0000 (17:36 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 7 Aug 2012 17:36:29 +0000 (17:36 +0000)
Review URL: http://codereview.appspot.com/6458080/

git-svn-id: http://skia.googlecode.com/svn/trunk@4992 2bbb7eff-a529-9590-31e7-b0007b416f81

src/effects/SkLightingImageFilter.cpp
src/gpu/gl/GrGLSL.cpp
src/gpu/gl/GrGLSL.h
src/gpu/gl/GrGLShaderBuilder.cpp
src/gpu/gl/GrGLShaderBuilder.h
src/gpu/gl/GrGLShaderVar.h
tests/GLProgramsTest.cpp

index c590c26..9700249 100644 (file)
@@ -338,6 +338,7 @@ public:
     virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
     SkScalar kd() const { return fKD; }
 private:
+    GR_DECLARE_CUSTOM_STAGE_TEST;
     typedef GrLightingEffect INHERITED;
     SkScalar fKD;
 };
@@ -360,6 +361,7 @@ public:
     SkScalar shininess() const { return fShininess; }
 
 private:
+    GR_DECLARE_CUSTOM_STAGE_TEST;
     typedef GrLightingEffect INHERITED;
     SkScalar fKS;
     SkScalar fShininess;
@@ -372,12 +374,11 @@ public:
     virtual ~GrGLLight() {}
     virtual void setupVariables(GrGLShaderBuilder* builder);
     virtual void emitVS(SkString* out) const {}
-    virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {}
+    virtual void emitFuncs(GrGLShaderBuilder* builder) {}
     virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
                                     SkString* out,
                                     const char* z) const = 0;
-    virtual void emitLightColor(const GrGLShaderBuilder*,
-                                SkString* out,
+    virtual void emitLightColor(GrGLShaderBuilder*,
                                 const char *surfaceToLight) const;
     virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const;
 
@@ -428,17 +429,17 @@ public:
     virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
     virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
     virtual void emitVS(SkString* out) const SK_OVERRIDE;
-    virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
+    virtual void emitFuncs(GrGLShaderBuilder* builder);
     virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
                                     SkString* out,
                                     const char* z) const SK_OVERRIDE;
-    virtual void emitLightColor(const GrGLShaderBuilder*,
-                                SkString* out,
+    virtual void emitLightColor(GrGLShaderBuilder*,
                                 const char *surfaceToLight) const SK_OVERRIDE;
 
 private:
     typedef GrGLLight INHERITED;
 
+    SkString        fLightColorFunc;
     UniformHandle   fLocationUni;
     UniformHandle   fExponentUni;
     UniformHandle   fCosOuterConeAngleUni;
@@ -905,6 +906,38 @@ bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
 ///////////////////////////////////////////////////////////////////////////////
 
 #if SK_SUPPORT_GPU
+
+namespace {
+SkPoint3 random_point3(SkRandom* random) {
+    return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
+                    SkScalarToFloat(random->nextSScalar1()),
+                    SkScalarToFloat(random->nextSScalar1()));
+}
+
+SkLight* create_random_light(SkRandom* random) {
+    int type = random->nextULessThan(3);
+    switch (type) {
+        case 0: {
+            return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
+        }
+        case 1: {
+            return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
+        }
+        case 2: {
+            return SkNEW_ARGS(SkSpotLight, (random_point3(random),
+                                            random_point3(random),
+                                            random->nextUScalar1(),
+                                            random->nextUScalar1(), 
+                                            random->nextU()));
+        }
+        default:
+            GrCrash();
+            return NULL;
+    }
+}
+
+}
+
 class GrGLLightingEffect  : public GrGLProgramStage {
 public:
     GrGLLightingEffect(const GrProgramStageFactory& factory,
@@ -919,7 +952,7 @@ public:
                         const char* inputColor,
                         const char* samplerName) SK_OVERRIDE;
 
-    virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
+    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
 
     static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
 
@@ -943,7 +976,7 @@ public:
     GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
                               const GrCustomStage& stage);
     virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
-    virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
+    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
     virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
@@ -962,7 +995,7 @@ public:
     GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
                                const GrCustomStage& stage);
     virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
-    virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
+    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
     virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
@@ -1013,6 +1046,19 @@ bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
             this->kd() == s.kd();
 }
 
+GR_DEFINE_CUSTOM_STAGE_TEST(GrDiffuseLightingEffect);
+
+GrCustomStage* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
+                                                   GrContext* context,
+                                                   GrTexture* textures[]) {
+    SkScalar surfaceScale = random->nextSScalar1();
+    SkScalar kd = random->nextUScalar1();
+    SkAutoTUnref<SkLight> light(create_random_light(random));
+    return SkNEW_ARGS(GrDiffuseLightingEffect, (textures[GrCustomStageUnitTest::kAlphaTextureIdx],
+                                                light, surfaceScale, kd));
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
@@ -1048,20 +1094,59 @@ void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
                                 const char* inputColor,
                                 const char* samplerName) {
     SkString* code = &builder->fFSCode;
-    SkString* funcs = &builder->fFSFunctions;
-    fLight->emitFuncs(builder, funcs);
-    this->emitLightFunc(builder, 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.0 * c + 2.0 * 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");
+    fLight->emitFuncs(builder);
+    SkString lightFunc;
+    this->emitLightFunc(builder, &lightFunc);
+    static const GrGLShaderVar gSobelArgs[] =  {
+        GrGLShaderVar("a", kFloat_GrSLType),
+        GrGLShaderVar("b", kFloat_GrSLType),
+        GrGLShaderVar("c", kFloat_GrSLType),
+        GrGLShaderVar("d", kFloat_GrSLType),
+        GrGLShaderVar("e", kFloat_GrSLType),
+        GrGLShaderVar("f", kFloat_GrSLType),
+        GrGLShaderVar("scale", kFloat_GrSLType),
+    };
+    SkString sobelFuncName;
+    builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
+                          kFloat_GrSLType,
+                          "sobel",
+                          SK_ARRAY_COUNT(gSobelArgs),
+                          gSobelArgs,
+                          "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
+                          &sobelFuncName);
+    static const GrGLShaderVar gPointToNormalArgs[] =  {
+        GrGLShaderVar("x", kFloat_GrSLType),
+        GrGLShaderVar("y", kFloat_GrSLType),
+        GrGLShaderVar("scale", kFloat_GrSLType),
+    };
+    SkString pointToNormalName;
+    builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
+                          kVec3f_GrSLType,
+                          "pointToNormal",
+                          SK_ARRAY_COUNT(gPointToNormalArgs),
+                          gPointToNormalArgs,
+                          "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
+                          &pointToNormalName);
+
+    static const GrGLShaderVar gInteriorNormalArgs[] =  {
+        GrGLShaderVar("m", kFloat_GrSLType, 9),
+        GrGLShaderVar("surfaceScale", kFloat_GrSLType),
+    };
+    SkString interiorNormalBody;
+    interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
+                               "\t       %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
+                               "\t       surfaceScale);\n",
+                                pointToNormalName.c_str(),
+                                sobelFuncName.c_str(),
+                                sobelFuncName.c_str());
+    SkString interiorNormalName;
+    builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
+                          kVec3f_GrSLType,
+                          "interiorNormal",
+                          SK_ARRAY_COUNT(gInteriorNormalArgs),
+                          gInteriorNormalArgs,
+                          interiorNormalBody.c_str(),
+                          &interiorNormalName);
 
     code->appendf("\t\tvec2 coord = %s;\n", builder->fSampleCoords.c_str());
     code->appendf("\t\tfloat m[9];\n");
@@ -1084,8 +1169,9 @@ vec3 interiorNormal(float m[9], float surfaceScale) {\n\
     arg.appendf("%s * m[4]", surfScale);
     fLight->emitSurfaceToLight(builder, code, arg.c_str());
     code->appendf(";\n");
-    code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, surfScale);
-    fLight->emitLightColor(builder, code, "surfaceToLight");
+    code->appendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
+                  outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
+    fLight->emitLightColor(builder, "surfaceToLight");
     code->appendf(")%s;\n", builder->fModulate.c_str());
 }
 
@@ -1122,12 +1208,23 @@ void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
     fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "KD");
 }
 
-void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
+void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
     const char* kd = builder->getUniformCStr(fKDUni);
-    funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
-    funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
-    funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
-    funcs->appendf("}\n");
+    static const GrGLShaderVar gLightArgs[] = {
+        GrGLShaderVar("normal", kVec3f_GrSLType),
+        GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
+        GrGLShaderVar("lightColor", kVec3f_GrSLType)
+    };
+    SkString lightBody;
+    lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
+    lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
+    builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
+                          kVec4f_GrSLType,
+                          "light",
+                          SK_ARRAY_COUNT(gLightArgs),
+                          gLightArgs,
+                          lightBody.c_str(),
+                          funcName);
 }
 
 void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
@@ -1160,6 +1257,19 @@ bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
            this->shininess() == s.shininess();
 }
 
+GR_DEFINE_CUSTOM_STAGE_TEST(GrSpecularLightingEffect);
+
+GrCustomStage* GrSpecularLightingEffect::TestCreate(SkRandom* random,
+                                                    GrContext* context,
+                                                    GrTexture* textures[]) {
+    SkScalar surfaceScale = random->nextSScalar1();
+    SkScalar ks = random->nextUScalar1();
+    SkScalar shininess = random->nextUScalar1();
+    SkAutoTUnref<SkLight> light(create_random_light(random));
+    return SkNEW_ARGS(GrSpecularLightingEffect, (textures[GrCustomStageUnitTest::kAlphaTextureIdx],
+                                                 light, surfaceScale, ks, shininess));
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
@@ -1177,15 +1287,26 @@ void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
                                         kFloat_GrSLType, "Shininess");
 }
 
-void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, 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");
-
+void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
     const char* ks = builder->getUniformCStr(fKSUni);
     const char* shininess = builder->getUniformCStr(fShininessUni);
-    funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
-    funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
-    funcs->appendf("}\n");
+
+    static const GrGLShaderVar gLightArgs[] = {
+        GrGLShaderVar("normal", kVec3f_GrSLType),
+        GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
+        GrGLShaderVar("lightColor", kVec3f_GrSLType)
+    };
+    SkString lightBody;
+    lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
+    lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
+    lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
+    builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
+                          kVec4f_GrSLType,
+                          "light",
+                          SK_ARRAY_COUNT(gLightArgs),
+                          gLightArgs,
+                          lightBody.c_str(),
+                          funcName);
 }
 
 void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
@@ -1200,11 +1321,10 @@ void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGLLight::emitLightColor(const GrGLShaderBuilder* builder,
-                               SkString* out,
+void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
                                const char *surfaceToLight) const {
     const char* color = builder->getUniformCStr(fColorUni);
-    out->append(color);
+    builder->fFSCode.append(color);
 }
 
 void GrGLLight::setupVariables(GrGLShaderBuilder* builder) {
@@ -1304,25 +1424,34 @@ void GrGLSpotLight::setData(const GrGLUniformManager& uman,
 void GrGLSpotLight::emitVS(SkString* out) const {
 }
 
-void GrGLSpotLight::emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {
+void GrGLSpotLight::emitFuncs(GrGLShaderBuilder* builder) {
     const char* exponent = builder->getUniformCStr(fExponentUni);
     const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
     const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
     const char* coneScale = builder->getUniformCStr(fConeScaleUni);
     const char* s = builder->getUniformCStr(fSUni);
     const char* color = builder->getUniformCStr(fColorUni);
-
-    out->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
-    out->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
-    out->appendf("\tif (cosAngle < %s) {\n", cosOuter);
-    out->appendf("\t\treturn vec3(0);\n");
-    out->appendf("\t}\n");
-    out->appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
-    out->appendf("\tif (cosAngle < %s) {\n", cosInner);
-    out->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", color, cosOuter, coneScale);
-    out->appendf("\t}\n");
-    out->appendf("\treturn %s;\n", color);
-    out->appendf("}\n");
+    static const GrGLShaderVar gLightColorArgs[] = {
+        GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
+    };
+    SkString lightColorBody;
+    lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
+    lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
+    lightColorBody.appendf("\t\treturn vec3(0);\n");
+    lightColorBody.appendf("\t}\n");
+    lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
+    lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
+    lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
+                           color, cosOuter, coneScale);
+    lightColorBody.appendf("\t}\n");
+    lightColorBody.appendf("\treturn %s;\n", color);
+    builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
+                          kVec3f_GrSLType,
+                          "lightColor",
+                          SK_ARRAY_COUNT(gLightColorArgs),
+                          gLightColorArgs,
+                          lightColorBody.c_str(),
+                          &fLightColorFunc);
 }
 
 void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
@@ -1332,9 +1461,9 @@ void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
     out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
 }
 
-void GrGLSpotLight::emitLightColor(const GrGLShaderBuilder* builder,
-                                   SkString* out, const char *surfaceToLight) const {
-    out->appendf("lightColor(%s)", surfaceToLight);
+void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
+                                   const char *surfaceToLight) const {
+    builder->fFSCode.appendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
 }
 
 #endif
index 759a17c..ff4d498 100644 (file)
@@ -66,12 +66,12 @@ bool GrGLSLSetupFSColorOuput(GrGLSLGeneration gen,
 }
 
 GrSLType GrSLFloatVectorType (int count) {
-    GR_STATIC_ASSERT(kFloat_GrSLType == 0);
-    GR_STATIC_ASSERT(kVec2f_GrSLType == 1);
-    GR_STATIC_ASSERT(kVec3f_GrSLType == 2);
-    GR_STATIC_ASSERT(kVec4f_GrSLType == 3);
+    GR_STATIC_ASSERT(kFloat_GrSLType == 1);
+    GR_STATIC_ASSERT(kVec2f_GrSLType == 2);
+    GR_STATIC_ASSERT(kVec3f_GrSLType == 3);
+    GR_STATIC_ASSERT(kVec4f_GrSLType == 4);
     GrAssert(count > 0 && count <= 4);
-    return (GrSLType)(count - 1);
+    return (GrSLType)(count);
 }
 
 const char* GrGLSLVectorHomogCoord(int count) {
index 7b92c23..a58f7e8 100644 (file)
@@ -35,6 +35,7 @@ enum GrGLSLGeneration {
  * langauges.)
  */
 enum GrSLType {
+    kVoid_GrSLType,
     kFloat_GrSLType,
     kVec2f_GrSLType,
     kVec3f_GrSLType,
index 3ca4086..167eb78 100644 (file)
@@ -291,6 +291,32 @@ void GrGLShaderBuilder::addVarying(GrSLType type,
     }
 }
 
+void GrGLShaderBuilder::emitFunction(ShaderType shader,
+                                     GrSLType returnType,
+                                     const char* name,
+                                     int argCnt,
+                                     const GrGLShaderVar* args,
+                                     const char* body,
+                                     SkString* outName) {
+    GrAssert(kFragment_ShaderType == shader);
+    fFSFunctions.append(GrGLShaderVar::TypeString(returnType));
+    if (kNonStageIdx != fCurrentStage) {
+        outName->printf(" %s_%d", name, fCurrentStage);
+    } else {
+        *outName = name;
+    }
+    fFSFunctions.append(*outName);
+    fFSFunctions.append("(");
+    for (int i = 0; i < argCnt; ++i) {
+        args[i].appendDecl(fContext, &fFSFunctions);
+        if (i < argCnt - 1) {
+            fFSFunctions.append(", ");
+        }
+    }
+    fFSFunctions.append(") {\n");
+    fFSFunctions.append(body);
+    fFSFunctions.append("}\n\n");
+}
 
 namespace {
 
@@ -321,6 +347,7 @@ inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
 void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
     for (int i = 0; i < vars.count(); ++i) {
         vars[i].appendDecl(fContext, out);
+        out->append(";\n");
     }
 }
 
@@ -328,6 +355,7 @@ void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) cons
     for (int i = 0; i < fUniforms.count(); ++i) {
         if (fUniforms[i].fVisibility & stype) {
             fUniforms[i].fVariable.appendDecl(fContext, out);
+            out->append(";\n");
         }
     }
 }
index ab0792b..31d603a 100644 (file)
@@ -66,6 +66,16 @@ public:
                                  const char* samplerName,
                                  const char* coordName);
 
+    /** Emits a helper function outside of main(). Currently ShaderType must be
+        kFragment_ShaderType. */
+    void emitFunction(ShaderType shader,
+                      GrSLType returnType,
+                      const char* name,
+                      int argCnt,
+                      const GrGLShaderVar* args,
+                      const char* body,
+                      SkString* outName);
+
     /** Generates a StageKey for the shader code based on the texture access parameters and the
         capabilities of the GL context.  This is useful for keying the shader programs that may
         have multiple representations, based on the type/format of textures used. */
@@ -144,7 +154,6 @@ public:
     VarArray    fFSInputs;
     SkString    fGSHeader; // layout qualifiers specific to GS
     VarArray    fFSOutputs;
-    SkString    fFSFunctions;
     SkString    fVSCode;
     SkString    fGSCode;
     SkString    fFSCode;
@@ -176,6 +185,7 @@ private:
     const GrGLContextInfo&  fContext;
     GrGLUniformManager&     fUniformManager;
     int                     fCurrentStage;
+    SkString                fFSFunctions;
 };
 
 #endif
index 0231d21..92d7ee0 100644 (file)
@@ -55,13 +55,25 @@ public:
         fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
     }
 
+    GrGLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray) {
+        GrAssert(kVoid_GrSLType != type);
+        fType = type;
+        fTypeModifier = kNone_TypeModifier;
+        fCount = arrayCount;
+        fPrecision = kDefault_Precision;
+        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
+        fName = name;
+    }
+
     GrGLShaderVar(const GrGLShaderVar& var)
         : fType(var.fType)
         , fTypeModifier(var.fTypeModifier)
         , fName(var.fName)
         , fCount(var.fCount)
         , fPrecision(var.fPrecision)
-        , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {}
+        , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {
+        GrAssert(kVoid_GrSLType != var.fType);
+    }
 
     /**
      * Values for array count that have special meaning. We allow 1-sized arrays.
@@ -79,6 +91,7 @@ public:
              const SkString& name,
              Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+        GrAssert(kVoid_GrSLType != type);
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
@@ -95,6 +108,7 @@ public:
              const char* name,
              Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+        GrAssert(kVoid_GrSLType != type);
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
@@ -112,6 +126,7 @@ public:
              int count,
              Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+        GrAssert(kVoid_GrSLType != type);
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
@@ -129,6 +144,7 @@ public:
              int count,
              Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+        GrAssert(kVoid_GrSLType != type);
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
@@ -232,11 +248,12 @@ public:
                          TypeString(effectiveType),
                          this->getName().c_str());
         }
-        out->append(";\n");
     }
 
     static const char* TypeString(GrSLType t) {
         switch (t) {
+            case kVoid_GrSLType:
+                return "void";
             case kFloat_GrSLType:
                 return "float";
             case kVec2f_GrSLType:
index 1228b4e..79c3faf 100644 (file)
@@ -13,8 +13,8 @@
 #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
 
 #include "gl/GrGpuGL.h"
-#include "SkLightingImageFilter.h"
 #include "GrProgramStageFactory.h"
+
 #include "GrRandom.h"
 #include "Test.h"
 
@@ -35,10 +35,6 @@ bool random_bool(GrRandom* r) {
     return r->nextF() > .5f;
 }
 
-SkPoint3 random_point3(GrRandom* r) {
-    return SkPoint3(r->nextF(), r->nextF(), r->nextF());
-}
-
 typedef GrGLProgram::StageDesc StageDesc;
 // TODO: Effects should be able to register themselves for inclusion in the
 // randomly generated shaders. They should be able to configure themselves
@@ -47,23 +43,6 @@ const GrCustomStage* create_random_effect(StageDesc* stageDesc,
                                           GrRandom* random,
                                           GrContext* context,
                                           GrTexture* dummyTextures[]) {
-    enum EffectType {
-        /**
-         * Lighting effects don't work in unit test because they assume they insert functions and
-         * assume the names are unique. This breaks when there are two light effects in the same
-         * shader.
-         */
-        /*
-        kDiffuseDistant_EffectType,
-        kDiffusePoint_EffectType,
-        kDiffuseSpot_EffectType,
-        kSpecularDistant_EffectType,
-        kSpecularPoint_EffectType,
-        kSpecularSpot_EffectType,
-        */
-
-        kEffectCount
-    };
 
     // TODO: Remove this when generator doesn't apply this non-custom-stage
     // notion to custom stages automatically.
@@ -75,112 +54,11 @@ const GrCustomStage* create_random_effect(StageDesc* stageDesc,
     // TODO: Remove GrRandom.
     SkRandom sk_random;
     sk_random.setSeed(random->nextU());
-
-    bool useFactory = random_bool(random);
-    if (useFactory) {
-        GrCustomStage* stage = GrCustomStageTestFactory::CreateStage(&sk_random,
-                                                                     context,
-                                                                     dummyTextures);
-        GrAssert(stage);
-        return stage;
-    }
-
-
-    // TODO: When matrices are property of the custom-stage then remove the
-    // no-persp flag code below.
-    int effect = random_int(random, kEffectCount);
-/*    switch (effect) {
-        case kDiffuseDistant_EffectType: {
-            SkPoint3 direction = random_point3(random);
-            direction.normalize();
-            SkColor lightColor = random->nextU();
-            SkScalar surfaceScale = SkFloatToScalar(random->nextF());
-            SkScalar kd = SkFloatToScalar(random->nextF());
-            SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
-            // does not work with perspective or mul-by-alpha-mask
-            GrCustomStage* stage;
-            bool ok = filter->asNewCustomStage(&stage, NULL);
-            SkASSERT(ok);
-            return stage;
-        }
-        case kDiffusePoint_EffectType: {
-            SkPoint3 location = random_point3(random);
-            SkColor lightColor = random->nextU();
-            SkScalar surfaceScale = SkFloatToScalar(random->nextF());
-            SkScalar kd = SkFloatToScalar(random->nextF());
-            SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
-            // does not work with perspective or mul-by-alpha-mask
-            GrCustomStage* stage;
-            bool ok = filter->asNewCustomStage(&stage, NULL);
-            SkASSERT(ok);
-            return stage;
-        }
-        case kDiffuseSpot_EffectType: {
-            SkPoint3 location = random_point3(random);
-            SkPoint3 target = random_point3(random);
-            SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
-            SkScalar specularExponent = SkFloatToScalar(random->nextF());
-            SkColor lightColor = random->nextU();
-            SkScalar surfaceScale = SkFloatToScalar(random->nextF());
-            SkScalar ks = SkFloatToScalar(random->nextF());
-            SkScalar shininess = SkFloatToScalar(random->nextF());
-            SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
-                location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
-            // does not work with perspective or mul-by-alpha-mask
-            GrCustomStage* stage;
-            bool ok = filter->asNewCustomStage(&stage, NULL);
-            SkASSERT(ok);
-            return stage;
-        }
-        case kSpecularDistant_EffectType: {
-            SkPoint3 direction = random_point3(random);
-            direction.normalize();
-            SkColor lightColor = random->nextU();
-            SkScalar surfaceScale = SkFloatToScalar(random->nextF());
-            SkScalar ks = SkFloatToScalar(random->nextF());
-            SkScalar shininess = SkFloatToScalar(random->nextF());
-            SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
-            // does not work with perspective or mul-by-alpha-mask
-            GrCustomStage* stage;
-            bool ok = filter->asNewCustomStage(&stage, NULL);
-            SkASSERT(ok);
-            return stage;
-        }
-        case kSpecularPoint_EffectType: {
-            SkPoint3 location = random_point3(random);
-            SkColor lightColor = random->nextU();
-            SkScalar surfaceScale = SkFloatToScalar(random->nextF());
-            SkScalar ks = SkFloatToScalar(random->nextF());
-            SkScalar shininess = SkFloatToScalar(random->nextF());
-            SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
-            // does not work with perspective or mul-by-alpha-mask
-            GrCustomStage* stage;
-            bool ok = filter->asNewCustomStage(&stage, NULL);
-            SkASSERT(ok);
-            return stage;
-        }
-        case kSpecularSpot_EffectType: {
-            SkPoint3 location = random_point3(random);
-            SkPoint3 target = random_point3(random);
-            SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
-            SkScalar specularExponent = SkFloatToScalar(random->nextF());
-            SkColor lightColor = random->nextU();
-            SkScalar surfaceScale = SkFloatToScalar(random->nextF());
-            SkScalar ks = SkFloatToScalar(random->nextF());
-            SkScalar shininess = SkFloatToScalar(random->nextF());
-            SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
-                location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
-            // does not work with perspective or mul-by-alpha-mask
-            GrCustomStage* stage;
-            bool ok = filter->asNewCustomStage(&stage, NULL);
-            SkASSERT(ok);
-            return stage;
-        }
-        default:
-            GrCrash("Unexpected custom effect type");
-    }
-    */
-    return NULL;
+    GrCustomStage* stage = GrCustomStageTestFactory::CreateStage(&sk_random,
+                                                                    context,
+                                                                    dummyTextures);
+    GrAssert(stage);
+    return stage;
 }
 }
 
@@ -321,4 +199,17 @@ static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
 #include "TestClassDef.h"
 DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
 
+// This is evil evil evil. The linker may throw away whole translation units as dead code if it 
+// thinks none of the functions are called. It will do this even if there are static initilializers
+// in the unit that could pass pointers to functions from the unit out to other translation units!
+// We force some of the effects that would otherwise be discarded to link here.
+
+#include "SkLightingImageFilter.h"
+
+void forceLinking();
+
+void forceLinking() {
+    SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
+}
+
 #endif