Add an option to initialize varyings without static use in vertex shaders

ANGLEBUG=554
TEST=webgl conformance test on mac: shaders-with-varyings.html
r=kbr@chromium.org,nicolascapens@chromium.org
cc=alokp@chromium.org,shannonwoods@chromium.org

Change-Id: I2e692d43fb15f1cf3ade3e398020d1fedb2b32f0
Reviewed-on: https://chromium-review.googlesource.com/185922
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Tested-by: Zhenyao Mo <zmo@chromium.org>

Conflicts:
	src/common/version.h
	src/compiler/translator/Compiler.cpp
Change-Id: If7db13ef345bd6199d4ea0d7786f0de20885f2f3
Reviewed-on: https://chromium-review.googlesource.com/186144
Reviewed-by: Nicolas Capens <nicolascapens@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Tested-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 909f35b..da88b9d 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -8,8 +8,8 @@
 #include "compiler/translator/DetectCallDepth.h"
 #include "compiler/translator/ForLoopUnroll.h"
 #include "compiler/translator/Initialize.h"
-#include "compiler/translator/InitializeGLPosition.h"
 #include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/InitializeVariables.h"
 #include "compiler/translator/MapLongVariableNames.h"
 #include "compiler/translator/ParseContext.h"
 #include "compiler/translator/RenameFunction.h"
