Pull out Effect Shaders in GPU Path Renderer

Move the effects in HairLinePathRender (and eventually others into their
own class called GrBezierEffects. This will allow for more sharing of
code between different path renderers on GPU.

BUG=

Committed: http://code.google.com/p/skia/source/detail?r=10877

R=bsalomon@google.com, jvanverth@google.com, robertphillips@google.com

Author: egdaniel@google.com

Review URL: https://chromiumcodereview.appspot.com/23004010

git-svn-id: http://skia.googlecode.com/svn/trunk@10884 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
new file mode 100644
index 0000000..c5a12c9
--- /dev/null
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrBezierEffect.h"
+
+#include "gl/GrGLEffect.h"
+#include "gl/GrGLSL.h"
+#include "GrTBackendEffectFactory.h"
+
+class GrGLConicEffect : public GrGLEffect {
+public:
+    GrGLConicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
+
+    virtual void emitCode(GrGLShaderBuilder* builder,
+                          const GrDrawEffect& drawEffect,
+                          EffectKey key,
+                          const char* outputColor,
+                          const char* inputColor,
+                          const TextureSamplerArray&) SK_OVERRIDE;
+
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
+
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
+
+private:
+    GrBezierEdgeType fEdgeType;
+
+    typedef GrGLEffect INHERITED;
+};
+    
+GrGLConicEffect::GrGLConicEffect(const GrBackendEffectFactory& factory,
+                                 const GrDrawEffect& drawEffect)
+    : INHERITED (factory) {
+    const GrConicEffect& ce = drawEffect.castEffect<GrConicEffect>();
+    fEdgeType = ce.getEdgeType();
+}
+
+void GrGLConicEffect::emitCode(GrGLShaderBuilder* builder,
+                               const GrDrawEffect& drawEffect,
+                               EffectKey key,
+                               const char* outputColor,
+                               const char* inputColor,
+                               const TextureSamplerArray& samplers) {
+    const char *vsName, *fsName;
+
+    builder->addVarying(kVec4f_GrSLType, "ConicCoeffs",
+                        &vsName, &fsName);
+    const SkString* attr0Name =
+        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+
+    builder->fsCodeAppend("\t\tfloat edgeAlpha;\n");
+
+    switch (fEdgeType) {
+        case kHairAA_GrBezierEdgeType: {
+            SkAssertResult(builder->enableFeature(
+                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+                                   "\t\t\t2.0*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
+                                   fsName, fsName, fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+                                   "\t\t\t2.0*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
+                                   fsName, fsName, fsName);
+            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
+                                   fsName, fsName);
+            builder->fsCodeAppend("\t\tfunc = abs(func);\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            // Add line below for smooth cubic ramp
+            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            break;
+        }
+        case kFillAA_GrBezierEdgeType: {
+            SkAssertResult(builder->enableFeature(
+                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+                                   "\t\t\t2.0*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
+                                   fsName, fsName, fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+                                   "\t\t\t2.0*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
+                                   fsName, fsName, fsName);
+            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
+                                   fsName, fsName);
+            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
+            // Add line below for smooth cubic ramp
+            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            break;
+        }
+        case kFillNoAA_GrBezierEdgeType: {
+            builder->fsCodeAppendf("\t\tedgeAlpha = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
+                                   fsName, fsName);
+            builder->fsCodeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
+            break;
+        }
+    }
+
+    SkString modulate;
+    GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
+    builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+}
+
+GrGLEffect::EffectKey GrGLConicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+    const GrConicEffect& ce = drawEffect.castEffect<GrConicEffect>();
+    return ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrConicEffect::~GrConicEffect() {}
+
+const GrBackendEffectFactory& GrConicEffect::getFactory() const {
+    return GrTBackendEffectFactory<GrConicEffect>::getInstance();
+}
+
+GrConicEffect::GrConicEffect(GrBezierEdgeType edgeType) : GrEffect() {
+    this->addVertexAttrib(kVec4f_GrSLType);
+    fEdgeType = edgeType;
+}
+
+bool GrConicEffect::onIsEqual(const GrEffect& other) const {
+    const GrConicEffect& ce = CastEffect<GrConicEffect>(other);
+    return (ce.fEdgeType == fEdgeType);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrConicEffect);
+
+GrEffectRef* GrConicEffect::TestCreate(SkMWCRandom* random,
+                                             GrContext*,
+                                             const GrDrawTargetCaps& caps,
+                                             GrTexture*[]) {
+    const GrBezierEdgeType edgeType = static_cast<GrBezierEdgeType>(random->nextULessThan(3));
+    return GrConicEffect::Create(edgeType, caps);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Quad
+//////////////////////////////////////////////////////////////////////////////
+
+class GrGLQuadEffect : public GrGLEffect {
+public:
+    GrGLQuadEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
+
+    virtual void emitCode(GrGLShaderBuilder* builder,
+                          const GrDrawEffect& drawEffect,
+                          EffectKey key,
+                          const char* outputColor,
+                          const char* inputColor,
+                          const TextureSamplerArray&) SK_OVERRIDE;
+
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
+
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
+
+private:
+    GrBezierEdgeType fEdgeType;
+
+    typedef GrGLEffect INHERITED;
+};
+    
+GrGLQuadEffect::GrGLQuadEffect(const GrBackendEffectFactory& factory,
+                                 const GrDrawEffect& drawEffect)
+    : INHERITED (factory) {
+    const GrQuadEffect& ce = drawEffect.castEffect<GrQuadEffect>();
+    fEdgeType = ce.getEdgeType();
+}
+
+void GrGLQuadEffect::emitCode(GrGLShaderBuilder* builder,
+                              const GrDrawEffect& drawEffect,
+                              EffectKey key,
+                              const char* outputColor,
+                              const char* inputColor,
+                              const TextureSamplerArray& samplers) {
+    const char *vsName, *fsName;
+
+    const SkString* attrName =
+        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
+
+    builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
+
+    switch (fEdgeType) {
+        case kHairAA_GrBezierEdgeType: {
+            SkAssertResult(builder->enableFeature(
+                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+            builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                   "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                   fsName, fsName);
+            builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+                                   fsName);
+            builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            // Add line below for smooth cubic ramp
+            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            break;
+        }
+        case kFillAA_GrBezierEdgeType: {
+            SkAssertResult(builder->enableFeature(
+                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+            builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                   "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                   fsName, fsName);
+            builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+                                   fsName);
+            builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha / sqrt(dot(gF, gF));\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
+            // Add line below for smooth cubic ramp
+            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            break;
+        }
+        case kFillNoAA_GrBezierEdgeType: {
+            builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+                                   fsName);
+            builder->fsCodeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
+            break;
+        }
+    }
+
+    SkString modulate;
+    GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
+    builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+
+    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+}
+
+GrGLEffect::EffectKey GrGLQuadEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+    const GrQuadEffect& ce = drawEffect.castEffect<GrQuadEffect>();
+    return ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrQuadEffect::~GrQuadEffect() {}
+
+const GrBackendEffectFactory& GrQuadEffect::getFactory() const {
+    return GrTBackendEffectFactory<GrQuadEffect>::getInstance();
+}
+
+GrQuadEffect::GrQuadEffect(GrBezierEdgeType edgeType) : GrEffect() {
+    this->addVertexAttrib(kVec4f_GrSLType);
+    fEdgeType = edgeType;
+}
+
+bool GrQuadEffect::onIsEqual(const GrEffect& other) const {
+    const GrQuadEffect& ce = CastEffect<GrQuadEffect>(other);
+    return (ce.fEdgeType == fEdgeType);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrQuadEffect);
+
+GrEffectRef* GrQuadEffect::TestCreate(SkMWCRandom* random,
+                                             GrContext*,
+                                             const GrDrawTargetCaps& caps,
+                                             GrTexture*[]) {
+    const GrBezierEdgeType edgeType = static_cast<GrBezierEdgeType>(random->nextULessThan(3));
+    return GrQuadEffect::Create(edgeType, caps);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Cubic
+//////////////////////////////////////////////////////////////////////////////
+
+class GrGLCubicEffect : public GrGLEffect {
+public:
+    GrGLCubicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
+
+    virtual void emitCode(GrGLShaderBuilder* builder,
+                          const GrDrawEffect& drawEffect,
+                          EffectKey key,
+                          const char* outputColor,
+                          const char* inputColor,
+                          const TextureSamplerArray&) SK_OVERRIDE;
+
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
+
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
+
+private:
+    GrBezierEdgeType fEdgeType;
+
+    typedef GrGLEffect INHERITED;
+};
+    
+GrGLCubicEffect::GrGLCubicEffect(const GrBackendEffectFactory& factory,
+                                 const GrDrawEffect& drawEffect)
+    : INHERITED (factory) {
+    const GrCubicEffect& ce = drawEffect.castEffect<GrCubicEffect>();
+    fEdgeType = ce.getEdgeType();
+}
+
+void GrGLCubicEffect::emitCode(GrGLShaderBuilder* builder,
+                               const GrDrawEffect& drawEffect,
+                               EffectKey key,
+                               const char* outputColor,
+                               const char* inputColor,
+                               const TextureSamplerArray& samplers) {
+    const char *vsName, *fsName;
+
+    builder->addVarying(kVec4f_GrSLType, "CubicCoeffs",
+                        &vsName, &fsName);
+    const SkString* attr0Name =
+        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+
+    builder->fsCodeAppend("\t\tfloat edgeAlpha;\n");
+
+    switch (fEdgeType) {
+        case kHairAA_GrBezierEdgeType: {
+            SkAssertResult(builder->enableFeature(
+                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+                                   "\t\t3.0*%s.x*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
+                                   fsName, fsName, fsName, fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+                                   "\t\t3.0*%s.x*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
+                                   fsName, fsName, fsName, fsName);
+            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
+                                   fsName, fsName, fsName, fsName, fsName);
+            builder->fsCodeAppend("\t\tfunc = abs(func);\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            // Add line below for smooth cubic ramp
+            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            break;
+        }
+        case kFillAA_GrBezierEdgeType: {
+            SkAssertResult(builder->enableFeature(
+                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+                                   "\t\t3.0*%s.x*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
+                                   fsName, fsName, fsName, fsName);
+            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+                                   "\t\t3.0*%s.x*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
+                                   fsName, fsName, fsName, fsName);
+            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
+                                   fsName, fsName, fsName, fsName, fsName);
+            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
+            builder->fsCodeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
+            // Add line below for smooth cubic ramp
+            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            break;
+        }
+        case kFillNoAA_GrBezierEdgeType: {
+            builder->fsCodeAppendf("\t\tedgeAlpha = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
+                                   fsName, fsName, fsName, fsName, fsName);
+            builder->fsCodeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
+            break;
+        }
+    }
+
+    SkString modulate;
+    GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
+    builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+}
+
+GrGLEffect::EffectKey GrGLCubicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+    const GrCubicEffect& ce = drawEffect.castEffect<GrCubicEffect>();
+    return ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrCubicEffect::~GrCubicEffect() {}
+
+const GrBackendEffectFactory& GrCubicEffect::getFactory() const {
+    return GrTBackendEffectFactory<GrCubicEffect>::getInstance();
+}
+
+GrCubicEffect::GrCubicEffect(GrBezierEdgeType edgeType) : GrEffect() {
+    this->addVertexAttrib(kVec4f_GrSLType);
+    fEdgeType = edgeType;
+}
+
+bool GrCubicEffect::onIsEqual(const GrEffect& other) const {
+    const GrCubicEffect& ce = CastEffect<GrCubicEffect>(other);
+    return (ce.fEdgeType == fEdgeType);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrCubicEffect);
+
+GrEffectRef* GrCubicEffect::TestCreate(SkMWCRandom* random,
+                                             GrContext*,
+                                             const GrDrawTargetCaps& caps,
+                                             GrTexture*[]) {
+    const GrBezierEdgeType edgeType = static_cast<GrBezierEdgeType>(random->nextULessThan(3));
+    return GrCubicEffect::Create(edgeType, caps);
+}