ES31: Support translating textureGather into HLSL - Part I

This patch is the first one in the series of supporting GLSL texture
function textureGather/textureGatherOffset on D3D11.

According to ESSL 3.1 SPEC (Chapter 8.9.3, Page 130), the definition
of textureGather on sampler2D is:
    gvec4 textureGather (gsampler2D sampler, vec2 P[, int comp])

The parameter "comp" is optional, and if it is specified, the value
of "comp" must be a constant integer expression with a value of 0, 1,
2, or 3, identifying the x, y, z, or w postswizzled component of the
four-component vector lookup result for each texel, respectively. If
comp is not specified, it is treated as 0.

According to the definition above, textureGather is equivalent to
Texture2D.Gather[Red|Green|Blue|Alpha] in HLSL, where we can use a
switch-case expression to choose the right HLSL texture function.

The features listed here will be implemented in the following patches:
1. Support textureGatherOffset
2. Support textureGather[Offset] on isamplers and usamplers
3. Support textureGather[Offset] on textures when swizzle is on
4. Support textureGather[Offset] on shadow samplers

BUG=angleproject:2826
TEST=dEQP-GLES31.functional.texture.gather.basic.2d.rgba8.*
     dEQP-GLES31.functional.texture.gather.basic.cube.rgba8.*
     (without texture_swizzle)
     dEQP-GLES31.functional.texture.gather.basic.2d_array.rgba8.*
     (without texture_swizzle)

Change-Id: Iff2ed4f8b65dad613cb0bafdfd19f8f0528e832c
Reviewed-on: https://chromium-review.googlesource.com/1232980
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/TextureFunctionHLSL.cpp b/src/compiler/translator/TextureFunctionHLSL.cpp
index 1666004..685c904 100644
--- a/src/compiler/translator/TextureFunctionHLSL.cpp
+++ b/src/compiler/translator/TextureFunctionHLSL.cpp
@@ -381,6 +381,8 @@
             break;
         case TextureFunctionHLSL::TextureFunction::GRAD:
             break;
+        case TextureFunctionHLSL::TextureFunction::GATHER:
+            break;
         default:
             UNREACHABLE();
     }
@@ -416,6 +418,10 @@
     {
         out << ", float bias";
     }
+    else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER)
+    {
+        out << ", int comp = 0";
+    }
 }
 
 void GetTextureReference(TInfoSinkBase &out,
@@ -812,6 +818,61 @@
     }
 }
 
+void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
+                                     const TextureFunctionHLSL::TextureFunction &textureFunction,
+                                     ShShaderOutput outputType,
+                                     const ImmutableString &textureReference,
+                                     const ImmutableString &samplerReference,
+                                     const ImmutableString &texCoordX,
+                                     const ImmutableString &texCoordY,
+                                     const ImmutableString &texCoordZ)
+{
+    const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
+    ImmutableString samplerCoordTypeString(
+        GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
+    ImmutableStringBuilder samplerCoordBuilder(
+        samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
+        texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
+
+    samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
+    if (hlslCoords >= 3)
+    {
+        if (textureFunction.coords < 3)
+        {
+            samplerCoordBuilder << ", 0";
+        }
+        else
+        {
+            samplerCoordBuilder << ", " << texCoordZ;
+        }
+    }
+    samplerCoordBuilder << ")";
+
+    ImmutableString samplerCoordString(samplerCoordBuilder);
+
+    out << "    switch(comp)\n"
+           "    {\n"
+           "        case 0:\n"
+           "            return "
+        << textureReference << ".GatherRed(" << samplerReference << ", " << samplerCoordString
+        << ");\n"
+           "        case 1:\n"
+           "            return "
+        << textureReference << ".GatherGreen(" << samplerReference << ", " << samplerCoordString
+        << ");\n"
+           "        case 2:\n"
+           "            return "
+        << textureReference << ".GatherBlue(" << samplerReference << ", " << samplerCoordString
+        << ");\n"
+           "        case 3:\n"
+           "            return "
+        << textureReference << ".GatherAlpha(" << samplerReference << ", " << samplerCoordString
+        << ");\n"
+           "        default:\n"
+           "            return float4(0.0, 0.0, 0.0, 1.0);\n"
+           "    }\n";
+}
+
 void OutputTextureSampleFunctionReturnStatement(
     TInfoSinkBase &out,
     const TextureFunctionHLSL::TextureFunction &textureFunction,
@@ -1078,6 +1139,9 @@
         case GRAD:
             name << "Grad";
             break;
+        case GATHER:
+            name << "Gather";
+            break;
         default:
             UNREACHABLE();
     }
@@ -1252,6 +1316,10 @@
         textureFunction.proj   = true;
         textureFunction.offset = true;
     }
+    else if (name == "textureGather")
+    {
+        textureFunction.method = TextureFunction::GATHER;
+    }
     else
         UNREACHABLE();
 
@@ -1321,13 +1389,21 @@
             ImmutableString texCoordX("t.x");
             ImmutableString texCoordY("t.y");
             ImmutableString texCoordZ("t.z");
-            ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
-            OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
-                                                           textureReference, &texCoordX, &texCoordY,
-                                                           &texCoordZ);
-            OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
-                                                       textureReference, samplerReference,
-                                                       texCoordX, texCoordY, texCoordZ);
+            if (textureFunction.method == TextureFunction::GATHER)
+            {
+                OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
+                                                samplerReference, texCoordX, texCoordY, texCoordZ);
+            }
+            else
+            {
+                ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
+                OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
+                                                               textureReference, &texCoordX,
+                                                               &texCoordY, &texCoordZ);
+                OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
+                                                           textureReference, samplerReference,
+                                                           texCoordX, texCoordY, texCoordZ);
+            }
         }
 
         out << "}\n"