ES31: Support compute shader shared variables in HLSL

This patch implements 'shared' variables in compute shader on D3D11
back-ends. GLSL shared variables are translated into 'groupshared'
ones in HLSL.

Note that although HLSL allows initializing the variables with
'groupshared' qualifier, currently we do not initialize them because:
1. It is very slow to for d3d11 drivers to compile the compute shader if
   we add the code to initialize a shared variable with large array size.
2. It seems unnecessary to do so and in GLSL it is not allowed to
   initialize a shared variable in the declaration. (ESSL 3.1, Chapter
   4.3.8)

BUG=angleproject:2682
TEST=angle_end2end_tests

Change-Id: Ica8247e1b98059968612a36e369718ef113a598c
Reviewed-on: https://chromium-review.googlesource.com/1109587
Reviewed-by: Jiajia Qin <jiajia.qin@intel.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 1c7e090..e93c3a6 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -6,9 +6,9 @@
 
 #include "compiler/translator/OutputHLSL.h"
 
+#include <stdio.h>
 #include <algorithm>
 #include <cfloat>
-#include <stdio.h>
 
 #include "common/angleutils.h"
 #include "common/debug.h"
@@ -56,7 +56,7 @@
     ASSERT(sequence->size() == 1);
     ASSERT(variable);
     return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
-            variable->getQualifier() == EvqConst);
+            variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
 }
 
 bool IsInStd140InterfaceBlock(TIntermTyped *node)
@@ -165,14 +165,14 @@
 {
     mInsideFunction = false;
 
-    mUsesFragColor               = false;
-    mUsesFragData                = false;
-    mUsesDepthRange              = false;
-    mUsesFragCoord               = false;
-    mUsesPointCoord              = false;
-    mUsesFrontFacing             = false;
-    mUsesPointSize               = false;
-    mUsesInstanceID              = false;
+    mUsesFragColor   = false;
+    mUsesFragData    = false;
+    mUsesDepthRange  = false;
+    mUsesFragCoord   = false;
+    mUsesPointCoord  = false;
+    mUsesFrontFacing = false;
+    mUsesPointSize   = false;
+    mUsesInstanceID  = false;
     mHasMultiviewExtensionEnabled =
         IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
     mUsesViewID                  = false;
@@ -414,18 +414,18 @@
 
     for (const auto &varying : mReferencedVaryings)
     {
-        const TType &type   = varying.second->getType();
+        const TType &type           = varying.second->getType();
         const ImmutableString &name = varying.second->name();
 
         // Program linking depends on this exact format
-        varyings += TString("static ") + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
-                    " " + Decorate(name) + ArrayString(type) + " = " + zeroInitializer(type) +
-                    ";\n";
+        varyings += TString("static ") + InterpolationString(type.getQualifier()) + " " +
+                    TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " +
+                    zeroInitializer(type) + ";\n";
     }
 
     for (const auto &attribute : mReferencedAttributes)
     {
-        const TType &type   = attribute.second->getType();
+        const TType &type           = attribute.second->getType();
         const ImmutableString &name = attribute.second->name();
 
         attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
@@ -499,7 +499,7 @@
             for (const auto &outputVariable : mReferencedOutputVariables)
             {
                 const ImmutableString &variableName = outputVariable.second->name();
-                const TType &variableType   = outputVariable.second->getType();
+                const TType &variableType           = outputVariable.second->getType();
 
                 out << "static " << TypeString(variableType) << " out_" << variableName
                     << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
@@ -509,8 +509,9 @@
         {
             const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
 
-            out << "static float4 gl_Color[" << numColorValues << "] =\n"
-                                                                  "{\n";
+            out << "static float4 gl_Color[" << numColorValues
+                << "] =\n"
+                   "{\n";
             for (unsigned int i = 0; i < numColorValues; i++)
             {
                 out << "    float4(0, 0, 0, 0)";
@@ -1244,7 +1245,7 @@
             {
                 if (visit == PreVisit)
                 {
-                    TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
+                    TIntermSymbol *instanceArraySymbol    = node->getLeft()->getAsSymbolNode();
                     const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
                     if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
                     {
@@ -1807,7 +1808,11 @@
                 declarator->getAsSymbolNode()->variable().symbolType() !=
                     SymbolType::Empty)  // Variable declaration
             {
-                if (!mInsideFunction)
+                if (declarator->getQualifier() == EvqShared)
+                {
+                    out << "groupshared ";
+                }
+                else if (!mInsideFunction)
                 {
                     out << "static ";
                 }
@@ -1820,7 +1825,15 @@
                 {
                     symbol->traverse(this);
                     out << ArrayString(symbol->getType());
-                    out << " = " + zeroInitializer(symbol->getType());
+                    // We don't initialize shared variables because:
+                    // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
+                    // code to initialize a groupshared array variable with a large array size.
+                    // 2. It is unnecessary to initialize shared variables, as GLSL even does not
+                    // allow initializing shared variables at all.
+                    if (declarator->getQualifier() != EvqShared)
+                    {
+                        out << " = " + zeroInitializer(symbol->getType());
+                    }
                 }
                 else
                 {
@@ -1928,7 +1941,7 @@
             else if (node->getFunction()->isImageFunction())
             {
                 const ImmutableString &name = node->getFunction()->name();
-                TType type                = (*arguments)[0]->getAsTyped()->getType();
+                TType type                  = (*arguments)[0]->getAsTyped()->getType();
                 TString imageFunctionName   = mImageFunctionHLSL->useImageFunction(
                     name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
                     type.getMemoryQualifier().readonly);