ES31: Support translating textureGatherOffset into HLSL

This patch implements the translation from GLSL texture function
textureGatherOffset into HLSL by using the optional "offset"
parameter of Texture2D.Gather[Red|Green|Blue|Alpha].

This patch also defines the implementation-dependent limit
MIN_PROGRAM_TEXTURE_GATHER_OFFSET and MAX_PROGRAM_TEXTURE_GATHER_OFFSET
on D3D11. According to MSDN, the valid range of "offset" used in
Gather should be [-32, 31].
https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/gather4-po--sm5---asm-

This patch also refactors OutputTextureGatherFunctionBody() so that
some redundant code can be removed.

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

Change-Id: Id0f411257b64c8a97428f16b1a86950ec6d36e2f
Reviewed-on: https://chromium-review.googlesource.com/1237303
Reviewed-by: Jiajia Qin <jiajia.qin@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/compiler/translator/TextureFunctionHLSL.cpp b/src/compiler/translator/TextureFunctionHLSL.cpp
index 685c904..164922f 100644
--- a/src/compiler/translator/TextureFunctionHLSL.cpp
+++ b/src/compiler/translator/TextureFunctionHLSL.cpp
@@ -850,25 +850,24 @@
 
     ImmutableString samplerCoordString(samplerCoordBuilder);
 
+    constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
+        {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
+
     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"
+           "    {\n";
+    for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
+    {
+        out << "        case " << component << ":\n"
+            << "            return " << textureReference << "." << kHLSLGatherFunctions[component]
+            << "(" << samplerReference << ", " << samplerCoordString;
+        if (textureFunction.offset)
+        {
+            out << ", offset";
+        }
+        out << ");\n";
+    }
+
+    out << "        default:\n"
            "            return float4(0.0, 0.0, 0.0, 1.0);\n"
            "    }\n";
 }
@@ -1320,6 +1319,11 @@
     {
         textureFunction.method = TextureFunction::GATHER;
     }
+    else if (name == "textureGatherOffset")
+    {
+        textureFunction.method = TextureFunction::GATHER;
+        textureFunction.offset = true;
+    }
     else
         UNREACHABLE();