[spirv-reader][ir] Support OpImageSampleDrefExplicitLod

Handle the `OpImageSampleDrefExplicitLod` instruction, converting the
texture to depth texture and sampler to sampler_comparison as needed.

Bug: 407384678
Change-Id: I2440bf0409fc6c75194d2edfc633d7482fa8547b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/248297
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/spirv/reader/lower/builtins.cc b/src/tint/lang/spirv/reader/lower/builtins.cc
index ec04027..9bf7fb3 100644
--- a/src/tint/lang/spirv/reader/lower/builtins.cc
+++ b/src/tint/lang/spirv/reader/lower/builtins.cc
@@ -248,6 +248,7 @@
                 case spirv::BuiltinFn::kImageSampleProjImplicitLod:
                 case spirv::BuiltinFn::kImageSampleProjExplicitLod:
                 case spirv::BuiltinFn::kImageSampleDrefImplicitLod:
+                case spirv::BuiltinFn::kImageSampleDrefExplicitLod:
                 case spirv::BuiltinFn::kImageWrite:
                     // Ignore image methods, they'll be handled by the `Texture` transform.
                     break;
diff --git a/src/tint/lang/spirv/reader/lower/texture.cc b/src/tint/lang/spirv/reader/lower/texture.cc
index 8ecbbee..eb7791c 100644
--- a/src/tint/lang/spirv/reader/lower/texture.cc
+++ b/src/tint/lang/spirv/reader/lower/texture.cc
@@ -150,6 +150,7 @@
                         builtin_worklist.Push(builtin);
                         break;
                     case spirv::BuiltinFn::kImageSampleDrefImplicitLod:
+                    case spirv::BuiltinFn::kImageSampleDrefExplicitLod:
                         depth_worklist.Push(builtin);
                         break;
                     default:
@@ -167,6 +168,7 @@
         for (auto* builtin : depth_worklist) {
             switch (builtin->Func()) {
                 case spirv::BuiltinFn::kImageSampleDrefImplicitLod:
+                case spirv::BuiltinFn::kImageSampleDrefExplicitLod:
                     ImageSampleDref(builtin);
                     break;
                 default:
@@ -624,12 +626,19 @@
             ProcessCoords(tex_ty, false, coords, new_args);
             new_args.Push(depth);
 
+            auto fn = core::BuiltinFn::kTextureSampleCompare;
+            if (HasLod(operand_mask)) {
+                fn = core::BuiltinFn::kTextureSampleCompareLevel;
+                idx++;  // Skip over the index
+
+                // Metal only supports Lod = 0 for comparison sampling without derivatives. So, WGSL
+                // doesn't take a level value, drop the LOD param.
+            }
             if (HasConstOffset(operand_mask)) {
                 ProcessOffset(args[idx++], new_args);
             }
 
-            b.CallWithResult(call->DetachResult(), core::BuiltinFn::kTextureSampleCompare,
-                             new_args);
+            b.CallWithResult(call->DetachResult(), fn, new_args);
         });
 
         call->Destroy();
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index ae7214a..c9cb1da 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -1781,6 +1781,9 @@
                 case spv::Op::OpImageSampleDrefImplicitLod:
                     EmitImageSampleDepth(inst, spirv::BuiltinFn::kImageSampleDrefImplicitLod);
                     break;
+                case spv::Op::OpImageSampleDrefExplicitLod:
+                    EmitImageSampleDepth(inst, spirv::BuiltinFn::kImageSampleDrefExplicitLod);
+                    break;
                 case spv::Op::OpPhi:
                     EmitPhi(inst);
                     break;
diff --git a/src/tint/lang/spirv/reader/texture_test.cc b/src/tint/lang/spirv/reader/texture_test.cc
index 24d69cc..c67109f 100644
--- a/src/tint/lang/spirv/reader/texture_test.cc
+++ b/src/tint/lang/spirv/reader/texture_test.cc
@@ -1379,6 +1379,7 @@
 %float_3 = OpConstant %float 3
 %float_4 = OpConstant %float 4
 %float_5 = OpConstant %float 5
+%float_null = OpConstantNull %float
 %coords2 = OpConstantComposite %v2float %float_1 %float_2
 %coords3 = OpConstantComposite %v3float %float_1 %float_2 %float_3
 %coords4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
@@ -1469,27 +1470,40 @@
     %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
     %8:i32 = convert %7
     %9:f32 = textureSampleCompare %5, %4, %6, %8, 1.0f, vec2<i32>(10i, 11i))",
