GLSL: workaround texture sampling with offset on depth arrays.

When calling textureSample() or textureSampleCompare() on a texture_depth_2d_array with an offset, use GLSL's
textureGradOffset() instead of textureOffset(), and explicitly
pass dFdx and dFdy of the texture coords parameter as the gradients.

Bug: 42240302
Change-Id: I8b18d832f62924b2c7d6d63c39a29e9e18ae6cbc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/198117
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 4ee3b91..f4256d8 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -1480,6 +1480,7 @@
     uint32_t glsl_ret_width = 4u;
     bool append_depth_ref_to_coords = true;
     bool is_depth = texture_type->Is<core::type::DepthTexture>();
+    bool is_array = IsTextureArray(texture_type->Dim());
 
     switch (builtin->Fn()) {
         case wgsl::BuiltinFn::kTextureSample:
@@ -1522,7 +1523,14 @@
             TINT_ICE() << "Unhandled texture builtin '" << std::string(builtin->str()) << "'";
     }
 
+    bool supplyDerivativesAsGradients = false;
     if (builtin->Signature().IndexOf(core::ParameterUsage::kOffset) >= 0) {
+        if ((builtin->Fn() == wgsl::BuiltinFn::kTextureSample ||
+             builtin->Fn() == wgsl::BuiltinFn::kTextureSampleCompare) &&
+            is_depth && is_array) {
+            out << "Grad";
+            supplyDerivativesAsGradients = true;
+        }
         out << "Offset";
     }
 
@@ -1560,6 +1568,14 @@
 
     emit_expr_as_signed(param_coords);
 
+    if (supplyDerivativesAsGradients) {
+        auto* coords = arg(Usage::kCoords);
+        out << ", dFdx(";
+        EmitExpression(out, coords);
+        out << "), dFdy(";
+        EmitExpression(out, coords);
+        out << ")";
+    }
     for (auto usage : {Usage::kLevel, Usage::kDdx, Usage::kDdy, Usage::kSampleIndex}) {
         if (auto* e = arg(usage)) {
             out << ", ";
diff --git a/src/tint/lang/glsl/writer/ast_printer/builtin_texture_test.cc b/src/tint/lang/glsl/writer/ast_printer/builtin_texture_test.cc
index b384c75..c8f158b 100644
--- a/src/tint/lang/glsl/writer/ast_printer/builtin_texture_test.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/builtin_texture_test.cc
@@ -154,7 +154,7 @@
         case ValidTextureOverload::kSampleDepth2dArrayF32:
             return R"(texture(Texture_Sampler, vec4(1.0f, 2.0f, float(3), 0.0f));)";
         case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
-            return R"(textureOffset(Texture_Sampler, vec4(1.0f, 2.0f, float(3), 0.0f), ivec2(4, 5));)";
+            return R"(textureGradOffset(Texture_Sampler, vec4(1.0f, 2.0f, float(3), 0.0f), dFdx(vec2(1.0f, 2.0f)), dFdy(vec2(1.0f, 2.0f)), ivec2(4, 5));)";
         case ValidTextureOverload::kSampleDepthCubeF32:
             return R"(texture(Texture_Sampler, vec4(1.0f, 2.0f, 3.0f, 0.0f));)";
         case ValidTextureOverload::kSampleDepthCubeArrayF32:
@@ -226,7 +226,7 @@
         case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
             return R"(texture(Texture_Sampler, vec4(1.0f, 2.0f, float(4), 3.0f));)";
         case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
-            return R"(textureOffset(Texture_Sampler, vec4(1.0f, 2.0f, float(4u), 3.0f), ivec2(5, 6));)";
+            return R"(textureGradOffset(Texture_Sampler, vec4(1.0f, 2.0f, float(4u), 3.0f), dFdx(vec2(1.0f, 2.0f)), dFdy(vec2(1.0f, 2.0f)), ivec2(5, 6));)";
         case ValidTextureOverload::kSampleCompareDepthCubeF32:
             return R"(texture(Texture_Sampler, vec4(1.0f, 2.0f, 3.0f, 4.0f));)";
         case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
diff --git a/test/tint/builtins/gen/literal/textureSample/4703d0.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureSample/4703d0.wgsl.expected.glsl
index 2c7c454..82e522b 100644
--- a/test/tint/builtins/gen/literal/textureSample/4703d0.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureSample/4703d0.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -11,7 +9,7 @@
 uniform highp sampler2DArrayShadow arg_0_arg_1;
 
 float textureSample_4703d0() {
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1u)), 0.0f), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1u)), 0.0f), dFdx(vec2(1.0f)), dFdy(vec2(1.0f)), ivec2(1));
   return res;
 }
 
@@ -23,12 +21,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/literal/textureSample/60bf45.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureSample/60bf45.wgsl.expected.glsl
index 53b2428..a67ca71 100644
--- a/test/tint/builtins/gen/literal/textureSample/60bf45.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureSample/60bf45.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -11,7 +9,7 @@
 uniform highp sampler2DArrayShadow arg_0_arg_1;
 
 float textureSample_60bf45() {
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1)), 0.0f), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1)), 0.0f), dFdx(vec2(1.0f)), dFdy(vec2(1.0f)), ivec2(1));
   return res;
 }
 
@@ -23,12 +21,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/literal/textureSampleCompare/7b5025.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureSampleCompare/7b5025.wgsl.expected.glsl
index f009aa4..a439863 100644
--- a/test/tint/builtins/gen/literal/textureSampleCompare/7b5025.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureSampleCompare/7b5025.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -11,7 +9,7 @@
 uniform highp sampler2DArrayShadow arg_0_arg_1;
 
 float textureSampleCompare_7b5025() {
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1u)), 1.0f), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1u)), 1.0f), dFdx(vec2(1.0f)), dFdy(vec2(1.0f)), ivec2(1));
   return res;
 }
 
