Refactor how precision is handled with GrGLShaderVar

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


git-svn-id: http://skia.googlecode.com/svn/trunk@4575 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLSL.cpp b/src/gpu/gl/GrGLSL.cpp
index 21dd940..759a17c 100644
--- a/src/gpu/gl/GrGLSL.cpp
+++ b/src/gpu/gl/GrGLSL.cpp
@@ -55,22 +55,6 @@
     }
 }
 
-const char* GrGetGLSLVarPrecisionDeclType(GrGLBinding binding) {
-    if (kES2_GrGLBinding == binding) {
-        return "mediump";
-    } else {
-        return " ";
-    }
-}
-
-const char* GrGetGLSLShaderPrecisionDecl(GrGLBinding binding) {
-    if (kES2_GrGLBinding == binding) {
-        return "precision mediump float;\n";
-    } else {
-        return "";
-    }
-}
-
 bool GrGLSLSetupFSColorOuput(GrGLSLGeneration gen,
                              const char* nameIfDeclared,
                              GrGLShaderVar* var) {
diff --git a/src/gpu/gl/GrGLSL.h b/src/gpu/gl/GrGLSL.h
index 587d6f2..7b92c23 100644
--- a/src/gpu/gl/GrGLSL.h
+++ b/src/gpu/gl/GrGLSL.h
@@ -58,18 +58,6 @@
                                  GrGLSLGeneration v);
 
 /**
- * Returns a string to include in a variable decleration to set the fp precision
- * or an emptry string if precision is not required.
- */
-const char* GrGetGLSLVarPrecisionDeclType(GrGLBinding binding);
-
-/**
- * Returns a string to set the default fp precision for an entire shader, or
- * an emptry string if precision is not required.
- */
-const char* GrGetGLSLShaderPrecisionDecl(GrGLBinding binding);
-
-/**
  * Depending on the GLSL version being emitted there may be an assumed output
  * variable from the fragment shader for the color. Otherwise, the shader must
  * declare an output variable for the color. If this function returns true:
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index d24f2f8..3303bf2 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -14,6 +14,9 @@
 // except FS outputs where we expect 2 at most.
 static const int kMaxFSOutputs = 2;
 
+// ES2 FS only guarantees mediump and lowp support
+static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
+
 // Architectural assumption: always 2-d input coords.
 // Likely to become non-constant and non-static, perhaps even
 // varying by stage, if we use 1D textures for gradients!
@@ -139,10 +142,9 @@
     var->setArrayCount(count);
 
     if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
+        // the fragment and vertex precisions must match
+        var->setPrecision(kDefaultFragmentPrecision);
         fFSUnis.push_back(*var);
-        // If it's shared between VS and FS, VS must override
-        // default highp and specify mediump.
-        var->setEmitPrecision(true);
     }
 
     return *var;
@@ -186,7 +188,6 @@
     }
 }
 
-
 void GrGLShaderBuilder::addVarying(GrSLType type,
                                    const char* name,
                                    int stageNum,
@@ -198,6 +199,30 @@
 }
 
 namespace {
+
+inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
+                                               GrGLBinding binding,
+                                               SkString* str) {
+    // Desktop GLSL has added precision qualifiers but they don't do anything.
+    if (kES2_GrGLBinding == binding) {
+        switch (p) {
+            case GrGLShaderVar::kHigh_Precision:
+                str->append("precision highp float;\n");
+                break;
+            case GrGLShaderVar::kMedium_Precision:
+                str->append("precision mediump float;\n");
+                break;
+            case GrGLShaderVar::kLow_Precision:
+                str->append("precision lowp float;\n");
+                break;
+            case GrGLShaderVar::kDefault_Precision:
+                GrCrash("Default precision now allowed.");
+            default:
+                GrCrash("Unknown precision value.");
+        }
+    }
+}
+
 void append_decls(const GrGLShaderBuilder::VarArray& vars,
                   const GrGLContextInfo& ctx,
                   SkString* string) {
@@ -229,7 +254,9 @@
             break;
         case kFragment_ShaderType:
             *shaderStr = fHeader;
-            shaderStr->append(GrGetGLSLShaderPrecisionDecl(fContext.binding()));
+            append_default_precision_qualifier(kDefaultFragmentPrecision,
+                                               fContext.binding(),
+                                               shaderStr);
             append_decls(fFSUnis, fContext, shaderStr);
             append_decls(fFSInputs, fContext, shaderStr);
             // We shouldn't have declared outputs on 1.10
@@ -239,5 +266,5 @@
             shaderStr->append(fFSCode);
             break;
     }
-
  }
+
diff --git a/src/gpu/gl/GrGLShaderVar.h b/src/gpu/gl/GrGLShaderVar.h
index 7be417d..2eccd3b 100644
--- a/src/gpu/gl/GrGLShaderVar.h
+++ b/src/gpu/gl/GrGLShaderVar.h
@@ -33,6 +33,17 @@
         kAttribute_TypeModifier
     };
 
+    enum Precision {
+        kLow_Precision,         // lowp
+        kMedium_Precision,      // mediump
+        kHigh_Precision,        // highp
+        kDefault_Precision,     // Default for the current context. We make
+                                // fragment shaders default to mediump on ES2
+                                // because highp support is not guaranteed (and
+                                // we haven't been motivated to test for it).
+                                // Otherwise, highp.
+    };
+
     /**
      * Defaults to a float with no precision specifier
      */