+        },
+        ImgData{
+            .name = "2D vec2 depth",
+            .spirv_type = "%float 2D 1 0 0 1 Unknown",
+            .spirv_fn = "OpImageSampleDrefImplicitLod %float %sampled_image %coords2 %float_1",
+            .wgsl_type = "texture_depth_2d",
+            .wgsl_fn = R"(
+    %6:f32 = textureSampleCompare %5, %4, vec2<f32>(1.0f, 2.0f), 1.0f)",
         }));
 
 INSTANTIATE_TEST_SUITE_P(
-    DISABLED_SpirvReaderTest_ImageSampleDrefExplicitLod,
+    SpirvReaderTest_ImageSampleDrefExplicitLod,
     SamplerComparisonTest,
     ::testing::Values(
         ImgData{
             .name = "2D",
             .spirv_type = "%float 2D 1 0 0 1 Unknown",
-            .spirv_fn = "OpImageSampleDrefExplicitLod %float %sampled_image %coords2 "
-                        "%depth Lod %float_0",
+            .spirv_fn =
+                "OpImageSampleDrefExplicitLod %float %sampled_image %coords2 %depth Lod %float_0",
             .wgsl_type = "texture_depth_2d",
-            .wgsl_fn = "textureSampleCompareLevel %4, %5, vec2<f32>(1.0f, 2.0f), 1.0f",
+            .wgsl_fn = R"(
+    %6:f32 = textureSampleCompareLevel %5, %4, vec2<f32>(1.0f, 2.0f), 1.0f)",
         },
         ImgData{
             .name = "2D array",
             .spirv_type = "%float 2D 1 1 0 1 Unknown",
-            .spirv_fn = "OpImageSampleDrefExplicitLod %float %sampled_image %coords3 "
-                        "%depth Lod %float_0",
+            .spirv_fn =
+                "OpImageSampleDrefExplicitLod %float %sampled_image %coords3 %depth Lod %float_0",
             .wgsl_type = "texture_depth_2d_array",
-            .wgsl_fn = "textureSampleCompareLevel %4, %5, vec2<f32>(1.0f, 2.0f), 3i, 1.0f",
+            .wgsl_fn = R"(
+    %6:vec2<f32> = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), xy
+    %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
+    %8:i32 = convert %7
+    %9:f32 = textureSampleCompareLevel %5, %4, %6, %8, 1.0f)",
         },
         ImgData{
             .name = "2D ConstOffset",
@@ -1497,8 +1511,8 @@
             .spirv_fn = "OpImageSampleDrefExplicitLod %float %sampled_image %coords2 %depth "
                         "Lod|ConstOffset %float_0 %offset2i",
             .wgsl_type = "texture_depth_2d",
-            .wgsl_fn = "textureSampleCompareLevel %4, %5, vec2<f32>(1.0f, 2.0f), 1.0f, "
-                       "vec2<i32>(10i, 11i)",
+            .wgsl_fn = R"(
+    %6:f32 = textureSampleCompareLevel %5, %4, vec2<f32>(1.0f, 2.0f), 1.0f, vec2<i32>(10i, 11i))",
         },
         ImgData{
             .name = "2D array ConstOffset",
@@ -1506,26 +1520,44 @@
             .spirv_fn = "OpImageSampleDrefExplicitLod %float %sampled_image %coords3 %depth "
                         "Lod|ConstOffset %float_0 %offset2i",
             .wgsl_type = "texture_depth_2d_array",
-            .wgsl_fn = "textureSampleCompareLevel %4, %5, vec2<f32>(1.0f, 2.0f), 3i, 1.0f, "
-                       "vec2<i32>(10i, 11i)",
+            .wgsl_fn = R"(
+    %6:vec2<f32> = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), xy
+    %7:f32 = swizzle vec3<f32>(1.0f, 2.0f, 3.0f), z
+    %8:i32 = convert %7
+    %9:f32 = textureSampleCompareLevel %5, %4, %6, %8, 1.0f, vec2<i32>(10i, 11i))",
         },
         ImgData{
             .name = "Cube",
             .spirv_type = "%float Cube 1 0 0 1 Unknown",
-            .spirv_fn = "OpImageSampleDrefExplicitLod %float %sampled_image %coords3 "
-                        "%depth Lod %float_0",
+            .spirv_fn =
+                "OpImageSampleDrefExplicitLod %float %sampled_image %coords3 %depth Lod %float_0",
             .wgsl_type = "texture_depth_cube",
-            .wgsl_fn = "textureSampleCompareLevel %4, %5, vec3<f32>(1.0f, 2.0f, 3.0f), 1.0f",
+            .wgsl_fn = R"(
+    %6:f32 = textureSampleCompareLevel %5, %4, vec3<f32>(1.0f, 2.0f, 3.0f), 1.0f)",
         },
         ImgData{
             .name = "Cube array",
             .spirv_type = "%float Cube 1 1 0 1 Unknown",
-            .spirv_fn = "OpImageSampleDrefExplicitLod %float %sampled_image %coords4 "
-                        "%depth Lod %float_0",
+            .spirv_fn =
+                "OpImageSampleDrefExplicitLod %float %sampled_image %coords4 %depth Lod %float_0",
             .wgsl_type = "texture_depth_cube_array",
-            .wgsl_fn = "textureSampleCompareLevel %4, %5, vec3<f32>(1.0f, 2.0f, 3.0f), "
-                       "4i, 1.0f",
-        }));
+            .wgsl_fn = R"(
+    %6:vec3<f32> = swizzle vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f), xyz
+    %7:f32 = swizzle vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f), w
+    %8:i32 = convert %7
+    %9:f32 = textureSampleCompareLevel %5, %4, %6, %8, 1.0f)",
+        },
+        ImgData{
+            .name = "2d vec2 depth lod",
+            .spirv_type = "%float 2D 1 0 0 1 Unknown",
+            .spirv_fn =
+                "OpImageSampleDrefExplicitLod %float %sampled_image %coords2 %float_1 Lod %float_0",
+            .wgsl_type = "texture_depth_2d",
+            .wgsl_fn = R"(
+    %6:f32 = textureSampleCompareLevel %5, %4, vec2<f32>(1.0f, 2.0f), 1.0f)",
+        }
+
+        ));
 
 INSTANTIATE_TEST_SUITE_P(
     DISABLED_SpirvReaderTest_ImageSampleProjDrefImplicitLod,
@@ -1570,6 +1602,34 @@
                        "vec2<i32>(10i, 11i)",
         }));
 
