Flatten "#pragma STDGL invariant(all)" into varying variables.

This is implemented as a compiler option which is enabled by default
when outputting to desktop GLSL version 130 and greater, which does
not support this #pragma in fragment shaders. As a workaround, and for
better compatibility on desktop OpenGL drivers, this pragma is also
flattened into the outputs of vertex shaders, and the inputs of ESSL
1.00 fragment shaders.

TEST=conformance/glsl/misc/shaders-with-invariance.html with --enable-unsafe-es3-apis
BUG=629622, angleproject:1293

Change-Id: Ib040230915e639971505ed496d26e804c9d64e68
Reviewed-on: https://chromium-review.googlesource.com/361792
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 55e74a1..06dc6cd 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -140,7 +140,8 @@
 }
 
 TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
-    : shaderType(type),
+    : variablesCollected(false),
+      shaderType(type),
       shaderSpec(spec),
       outputType(output),
       maxUniformVectors(0),
@@ -408,12 +409,20 @@
     return NULL;
 }
 
-bool TCompiler::compile(const char* const shaderStrings[],
-    size_t numStrings, int compileOptions)
+bool TCompiler::compile(const char *const shaderStrings[], size_t numStrings, int compileOptionsIn)
 {
     if (numStrings == 0)
         return true;
 
+    int compileOptions = compileOptionsIn;
+
+    // Apply key workarounds.
+    if (shouldFlattenPragmaStdglInvariantAll())
+    {
+        // This should be harmless to do in all cases, but for the moment, do it only conditionally.
+        compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
+    }
+
     TScopedPoolAllocator scopedAlloc(&allocator);
     TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
 
@@ -577,6 +586,7 @@
     expandedUniforms.clear();
     varyings.clear();
     interfaceBlocks.clear();
+    variablesCollected = false;
 
     builtInFunctionEmulator.Cleanup();
 
@@ -833,12 +843,16 @@
 
 void TCompiler::collectVariables(TIntermNode* root)
 {
-    sh::CollectVariables collect(&attributes, &outputVariables, &uniforms, &varyings,
-                                 &interfaceBlocks, hashFunction, symbolTable, extensionBehavior);
-    root->traverse(&collect);
+    if (!variablesCollected)
+    {
+        sh::CollectVariables collect(&attributes, &outputVariables, &uniforms, &varyings,
+                                     &interfaceBlocks, hashFunction, symbolTable, extensionBehavior);
+        root->traverse(&collect);
 
-    // This is for enforcePackingRestriction().
-    sh::ExpandUniforms(uniforms, &expandedUniforms);
+        // This is for enforcePackingRestriction().
+        sh::ExpandUniforms(uniforms, &expandedUniforms);
+        variablesCollected = true;
+    }
 }
 
 bool TCompiler::enforcePackingRestrictions()
@@ -907,9 +921,26 @@
     return builtInFunctionEmulator;
 }
 
-void TCompiler::writePragma()
+void TCompiler::writePragma(int compileOptions)
 {
-    TInfoSinkBase &sink = infoSink.obj;
-    if (mPragma.stdgl.invariantAll)
-        sink << "#pragma STDGL invariant(all)\n";
+    if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
+    {
+        TInfoSinkBase &sink = infoSink.obj;
+        if (mPragma.stdgl.invariantAll)
+            sink << "#pragma STDGL invariant(all)\n";
+    }
+}
+
+bool TCompiler::isVaryingDefined(const char *varyingName)
+{
+    ASSERT(variablesCollected);
+    for (size_t ii = 0; ii < varyings.size(); ++ii)
+    {
+        if (varyings[ii].name == varyingName)
+        {
+            return true;
+        }
+    }
+
+    return false;
 }