Add GrEllipseEdgeEffect.

Adds the effect that replaces the old oval rendering code. Also hooks in code to set attribute names and indices for effects.

Author: jvanverth@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@8092 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLEffect.cpp b/src/gpu/gl/GrGLEffect.cpp
index ccea269..f2cd37c 100644
--- a/src/gpu/gl/GrGLEffect.cpp
+++ b/src/gpu/gl/GrGLEffect.cpp
@@ -31,3 +31,18 @@
     }
     return key;
 }
+
+GrGLEffect::EffectKey GrGLEffect::GenAttribKey(const GrEffectStage& stage) {
+    EffectKey key = 0;
+
+    int numAttributes = stage.getVertexAttribIndexCount();
+    GrAssert(numAttributes <= 2);
+    const int* attributeIndices = stage.getVertexAttribIndices();
+    for (int index = 0; index < numAttributes; ++index) {
+        EffectKey value = attributeIndices[index] << 2*index;
+        GrAssert(0 == (value & key)); // keys for each attribute ought not to overlap
+        key |= value;
+    }
+
+    return key;
+}
diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h
index 76f865e..869fbda 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -87,6 +87,7 @@
     const char* name() const { return fFactory.name(); }
 
     static EffectKey GenTextureKey(const GrEffectRef*, const GrGLCaps&);
+    static EffectKey GenAttribKey(const GrEffectStage& stage);
 
    /**
     * GrGLEffect subclasses get passed a GrEffectStage in their emitCode and setData functions.
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 2b6ccbd..c164357 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -419,9 +419,7 @@
     if (fDesc.fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
         const char *vsName, *fsName;
         builder->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName);
-        builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
-                                          GrGLShaderVar::kAttribute_TypeModifier,
-                                          EDGE_ATTR_NAME);
+        builder->addAttribute(kVec4f_GrSLType, EDGE_ATTR_NAME);
         builder->vsCodeAppendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
         switch (fDesc.fVertexEdgeType) {
         case GrDrawState::kHairLine_EdgeType:
@@ -467,13 +465,6 @@
             builder->fsCodeAppendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
             builder->fsCodeAppend("\tedgeAlpha = outerAlpha * innerAlpha;\n");
             break;
-        case GrDrawState::kEllipse_EdgeType:
-            builder->fsCodeAppend("\tfloat edgeAlpha;\n");
-            builder->fsCodeAppendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName);
-            builder->fsCodeAppendf("\toffset.y *= %s.w;\n", fsName);
-            builder->fsCodeAppend("\tfloat d = length(offset);\n");
-            builder->fsCodeAppendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
-            break;
         default:
             GrCrash("Unknown Edge Type!");
             break;
@@ -492,9 +483,7 @@
 void GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString* inColor) {
     switch (fDesc.fColorInput) {
         case GrGLProgram::Desc::kAttribute_ColorInput: {
-            builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
-                GrGLShaderVar::kAttribute_TypeModifier,
-                COL_ATTR_NAME);
+            builder->addAttribute(kVec4f_GrSLType, COL_ATTR_NAME);
             const char *vsName, *fsName;
             builder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
             builder->vsCodeAppendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
@@ -534,9 +523,7 @@
 namespace {
 void gen_attribute_coverage(GrGLShaderBuilder* builder,
                             SkString* inOutCoverage) {
-    builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
-                                      GrGLShaderVar::kAttribute_TypeModifier,
-                                      COV_ATTR_NAME);
+    builder->addAttribute(kVec4f_GrSLType, COV_ATTR_NAME);
     const char *vsName, *fsName;
     builder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
     builder->vsCodeAppendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
@@ -777,9 +764,7 @@
 
     // add texture coordinates that are used to the list of vertex attr decls
     if (GrDrawState::AttributesBindExplicitTexCoords(attribBindings)) {
-        builder.fVSAttrs.push_back().set(kVec2f_GrSLType,
-            GrGLShaderVar::kAttribute_TypeModifier,
-            TEX_ATTR_NAME);
+        builder.addAttribute(kVec2f_GrSLType, TEX_ATTR_NAME);
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -917,6 +902,11 @@
                     inCoverage = outCoverage;
                 }
             }
+
+            // discard if coverage is zero
+            if (fDesc.fDiscardIfOutsideEdge && !outCoverage.isEmpty()) {
+                builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", outCoverage.c_str());
+            }
         }
 
         if (Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) {
@@ -1022,6 +1012,13 @@
         GL_CALL(BindAttribLocation(fProgramID, fDesc.fTexCoordAttributeIndex, TEX_ATTR_NAME));
     }
 
+    const GrGLShaderBuilder::AttributePair* attribEnd = builder.getEffectAttributes().end();
+    for (const GrGLShaderBuilder::AttributePair* attrib = builder.getEffectAttributes().begin(); 
+         attrib != attribEnd;
+         ++attrib) {
+         GL_CALL(BindAttribLocation(fProgramID, attrib->fIndex, attrib->fName.c_str()));
+    }
+
     GL_CALL(LinkProgram(fProgramID));
 
     GrGLint linked = GR_GL_INIT_ZERO;
diff --git a/src/gpu/gl/GrGLSL.h b/src/gpu/gl/GrGLSL.h
index 4559fdd..940501c 100644
--- a/src/gpu/gl/GrGLSL.h
+++ b/src/gpu/gl/GrGLSL.h
@@ -9,6 +9,7 @@
 #define GrGLSL_DEFINED
 
 #include "gl/GrGLInterface.h"
+#include "GrTypesPriv.h"
 
 class GrGLShaderVar;
 class SkString;
@@ -34,22 +35,6 @@
     k150_GrGLSLGeneration,
 };
 
-/**
- * Types of shader-language-specific boxed variables we can create.
- * (Currently only GrGLShaderVars, but should be applicable to other shader
- * languages.)
- */
-enum GrSLType {
-    kVoid_GrSLType,
-    kFloat_GrSLType,
-    kVec2f_GrSLType,
-    kVec3f_GrSLType,
-    kVec4f_GrSLType,
-    kMat33f_GrSLType,
-    kMat44f_GrSLType,
-    kSampler2D_GrSLType
-};
-
 enum GrSLConstantVec {
     kZeros_GrSLConstantVec,
     kOnes_GrSLConstantVec,
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 5c3f5b3..1a238ae 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -258,6 +258,22 @@
     return fUniforms[handle_to_index(u)].fVariable;
 }
 