@@ -23,12 +21,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/literal/textureSampleCompare/af1051.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureSampleCompare/af1051.wgsl.expected.glsl
index 28b6b19..e1d4652 100644
--- a/test/tint/builtins/gen/literal/textureSampleCompare/af1051.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureSampleCompare/af1051.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -11,7 +9,7 @@
 uniform highp sampler2DArrayShadow arg_0_arg_1;
 
 float textureSampleCompare_af1051() {
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1)), 1.0f), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(vec2(1.0f), float(1)), 1.0f), dFdx(vec2(1.0f)), dFdy(vec2(1.0f)), ivec2(1));
   return res;
 }
 
@@ -23,12 +21,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/textureSample/4703d0.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureSample/4703d0.wgsl.expected.glsl
index f9c5dc3..19abef6 100644
--- a/test/tint/builtins/gen/var/textureSample/4703d0.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureSample/4703d0.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -13,7 +11,7 @@
 float textureSample_4703d0() {
   vec2 arg_2 = vec2(1.0f);
   uint arg_3 = 1u;
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), 0.0f), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), 0.0f), dFdx(arg_2), dFdy(arg_2), ivec2(1));
   return res;
 }
 
@@ -25,12 +23,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/textureSample/60bf45.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureSample/60bf45.wgsl.expected.glsl
index b3e933f..8dce77b 100644
--- a/test/tint/builtins/gen/var/textureSample/60bf45.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureSample/60bf45.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -13,7 +11,7 @@
 float textureSample_60bf45() {
   vec2 arg_2 = vec2(1.0f);
   int arg_3 = 1;
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), 0.0f), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), 0.0f), dFdx(arg_2), dFdy(arg_2), ivec2(1));
   return res;
 }
 
@@ -25,12 +23,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/textureSampleCompare/7b5025.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureSampleCompare/7b5025.wgsl.expected.glsl
index 2dbab2a..0b00a71c1 100644
--- a/test/tint/builtins/gen/var/textureSampleCompare/7b5025.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureSampleCompare/7b5025.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -14,7 +12,7 @@
   vec2 arg_2 = vec2(1.0f);
   uint arg_3 = 1u;
   float arg_4 = 1.0f;
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), arg_4), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), arg_4), dFdx(arg_2), dFdy(arg_2), ivec2(1));
   return res;
 }
 
@@ -26,12 +24,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:15: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:15: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/textureSampleCompare/af1051.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureSampleCompare/af1051.wgsl.expected.glsl
index 395423e..fede927 100644
--- a/test/tint/builtins/gen/var/textureSampleCompare/af1051.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureSampleCompare/af1051.wgsl.expected.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -14,7 +12,7 @@
   vec2 arg_2 = vec2(1.0f);
   int arg_3 = 1;
   float arg_4 = 1.0f;
-  float res = textureOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), arg_4), ivec2(1));
+  float res = textureGradOffset(arg_0_arg_1, vec4(vec3(arg_2, float(arg_3)), arg_4), dFdx(arg_2), dFdy(arg_2), ivec2(1));
   return res;
 }
 
@@ -26,12 +24,3 @@
   fragment_main();
   return;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:15: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:15: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/unittest/reader/spirv/ImageSampleDrefImplicitLod_SpvParserHandleTest_SampledImageAccessTest_Variable_3.spvasm.expected.glsl b/test/tint/unittest/reader/spirv/ImageSampleDrefImplicitLod_SpvParserHandleTest_SampledImageAccessTest_Variable_3.spvasm.expected.glsl
deleted file mode 100644
index 195d058..0000000
--- a/test/tint/unittest/reader/spirv/ImageSampleDrefImplicitLod_SpvParserHandleTest_SampledImageAccessTest_Variable_3.spvasm.expected.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-SKIP: FAILED
-
-#version 310 es
-precision highp float;
-precision highp int;
-
-int tint_ftoi(float v) {
-  return ((v <= 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
-}
-
-uniform highp sampler2DArrayShadow x_20_x_10;
-
-void main_1() {
-  float f1 = 1.0f;
-  vec2 vf12 = vec2(1.0f, 2.0f);
-  vec2 vf21 = vec2(2.0f, 1.0f);
-  vec3 vf123 = vec3(1.0f, 2.0f, 3.0f);
-  vec4 vf1234 = vec4(1.0f, 2.0f, 3.0f, 4.0f);
-  int i1 = 1;
-  ivec2 vi12 = ivec2(1, 2);
-  ivec3 vi123 = ivec3(1, 2, 3);
-  ivec4 vi1234 = ivec4(1, 2, 3, 4);
-  uint u1 = 1u;
-  uvec2 vu12 = uvec2(1u, 2u);
-  uvec3 vu123 = uvec3(1u, 2u, 3u);
-  uvec4 vu1234 = uvec4(1u, 2u, 3u, 4u);
-  float coords1 = 1.0f;
-  vec2 coords12 = vf12;
-  vec3 coords123 = vf123;
-  vec4 coords1234 = vf1234;
-  float x_79 = textureOffset(x_20_x_10, vec4(vec3(coords123.xy, float(tint_ftoi(round(coords123.z)))), 0.20000000298023223877f), ivec2(3, 4));
-  return;
-}
-
-void tint_symbol() {
-  main_1();
-}
-
-void main() {
-  tint_symbol();
-  return;
-}
-error: Error parsing GLSL shader:
-ERROR: 0:29: 'sampler' : TextureOffset does not support sampler2DArrayShadow :  ES Profile
-ERROR: 0:29: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1