@@ -30,43 +30,51 @@
 }
 
 namespace {
-class TScopedPoolAllocator {
-public:
-    TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) {
+class TScopedPoolAllocator
+{
+  public:
+    TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
+    {
         mAllocator->push();
         SetGlobalPoolAllocator(mAllocator);
     }
-    ~TScopedPoolAllocator() {
+    ~TScopedPoolAllocator()
+    {
         SetGlobalPoolAllocator(NULL);
         mAllocator->pop();
     }
 
-private:
+  private:
     TPoolAllocator* mAllocator;
 };
 
-class TScopedSymbolTableLevel {
-public:
-    TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) {
+class TScopedSymbolTableLevel
+{
+  public:
+    TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
+    {
         ASSERT(mTable->atBuiltInLevel());
         mTable->push();
     }
-    ~TScopedSymbolTableLevel() {
+    ~TScopedSymbolTableLevel()
+    {
         while (!mTable->atBuiltInLevel())
             mTable->pop();
     }
 
-private:
+  private:
     TSymbolTable* mTable;
 };
 }  // namespace
 
-TShHandleBase::TShHandleBase() {
+TShHandleBase::TShHandleBase()
+{
     allocator.push();
     SetGlobalPoolAllocator(&allocator);
 }
 
-TShHandleBase::~TShHandleBase() {
+TShHandleBase::~TShHandleBase()
+{
     SetGlobalPoolAllocator(NULL);
     allocator.popAll();
 }
@@ -156,7 +164,8 @@
 
     shaderVersion = parseContext.getShaderVersion();
 
-    if (success) {
+    if (success)
+    {
         TIntermNode* root = parseContext.treeRoot;
         success = intermediate.postProcess(root);
 
@@ -198,26 +207,31 @@
         if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL)
             mapLongVariableNames(root);
 
-        if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) {
-            InitializeGLPosition initGLPosition;
-            root->traverse(&initGLPosition);
-        }
+        if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
+            initializeGLPosition(root);
 
-        if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) {
+        if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
+        {
             UnfoldShortCircuitAST unfoldShortCircuit;
             root->traverse(&unfoldShortCircuit);
             unfoldShortCircuit.updateTree();
         }
 
-        if (success && (compileOptions & SH_VARIABLES)) {
+        if (success && (compileOptions & SH_VARIABLES))
+        {
             collectVariables(root);
-            if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) {
+            if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
+            {
                 success = enforcePackingRestrictions();
-                if (!success) {
+                if (!success)
+                {
                     infoSink.info.prefix(EPrefixError);
                     infoSink.info << "too many uniforms";
                 }
             }
+            if (success && shaderType == SH_VERTEX_SHADER &&
+                (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
+                initializeVaryingsWithoutStaticUse(root);
         }
 
         if (success && (compileOptions & SH_INTERMEDIATE_TREE))
@@ -268,12 +282,14 @@
         symbolTable.setDefaultPrecision(integer, EbpHigh);
         symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
         break;
-      default: assert(false && "Language not supported");
+      default:
+        assert(false && "Language not supported");
     }
     // We set defaults for all the sampler types, even those that are
     // only available if an extension exists.
     for (int samplerType = EbtGuardSamplerBegin + 1;
-         samplerType < EbtGuardSamplerEnd; ++samplerType) {
+         samplerType < EbtGuardSamplerEnd; ++samplerType)
+    {
         sampler.type = static_cast<TBasicType>(samplerType);
         symbolTable.setDefaultPrecision(sampler, EbpLow);
     }
@@ -305,24 +321,25 @@
 {
     DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
     root->traverse(&detect);
-    switch (detect.detectCallDepth()) {
-        case DetectCallDepth::kErrorNone:
-            return true;
-        case DetectCallDepth::kErrorMissingMain:
-            infoSink.info.prefix(EPrefixError);
-            infoSink.info << "Missing main()";
-            return false;
-        case DetectCallDepth::kErrorRecursion:
-            infoSink.info.prefix(EPrefixError);
-            infoSink.info << "Function recursion detected";
-            return false;
-        case DetectCallDepth::kErrorMaxDepthExceeded:
-            infoSink.info.prefix(EPrefixError);
-            infoSink.info << "Function call stack too deep";
-            return false;
-        default:
-            UNREACHABLE();
-            return false;
+    switch (detect.detectCallDepth())
+    {
+      case DetectCallDepth::kErrorNone:
+        return true;
+      case DetectCallDepth::kErrorMissingMain:
+        infoSink.info.prefix(EPrefixError);
+        infoSink.info << "Missing main()";
+        return false;
+      case DetectCallDepth::kErrorRecursion:
+        infoSink.info.prefix(EPrefixError);
+        infoSink.info << "Function recursion detected";
+        return false;
+      case DetectCallDepth::kErrorMaxDepthExceeded:
+        infoSink.info.prefix(EPrefixError);
+        infoSink.info << "Function call stack too deep";
+        return false;
+      default:
+        UNREACHABLE();
+        return false;
     }
 }
 
@@ -339,7 +356,8 @@
     root->traverse(&renamer);
 }
 
-bool TCompiler::validateLimitations(TIntermNode* root) {
+bool TCompiler::validateLimitations(TIntermNode* root)
+{
     ValidateLimitations validate(shaderType, infoSink.info);
     root->traverse(&validate);
     return validate.numErrors() == 0;
@@ -347,26 +365,30 @@
 
 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
 {
-    if (shaderSpec != SH_WEBGL_SPEC) {
+    if (shaderSpec != SH_WEBGL_SPEC)
+    {
         infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
         return false;
     }
 
-    if (shaderType == SH_FRAGMENT_SHADER) {
+    if (shaderType == SH_FRAGMENT_SHADER)
+    {
         TDependencyGraph graph(root);
 
         // Output any errors first.
         bool success = enforceFragmentShaderTimingRestrictions(graph);
         
         // Then, output the dependency graph.
-        if (outputGraph) {
+        if (outputGraph)
+        {
             TDependencyGraphOutput output(infoSink.info);
             output.outputAllSpanningTrees(graph);
         }
         
         return success;
     }
-    else {
+    else
+    {
         return enforceVertexShaderTimingRestrictions(root);
     }
 }
@@ -386,7 +408,8 @@
         samplerSymbol->traverse(&graphTraverser);
     }
 
-    if (traverser.getMaxDepth() > maxExpressionComplexity) {
+    if (traverser.getMaxDepth() > maxExpressionComplexity)
+    {
         infoSink.info << "Expression too complex.";
         return false;
     }
@@ -419,6 +442,70 @@
     return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
 }
 
+void TCompiler::initializeGLPosition(TIntermNode* root)
+{
+    InitializeVariables::InitVariableInfoList variables;
+    InitializeVariables::InitVariableInfo var(
+        "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
+    variables.push_back(var);
+    InitializeVariables initializer(variables);
+    root->traverse(&initializer);
+}
+
+void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
+{
+    InitializeVariables::InitVariableInfoList variables;
+    for (size_t ii = 0; ii < varyings.size(); ++ii)
+    {
+        const TVariableInfo& varying = varyings[ii];
+        if (varying.staticUse)
+            continue;
+        unsigned char size = 0;
+        bool matrix = false;
+        switch (varying.type)
+        {
+          case SH_FLOAT:
+            size = 1;
+            break;
+          case SH_FLOAT_VEC2:
+            size = 2;
+            break;
+          case SH_FLOAT_VEC3:
+            size = 3;
+            break;
+          case SH_FLOAT_VEC4:
+            size = 4;
+            break;
+          case SH_FLOAT_MAT2:
+            size = 2;
+            matrix = true;
+            break;
+          case SH_FLOAT_MAT3:
+            size = 3;
+            matrix = true;
+            break;
+          case SH_FLOAT_MAT4:
+            size = 4;
+            matrix = true;
+            break;
+          default:
+            ASSERT(false);
+        }
+        TType type(EbtFloat, EbpUndefined, EvqVaryingOut, size, matrix, varying.isArray);
+        TString name = varying.name.c_str();
+        if (varying.isArray)
+        {
+            type.setArraySize(varying.size);
+            name = name.substr(0, name.find_first_of('['));
+        }
+
+        InitializeVariables::InitVariableInfo var(name, type);
+        variables.push_back(var);
+    }
+    InitializeVariables initializer(variables);
+    root->traverse(&initializer);
+}
+
 void TCompiler::mapLongVariableNames(TIntermNode* root)
 {
     ASSERT(longNameMap);