+// Metal requires comparison sampling with explicit Level-of-detail to use Lod 0.  The SPIR-V reader
+// requires the operand to be parsed as a constant 0 value. SPIR-V validation requires the Lod
+// parameter to be a floating point value for non-fetch operations. So only test float values.
+INSTANTIATE_TEST_SUITE_P(
+    SpirvReaderTest_ImageSampleDrefExplicitLod_CheckForLod0,
+    SamplerComparisonTest,
+    ::testing::Values(
+        ImgData{
+            .name = "2d 0.0",
+            .spirv_type = "%float 2D 1 0 0 1 Unknown",
+            .spirv_fn =
+                "OpImageSampleDrefExplicitLod %float %sampled_image %coords4 %float_1 Lod %float_0",
+            .wgsl_type = "texture_depth_2d",
+            .wgsl_fn = R"(
+    %6:vec2<f32> = swizzle vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f), xy
+    %7:f32 = textureSampleCompareLevel %5, %4, %6, 1.0f)",
+        },
+        ImgData{
+            .name = "2D null",
+            .spirv_type = "%float 2D 1 0 0 1 Unknown",
+            .spirv_fn = "OpImageSampleDrefExplicitLod %float %sampled_image %coords4 %float_1 Lod "
+                        "%float_null",
+            .wgsl_type = "texture_depth_2d",
+            .wgsl_fn = R"(
+    %6:vec2<f32> = swizzle vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f), xy
+    %7:f32 = textureSampleCompareLevel %5, %4, %6, 1.0f)",
+        }));
+
 // This test shows the use of a sampled image used with both regular
 // sampling and depth-reference sampling.  The texture is a depth-texture,
 // and we use builtins textureSample and textureSampleCompare
