Pull GLSL helpers out of GrGLProgram.cpp

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




git-svn-id: http://skia.googlecode.com/svn/trunk@3161 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrGLProgram.cpp b/src/gpu/GrGLProgram.cpp
index 610446d..e77638f 100644
--- a/src/gpu/GrGLProgram.cpp
+++ b/src/gpu/GrGLProgram.cpp
@@ -22,23 +22,6 @@
     kUseUniform = 2000
 };
 
-
-const char* GrPrecision(const GrGLInterface* gl) {
-    if (gl->supportsES2()) {
-        return "mediump";
-    } else {
-        return " ";
-    }
-}
-
-const char* GrShaderPrecision(const GrGLInterface* gl) {
-    if (gl->supportsES2()) {
-        return "precision mediump float;\n";
-    } else {
-        return "";
-    }
-}
-
 }  // namespace
 
 #define PRINT_SHADERS 0
@@ -380,29 +363,6 @@
 
 namespace {
 
-const char* glsl_version_string(const GrGLInterface* gl,
-                                GrGLSLGeneration v) {
-    switch (v) {
-        case k110_GLSLGeneration:
-            if (gl->supportsES2()) {
-                // ES2s shader language is based on version 1.20 but is version
-                // 1.00 of the ES language.
-                return "#version 100\n";
-            } else {
-                return "#version 110\n";
-            }
-        case k130_GLSLGeneration:
-            GrAssert(!gl->supportsES2());
-            return "#version 130\n";
-        case k150_GLSLGeneration:
-            GrAssert(!gl->supportsES2());
-            return "#version 150\n";
-        default:
-            GrCrash("Unknown GL version.");
-            return ""; // suppress warning
-    }
-}
-
 // Adds a var that is computed in the VS and read in FS.
 // If there is a GS it will just pass it through.
 void append_varying(GrGLShaderVar::Type type,
@@ -568,29 +528,6 @@
 
 namespace {
 
-// returns true if the color output was explicitly declared or not.
-bool decl_and_get_fs_color_output(GrGLSLGeneration v,
-                                  VarArray* fsOutputs,
-                                  const char** name) {
-    switch (v) {
-        case k110_GLSLGeneration:
-            *name = "gl_FragColor";
-            return false;
-            break;
-        case k130_GLSLGeneration: // fallthru
-        case k150_GLSLGeneration:
-            *name = declared_color_output_name();
-            fsOutputs->push_back().set(GrGLShaderVar::kVec4f_Type,
-                                       GrGLShaderVar::kOut_TypeModifier,
-                                       declared_color_output_name());
-            return true;
-            break;
-        default:
-            GrCrash("Unknown GLSL version.");
-            return false; // suppress warning
-    }
-}
-
 void genInputColor(GrGLProgram::ProgramDesc::ColorInput colorInput,
                    GrGLProgram::CachedData* programData,
                    ShaderCodeSegments* segments,
@@ -664,7 +601,7 @@
                                     ShaderCodeSegments* segments) const {
 #if GR_GL_EXPERIMENTAL_GS
     if (fProgramDesc.fExperimentalGS) {
-        GrAssert(glslGeneration >= k150_GLSLGeneration);
+        GrAssert(glslGeneration >= k150_GrGLSLGeneration);
         segments->fGSHeader.append("layout(triangles) in;\n"
                                    "layout(triangle_strip, max_vertices = 6) out;\n");
         segments->fGSCode.append("void main() {\n"
@@ -758,12 +695,17 @@
 
     // the dual source output has no canonical var name, have to
     // declare an output, which is incompatible with gl_FragColor/gl_FragData.
-    const char* fsColorOutput = NULL;
     bool dualSourceOutputWritten = false;
-    segments.fHeader.printf(glsl_version_string(gl, glslGeneration));
-    bool isColorDeclared = decl_and_get_fs_color_output(glslGeneration,
-                                                        &segments.fFSOutputs,
-                                                        &fsColorOutput);
+    segments.fHeader.printf(GrGetGLSLVersionDecl(gl->fBindingsExported,
+                                                 glslGeneration));
+
+    GrGLShaderVar colorOutput;
+    bool isColorDeclared = GrGLSLSetupFSColorOuput(glslGeneration,
+                                                   declared_color_output_name(),
+                                                   &colorOutput);
+    if (isColorDeclared) {
+        segments.fFSOutputs.push_back(colorOutput);
+    }
 
 #if GR_GL_ATTRIBUTE_MATRICES
     segments.fVSAttrs.push_back().set(GrGLShaderVar::kMat33f_Type,
@@ -872,7 +814,7 @@
         SkXfermode::kZero_Coeff == colorCoeff &&
         !applyColorMatrix) {
         segments.fFSCode.appendf("\t%s = %s;\n",
-                                 fsColorOutput,
+                                 colorOutput.getName().c_str(),
                                  all_zeros_vec(4));
         wroteFragColorZero = true;
     } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
@@ -1005,21 +947,21 @@
     if (!wroteFragColorZero) {
         if (coverageIsZero) {
             segments.fFSCode.appendf("\t%s = %s;\n",
-                                     fsColorOutput,
+                                     colorOutput.getName().c_str(),
                                      all_zeros_vec(4));
         } else {
-            modulate_helper(fsColorOutput,
+            modulate_helper(colorOutput.getName().c_str(),
                             inColor.c_str(),
                             inCoverage.c_str(),
                             &segments.fFSCode);
         }
         if (ProgramDesc::kNo_OutputPM == fProgramDesc.fOutputPM) {
             segments.fFSCode.appendf("\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(%s.rgb / %s.a, %s.a);\n",
-                                     fsColorOutput,
-                                     fsColorOutput,
-                                     fsColorOutput,
-                                     fsColorOutput,
-                                     fsColorOutput);
+                                     colorOutput.getName().c_str(),
+                                     colorOutput.getName().c_str(),
+                                     colorOutput.getName().c_str(),
+                                     colorOutput.getName().c_str(),
+                                     colorOutput.getName().c_str());
         }
     }
 
@@ -1169,13 +1111,13 @@
     temps.reset();
 
     append_string(segments.fHeader, &strs, &lengths);
-    GrStringBuilder precisionStr(GrShaderPrecision(gl));
+    GrStringBuilder precisionStr(GrGetGLSLShaderPrecisionDecl(gl->fBindingsExported));
     append_string(precisionStr, &strs, &lengths);
     append_decls(segments.fFSUnis, gl, &strs, &lengths, &temps, glslGeneration);
     append_decls(segments.fFSInputs, gl, &strs, &lengths,
                  &temps, glslGeneration);
     // We shouldn't have declared outputs on 1.10
-    GrAssert(k110_GLSLGeneration != glslGeneration ||
+    GrAssert(k110_GrGLSLGeneration != glslGeneration ||
              segments.fFSOutputs.empty());
     append_decls(segments.fFSOutputs, gl, &strs, &lengths,
                  &temps, glslGeneration);
diff --git a/src/gpu/GrGLSL.cpp b/src/gpu/GrGLSL.cpp
index 1062c81..e933ee8 100644
--- a/src/gpu/GrGLSL.cpp
+++ b/src/gpu/GrGLSL.cpp
@@ -6,27 +6,77 @@
  */
 
 #include "GrGLSL.h"
+#include "GrGLShaderVar.h"
 
-GrGLSLGeneration GetGLSLGeneration(GrGLBinding binding,
+GrGLSLGeneration GrGetGLSLGeneration(GrGLBinding binding,
                                    const GrGLInterface* gl) {
     GrGLSLVersion ver = GrGLGetGLSLVersion(gl);
     switch (binding) {
         case kDesktop_GrGLBinding:
             GrAssert(ver >= GR_GLSL_VER(1,10));
             if (ver >= GR_GLSL_VER(1,50)) {
-                return k150_GLSLGeneration;
+                return k150_GrGLSLGeneration;
             } else if (ver >= GR_GLSL_VER(1,30)) {
-                return k130_GLSLGeneration;
+                return k130_GrGLSLGeneration;
             } else {
-                return k110_GLSLGeneration;
+                return k110_GrGLSLGeneration;
             }
         case kES2_GrGLBinding:
             // version 1.00 of ES GLSL based on ver 1.20 of desktop GLSL
             GrAssert(ver >= GR_GL_VER(1,00));
-            return k110_GLSLGeneration;
+            return k110_GrGLSLGeneration;
         default:
             GrCrash("Unknown GL Binding");
-            return k110_GLSLGeneration; // suppress warning
+            return k110_GrGLSLGeneration; // suppress warning
     }
 }
 
+const char* GrGetGLSLVersionDecl(GrGLBinding binding,
+                                   GrGLSLGeneration gen) {
+    switch (gen) {
+        case k110_GrGLSLGeneration:
+            if (kES2_GrGLBinding == binding) {
+                // ES2s shader language is based on version 1.20 but is version
+                // 1.00 of the ES language.
+                return "#version 100\n";
+            } else {
+                GrAssert(kDesktop_GrGLBinding == binding);
+                return "#version 110\n";
+            }
+        case k130_GrGLSLGeneration:
+            GrAssert(kDesktop_GrGLBinding == binding);
+            return "#version 130\n";
+        case k150_GrGLSLGeneration:
+            GrAssert(kDesktop_GrGLBinding == binding);
+            return "#version 150\n";
+        default:
+            GrCrash("Unknown GL version.");
+            return ""; // suppress warning
+    }
+}
+
+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) {
+    bool declaredOutput = k110_GrGLSLGeneration != gen;
+    var->set(GrGLShaderVar::kVec4f_Type,
+             GrGLShaderVar::kOut_TypeModifier,
+             declaredOutput ? nameIfDeclared : "gl_FragColor");
+    return declaredOutput;
+}
diff --git a/src/gpu/GrGLSL.h b/src/gpu/GrGLSL.h
index 501d1ba..5b9c5b6 100644
--- a/src/gpu/GrGLSL.h
+++ b/src/gpu/GrGLSL.h
@@ -10,25 +10,67 @@
 
 #include "GrGLInterface.h"
 
+class GrGLShaderVar;
+
 // Limited set of GLSL versions we build shaders for. Caller should round
 // down the GLSL version to one of these enums.
 enum GrGLSLGeneration {
     /**
      * Desktop GLSL 1.10 and ES2 shading lang (based on desktop GLSL 1.20)
      */
-    k110_GLSLGeneration,
+    k110_GrGLSLGeneration,
     /**
      * Desktop GLSL 1.30
      */
-    k130_GLSLGeneration,
+    k130_GrGLSLGeneration,
     /**
      * Dekstop GLSL 1.50
      */
-    k150_GLSLGeneration,
+    k150_GrGLSLGeneration,
 };
 
-GrGLSLGeneration GetGLSLGeneration(GrGLBinding binding,
-                                   const GrGLInterface* gl);
+/**
+ * Gets the most recent GLSL Generation compatible with the OpenGL context.
+ */
+GrGLSLGeneration GrGetGLSLGeneration(GrGLBinding binding,
+                                     const GrGLInterface* gl);
+
+/**
+ * Returns a string to include at the begining of a shader to declare the GLSL
+ * version.
+ */
+const char* GrGetGLSLVersionDecl(GrGLBinding binding,
+                                 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:
+ *    * Parameter var's name will be set to nameIfDeclared
+ *    * The variable must be declared in the fragment shader
+ *    * The variable has to be bound as the color output 
+ *      (using glBindFragDataLocation)
+ *    If the function returns false:
+ *    * Parameter var's name will be set to the GLSL built-in color output name.
+ *    * Do not declare the variable in the shader.
+ *    * Do not use glBindFragDataLocation to bind the variable
+ * In either case var is initialized to represent the color output in the
+ * shader.
+ */
+ bool GrGLSLSetupFSColorOuput(GrGLSLGeneration gen,
+                             const char* nameIfDeclared,
+                             GrGLShaderVar* var);
 
 #endif
-
diff --git a/src/gpu/GrGLShaderVar.h b/src/gpu/GrGLShaderVar.h
index 1d5d7ca..7bec9f9 100644
--- a/src/gpu/GrGLShaderVar.h
+++ b/src/gpu/GrGLShaderVar.h
@@ -278,13 +278,13 @@
             case kNone_TypeModifier:
                 return "";
             case kOut_TypeModifier:
-                return k110_GLSLGeneration == gen ? "varying" : "out";
+                return k110_GrGLSLGeneration == gen ? "varying" : "out";
             case kIn_TypeModifier:
-                return k110_GLSLGeneration == gen ? "varying" : "in";
+                return k110_GrGLSLGeneration == gen ? "varying" : "in";
             case kUniform_TypeModifier:
                 return "uniform";
             case kAttribute_TypeModifier:
-                return k110_GLSLGeneration == gen ? "attribute" : "in";
+                return k110_GrGLSLGeneration == gen ? "attribute" : "in";
             default:
                 GrCrash("Unknown shader variable type modifier.");
                 return ""; // suppress warning
diff --git a/src/gpu/GrGpuGLShaders.cpp b/src/gpu/GrGpuGLShaders.cpp
index b8e0999a..d03c9f2 100644
--- a/src/gpu/GrGpuGLShaders.cpp
+++ b/src/gpu/GrGpuGLShaders.cpp
@@ -166,7 +166,7 @@
 bool GrGpuGLShaders::programUnitTest() {
 
     GrGLSLGeneration glslGeneration = 
-            GetGLSLGeneration(this->glBinding(), this->glInterface());
+            GrGetGLSLGeneration(this->glBinding(), this->glInterface());
     static const int STAGE_OPTS[] = {
         0,
         StageDesc::kNoPerspective_OptFlagBit,
@@ -306,7 +306,7 @@
     : GrGpuGL(gl, get_binding_in_use(gl)) {
 
     GrGLSLGeneration glslGeneration =
-        GetGLSLGeneration(this->glBinding(), gl);
+        GrGetGLSLGeneration(this->glBinding(), gl);
 
     // Enable supported shader-related caps
     if (kDesktop_GrGLBinding == this->glBinding()) {
@@ -317,7 +317,7 @@
         // we don't support GL_ARB_geometry_shader4, just GL 3.2+ GS
         fCaps.fGeometryShaderSupport = 
                                 this->glVersion() >= GR_GL_VER(3,2) &&
-                                glslGeneration >= k150_GLSLGeneration;
+                                glslGeneration >= k150_GrGLSLGeneration;
     } else {
         fCaps.fShaderDerivativeSupport =
                             this->hasExtension("GL_OES_standard_derivatives");