@@ -40,7 +51,7 @@
         fType = kFloat_GrSLType;
         fTypeModifier = kNone_TypeModifier;
         fCount = kNonArray;
-        fEmitPrecision = false;
+        fPrecision = kDefault_Precision;
         fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
     }
 
@@ -49,7 +60,7 @@
         , fTypeModifier(var.fTypeModifier)
         , fName(var.fName)
         , fCount(var.fCount)
-        , fEmitPrecision(var.fEmitPrecision)
+        , fPrecision(var.fPrecision)
         , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {}
 
     /**
@@ -66,13 +77,13 @@
     void set(GrSLType type,
              TypeModifier typeModifier,
              const SkString& name,
-             bool emitPrecision = false,
+             Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
         fCount = kNonArray;
-        fEmitPrecision = emitPrecision;
+        fPrecision = precision;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
 
@@ -82,13 +93,13 @@
     void set(GrSLType type,
              TypeModifier typeModifier,
              const char* name,
-             bool specifyPrecision = false,
+             Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
         fCount = kNonArray;
-        fEmitPrecision = specifyPrecision;
+        fPrecision = precision;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
 
@@ -99,13 +110,13 @@
              TypeModifier typeModifier,
              const SkString& name,
              int count,
-             bool specifyPrecision = false,
+             Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
         fCount = count;
-        fEmitPrecision = specifyPrecision;
+        fPrecision = precision;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
 
@@ -116,13 +127,13 @@
              TypeModifier typeModifier,
              const char* name,
              int count,
-             bool specifyPrecision = false,
+             Precision precision = kDefault_Precision,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         fType = type;
         fTypeModifier = typeModifier;
         fName = name;
         fCount = count;
-        fEmitPrecision = specifyPrecision;
+        fPrecision = precision;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
 
@@ -178,13 +189,14 @@
     void setTypeModifier(TypeModifier type) { fTypeModifier = type; }
 
     /**
-     * Must the variable declaration emit a precision specifier
+     * Get the precision of the var
      */
-    bool emitsPrecision() const { return fEmitPrecision; }
+    Precision getPrecision() const { return fPrecision; }
+
     /**
-     * Specify whether the declaration should specify precision
+     * Set the precision of the var
      */
-    void setEmitPrecision(bool p) { fEmitPrecision = p; }
+    void setPrecision(Precision p) { fPrecision = p; }
 
     /**
      * Write a declaration of this variable to out.
@@ -195,10 +207,7 @@
                                           gl.glslGeneration()));
            out->append(" ");
         }
-        if (this->emitsPrecision()) {
-            out->append(GrGetGLSLVarPrecisionDeclType(gl.binding()));
-            out->append(" ");
-        }
+        out->append(PrecisionString(fPrecision, gl.binding()));
         GrSLType effectiveType = this->getType();
         if (this->isArray()) {
             if (this->isUnsizedArray()) {
@@ -257,8 +266,7 @@
     }
 
 private:
-    static const char* TypeModifierString(TypeModifier t,
-                                          GrGLSLGeneration gen) {
+    static const char* TypeModifierString(TypeModifier t, GrGLSLGeneration gen) {
         switch (t) {
             case kNone_TypeModifier:
                 return "";
@@ -276,11 +284,30 @@
         }
     }
 
-    GrSLType fType;
+    static const char* PrecisionString(Precision p, GrGLBinding binding) {
+        // Desktop GLSL has added precision qualifiers but they don't do anything.
+        if (kES2_GrGLBinding == binding) {
+            switch (p) {
+                case kLow_Precision:
+                    return "lowp ";
+                case kMedium_Precision:
+                    return "mediump ";
+                case kHigh_Precision:
+                    return "highp ";
+                case kDefault_Precision:
+                    return "";
+                default:
+                    GrCrash("Unexpected precision type.");
+            }
+        }
+        return "";
+    }
+
+    GrSLType        fType;
     TypeModifier    fTypeModifier;
     SkString        fName;
     int             fCount;
-    bool            fEmitPrecision;
+    Precision       fPrecision;
     /// Work around driver bugs on some hardware that don't correctly
     /// support uniform float []
     bool            fUseUniformFloatArrays;