Implement texelFetch and texelFetchOffset.

BUG=angle:564

Change-Id: I7ad3484061f5d6912d7842bdadc6297de3e82ef8
Reviewed-on: https://chromium-review.googlesource.com/186990
Tested-by: Nicolas Capens <nicolascapens@chromium.org>
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index f59ad83..69a1faf 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -503,6 +503,14 @@
     symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler3D, float4, float1, int3);
     symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLodOffset", sampler2DShadow, float4, float1, int2);
 
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2D, int2, int1);
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler3D, int3, int1);
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2DArray, int3, int1);
+
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, int2);
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, int3);
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, int1, int2);
+
     //
     // Depth range in window coordinates
     //
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 503d10d..03ff3fc 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -55,11 +55,12 @@
 
     switch(method)
     {
-      case IMPLICIT:                 break;
-      case BIAS:                     break;
-      case LOD:      name += "Lod";  break;
-      case LOD0:     name += "Lod0"; break;
-      case SIZE:     name += "Size"; break;
+      case IMPLICIT:                  break;
+      case BIAS:                      break;
+      case LOD:      name += "Lod";   break;
+      case LOD0:     name += "Lod0";  break;
+      case SIZE:     name += "Size";  break;
+      case FETCH:    name += "Fetch"; break;
       default: UNREACHABLE();
     }
 
@@ -1000,13 +1001,25 @@
         }
         else UNREACHABLE();
 
-        switch(textureFunction->coords)
+        if (textureFunction->method == TextureFunction::FETCH)   // Integer coordinates
         {
-          case 1: out << ", int lod";  break;
-          case 2: out << ", float2 t"; break;
-          case 3: out << ", float3 t"; break;
-          case 4: out << ", float4 t"; break;
-          default: UNREACHABLE();
+            switch(textureFunction->coords)
+            {
+              case 2: out << ", int2 t"; break;
+              case 3: out << ", int3 t"; break;
+              default: UNREACHABLE();
+            }
+        }
+        else   // Floating-point coordinates (except textureSize)
+        {
+            switch(textureFunction->coords)
+            {
+              case 1: out << ", int lod";  break;   // textureSize()
+              case 2: out << ", float2 t"; break;
+              case 3: out << ", float3 t"; break;
+              case 4: out << ", float4 t"; break;
+              default: UNREACHABLE();
+            }
         }
 
         switch(textureFunction->method)
@@ -1016,6 +1029,7 @@
           case TextureFunction::LOD:      out << ", float lod";  break;
           case TextureFunction::LOD0:                            break;
           case TextureFunction::SIZE:                            break;
+          case TextureFunction::FETCH:    out << ", int mip";    break;
           default: UNREACHABLE();
         }
 
@@ -1103,7 +1117,8 @@
         }
         else
         {
-            if (IsIntegerSampler(textureFunction->sampler))
+            if (IsIntegerSampler(textureFunction->sampler) &&
+                textureFunction->method != TextureFunction::FETCH)
             {
                 if (IsSampler2D(textureFunction->sampler))
                 {
@@ -1228,7 +1243,8 @@
             }
             else if (mOutputType == SH_HLSL11_OUTPUT)
             {
-                if (IsIntegerSampler(textureFunction->sampler))
+                if (IsIntegerSampler(textureFunction->sampler) ||
+                    textureFunction->method == TextureFunction::FETCH)
                 {
                     out << "x.Load(";
                 }
@@ -1256,7 +1272,8 @@
             TString addressz = "";
             TString close = "";
 
-            if (IsIntegerSampler(textureFunction->sampler))
+            if (IsIntegerSampler(textureFunction->sampler) ||
+                textureFunction->method == TextureFunction::FETCH)
             {
                 switch(hlslCoords)
                 {
@@ -1265,19 +1282,23 @@
                   default: UNREACHABLE();
                 }
             
-                addressx = "int(floor(width * frac((";
-                addressy = "int(floor(height * frac((";
-
-                if (IsSamplerArray(textureFunction->sampler))
+                // Convert from normalized floating-point to integer
+                if (textureFunction->method != TextureFunction::FETCH)
                 {
-                    addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
-                }
-                else
-                {
-                    addressz = "int(floor(depth * frac((";
-                }
+                    addressx = "int(floor(width * frac((";
+                    addressy = "int(floor(height * frac((";
 
-                close = "))))";
+                    if (IsSamplerArray(textureFunction->sampler))
+                    {
+                        addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
+                    }
+                    else
+                    {
+                        addressz = "int(floor(depth * frac((";
+                    }
+
+                    close = "))))";
+                }
             }
             else
             {
@@ -1338,7 +1359,8 @@
                     out << ", " + addressz + ("t.z" + proj) + close;
                 }
 
-                if (IsIntegerSampler(textureFunction->sampler))
+                if (IsIntegerSampler(textureFunction->sampler) ||
+                    textureFunction->method == TextureFunction::FETCH)
                 {
                     out << ", mip)";
                 }
@@ -2369,6 +2391,15 @@
                     textureFunction.proj = true;
                     textureFunction.offset = true;
                 }
+                else if (name == "texelFetch")
+                {
+                    textureFunction.method = TextureFunction::FETCH;
+                }
+                else if (name == "texelFetchOffset")
+                {
+                    textureFunction.method = TextureFunction::FETCH;
+                    textureFunction.offset = true;
+                }
                 else UNREACHABLE();
 
                 if (textureFunction.method == TextureFunction::IMPLICIT)   // Could require lod 0 or have a bias argument
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index d7556b8..e8d24f8 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -104,7 +104,8 @@
             BIAS,
             LOD,
             LOD0,
-            SIZE   // textureSize()
+            SIZE,   // textureSize()
+            FETCH
         };
 
         TBasicType sampler;