@@ -2900,7 +2960,7 @@
 // In SPIR-V, sampling and dref sampling operations use floating point coordinates.  Prove that we
 // preserve floating point-ness. Test across all such instructions.
 INSTANTIATE_TEST_SUITE_P(
-    DISABLED_SpirvReaderTest_PreserveFloatCoords_NonArrayed,
+    SpirvReaderTest_PreserveFloatCoords_NonArrayed,
     SampledImageCoordsTest,
     ::testing::Values(
         // Scalar cases
@@ -2908,48 +2968,35 @@
             .name = "1D",
             .spirv_type = "%float 1D 0 0 0 1 Unknown",
             .spirv_fn = "%result = OpImageSampleImplicitLod %v4float %sampled_image %float_1",
-            .wgsl_type = "",
-            .wgsl_fn = "f1",
+            .wgsl_type = "texture_1d<f32>",
+            .wgsl_fn = R"(
+    %6:vec4<f32> = textureSample %5, %4, 1.0f)",
         },
         ImgData{
             .name = "1D lod",
             .spirv_type = "%float 1D 0 0 0 1 Unknown",
             .spirv_fn =
                 "%result = OpImageSampleExplicitLod %v4float %sampled_image %float_1 Lod %float_1",
-            .wgsl_type = "",
-            .wgsl_fn = "f1",
+            .wgsl_type = "texture_1d<f32>",
+            .wgsl_fn = R"(
+    %6:vec4<f32> = textureSampleLevel %5, %4, 1.0f, 1.0f)",
         },
         ImgData{
             .name = "2D vec2",
             .spirv_type = "%float 2D 0 0 0 1 Unknown",
             .spirv_fn = "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf12",
-            .wgsl_type = "",
-            .wgsl_fn = "vf12",
+            .wgsl_type = "texture_2d<f32>",
+            .wgsl_fn = R"(
+    %6:vec4<f32> = textureSample %5, %4, vec2<f32>(1.0f, 2.0f))",
         },
         ImgData{
             .name = "2D vec2 lod",
             .spirv_type = "%float 2D 0 0 0 1 Unknown",
             .spirv_fn =
                 "%result = OpImageSampleExplicitLod %v4float %sampled_image %vf12 Lod %float_1",
-            .wgsl_type = "",
-            .wgsl_fn = "vf12",
-        },
-        ImgData{
-            .name = "2D vec2 depth",
-            .spirv_type = "%float 2D 1 0 0 1 Unknown",
-            .spirv_fn =
-                "%result = OpImageSampleDrefImplicitLod %float %sampled_image %vf12 %float_1",
-            .wgsl_type = "",
-            .wgsl_fn = "vf12",
-        },
-        ImgData{
-            .name = "2d vec2 depth lod",
-            .spirv_type = "%float 2D 1 0 0 1 Unknown",
-            .spirv_fn =
-                "%result = OpImageSampleDrefExplicitLod %float %sampled_image %vf12 %float_1 "
-                "Lod %float_0",
-            .wgsl_type = "",
-            .wgsl_fn = "vf12",
+            .wgsl_type = "texture_2d<f32>",
+            .wgsl_fn = R"(
+    %6:vec4<f32> = textureSampleLevel %5, %4, vec2<f32>(1.0f, 2.0f), 1.0f)",
         }));
 
 // In SPIR-V, sampling and dref sampling operations use floating point coordinates.  Prove that we
@@ -2994,30 +3041,6 @@
             .wgsl_fn = "vf123.xy",
         }));
 
-// Metal requires comparison sampling with explicit Level-of-detail to use Lod 0.  The SPIR-V reader
-// requires the operand to be parsed as a constant 0 value. SPIR-V validation requires the Lod
-// parameter to be a floating point value for non-fetch operations. So only test float values.
-INSTANTIATE_TEST_SUITE_P(
-    DISABLED_SpirvReaderTest_ImageSampleDrefExplicitLod_CheckForLod0,
-    SampledImageCoordsTest,
-    ::testing::Values(
-        ImgData{
-            .name = "2d 0.0",
-            .spirv_type = "%float 2D 1 0 0 1 Unknown",
-            .spirv_fn = "%result = OpImageSampleDrefExplicitLod %float %sampled_image "
-                        "%vf1234 %float_1 Lod %float_0",
-            .wgsl_type = "",
-            .wgsl_fn = "vf1234.xy",
-        },
-        ImgData{
-            .name = "2D null",
-            .spirv_type = "%float 2D 1 0 0 1 Unknown",
-            .spirv_fn = "%result = OpImageSampleDrefExplicitLod %float %sampled_image "
-                        "%vf1234 %float_1 Lod %float_null",
-            .wgsl_type = "",
-            .wgsl_fn = "vf1234.xy",
-        }));
-
 // This is like the previous test, but for Projection sampling.
 //
 // Metal requires comparison sampling with explicit Level-of-detail to use Lod 0.  The SPIR-V reader