+bool GrGLShaderBuilder::addAttribute(GrSLType type,
+                                     const char* name) {
+    for (int i = 0; i < fVSAttrs.count(); ++i) {
+        const GrGLShaderVar& attr = fVSAttrs[i];
+        // if attribute already added, don't add it again
+        if (attr.getName().equals(name)) {
+            GrAssert(attr.getType() == type);
+            return false;
+        }
+    }
+    fVSAttrs.push_back().set(type,
+                             GrGLShaderVar::kAttribute_TypeModifier,
+                             name);
+    return true;
+}
+
 void GrGLShaderBuilder::addVarying(GrSLType type,
                                    const char* name,
                                    const char** vsOutName,
@@ -491,6 +507,18 @@
         samplerHandles->push_back(textureSamplers[i].fSamplerUniform);
     }
 
+    int numAttributes = stage.getVertexAttribIndexCount();
+    const int* attributeIndices = stage.getVertexAttribIndices();
+    SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames;
+    for (int i = 0; i < numAttributes; ++i) {
+        SkString attributeName("aAttr");
+        attributeName.appendS32(attributeIndices[i]);
+
+        if (this->addAttribute(effect->vertexAttribType(i), attributeName.c_str())) {
+            fEffectAttributes.push_back().set(attributeIndices[i], attributeName);
+        }
+    }
+
     GrGLEffect* glEffect = effect->getFactory().createGLInstance(effect);
 
     // Enclose custom code in a block to avoid namespace conflicts
@@ -508,3 +536,16 @@
 
     return glEffect;
 }
+
+const SkString* GrGLShaderBuilder::getEffectAttributeName(int attributeIndex) const {
+    const AttributePair* attribEnd = this->getEffectAttributes().end();
+    for (const AttributePair* attrib = this->getEffectAttributes().begin(); 
+         attrib != attribEnd;
+         ++attrib) {
+        if (attrib->fIndex == attributeIndex) {
+            return &attrib->fName;
+        }
+    }   
+
+    return NULL;
+}
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 08b3ef5..524a885 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -184,7 +184,11 @@
         return this->getUniformVariable(u).c_str();
     }
 
-    /** Add a varying variable to the current program to pass values between vertex and fragment
+   /** Add a vertex attribute to the current program that is passed in from the vertex data.
+       Returns false if the attribute was already there, true otherwise. */
+    bool addAttribute(GrSLType type, const char* name);
+
+   /** Add a varying variable to the current program to pass values between vertex and fragment
         shaders. If the last two parameters are non-NULL, they are filled in with the name
         generated. */
     void addVarying(GrSLType type,
@@ -222,6 +226,19 @@
                                 const char* vsInCoord,
                                 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
     GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
+
+    struct AttributePair {
+        void set(int index, const SkString& name) {
+            fIndex = index; fName = name;
+        }
+        int      fIndex;
+        SkString fName;
+    };
+    const SkSTArray<10, AttributePair, true>& getEffectAttributes() const {
+        return fEffectAttributes;
+    }
+    const SkString* getEffectAttributeName(int attributeIndex) const;
+
     // TODO: Make this do all the compiling, linking, etc.
     void finished(GrGLuint programID);
 
@@ -270,6 +287,8 @@
     bool                                fSetupFragPosition;
     GrGLUniformManager::UniformHandle   fRTHeightUniform;
 
+    SkSTArray<10, AttributePair, true>  fEffectAttributes;
+
     GrGLShaderVar*                      fPositionVar;
 };