[Compat] Fix a bug when textureDimension with 1 arg is first called

When textureDimension with 1 arg is first called,
it accidentally returns TextureQueryType::kTextureNumSamples.

Add tests and asserts to add some robustness.

Also fixes same bug for TextureLoad.

Bug: dawn:2442
Change-Id: Ida753f7ae99417c683e20704e89c379837ccdf70
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/184640
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Shrek Shao <shrekshao@google.com>
diff --git a/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp b/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp
index 429f722..847bfa0 100644
--- a/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp
+++ b/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp
@@ -203,6 +203,139 @@
     EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, 0, sizeof(expected) / sizeof(uint32_t));
 }
 
+// Testing that baseMipLevel is handled correctly.
+TEST_P(TextureShaderBuiltinTests, BaseMipLevelTextureView) {
+    // TODO(dawn:2538): failing on OpenGLES Angle backed by D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsANGLED3D11());
+    constexpr uint32_t kCubeLayers = 1;
+    constexpr uint32_t kMipLevels = 3;
+    wgpu::Texture tex =
+        CreateTexture("tex", kCubeLayers, kMipLevels, 1, wgpu::TextureViewDimension::e2D);
+
+    constexpr uint32_t kBaseMipLevel = 1;
+    constexpr uint32_t kViewMipLevelCount = 2;
+    DAWN_ASSERT(kBaseMipLevel + kViewMipLevelCount <= kMipLevels);
+    wgpu::TextureView texView = CreateTextureView(tex, "texView", wgpu::TextureViewDimension::e2D,
+                                                  kBaseMipLevel, kViewMipLevelCount);
+
+    const uint32_t textureWidthLevel0 = 1 << kMipLevels;
+    const uint32_t textureWidthLevel1 = textureWidthLevel0 >> 1;
+    const uint32_t textureWidthLevel2 = textureWidthLevel1 >> 1;
+    const uint32_t expected[] = {
+        textureWidthLevel1,
+        textureWidthLevel1,
+        textureWidthLevel2,
+    };
+
+    wgpu::BufferDescriptor bufferDesc;
+    bufferDesc.size = sizeof(expected);
+    bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
+    wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
+
+    std::ostringstream shaderSource;
+    // clang-format off
+    shaderSource << R"(
+    @group(0) @binding(0) var<storage, read_write> dstBuf : array<u32>;
+    @group(0) @binding(1) var tex : texture_2d<f32>;
+
+    @compute @workgroup_size(1, 1, 1) fn main() {
+        dstBuf[0] = textureDimensions(tex).x;
+        dstBuf[1] = textureDimensions(tex, 0).x;
+        dstBuf[2] = textureDimensions(tex, 1).x;
+    }
+    )";
+    // clang-format on
+
+    wgpu::ComputePipelineDescriptor pipelineDescriptor;
+    pipelineDescriptor.compute.module = utils::CreateShaderModule(device, shaderSource.str());
+    wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDescriptor);
+
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    {
+        wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+        pass.SetPipeline(pipeline);
+        pass.SetBindGroup(0, utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
+                                                  {
+                                                      {0, buffer},
+                                                      {1, texView},
+                                                  }));
+        pass.DispatchWorkgroups(1);
+        pass.End();
+    }
+
+    wgpu::CommandBuffer commands = encoder.Finish();
+    queue.Submit(1, &commands);
+
+    EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, 0, sizeof(expected) / sizeof(uint32_t));
+}
+
+// Testing that baseMipLevel is handled correctly for texture_cube.
+TEST_P(TextureShaderBuiltinTests, BaseMipLevelTextureViewCube) {
+    // TODO(dawn:2442): fix texture_cube base mip level bug.
+    DAWN_SUPPRESS_TEST_IF(IsCompatibilityMode());
+    constexpr uint32_t kCubeLayers = 6;
+    constexpr uint32_t kMipLevels = 3;
+    wgpu::Texture texCube =
+        CreateTexture("texCube", kCubeLayers, kMipLevels, 1, wgpu::TextureViewDimension::Cube);
+
+    constexpr uint32_t kBaseMipLevel = 1;
+    constexpr uint32_t kViewMipLevelCount = 2;
+    DAWN_ASSERT(kBaseMipLevel + kViewMipLevelCount <= kMipLevels);
+    wgpu::TextureView texViewCube =
+        CreateTextureView(texCube, "texViewCube", wgpu::TextureViewDimension::Cube, kBaseMipLevel,
+                          kViewMipLevelCount);
+
+    const uint32_t textureWidthLevel0 = 1 << kMipLevels;
+    const uint32_t textureWidthLevel1 = textureWidthLevel0 >> 1;
+    const uint32_t textureWidthLevel2 = textureWidthLevel1 >> 1;
+    const uint32_t expected[] = {
+        textureWidthLevel1,
+        textureWidthLevel1,
+        textureWidthLevel2,
+    };
+
+    wgpu::BufferDescriptor bufferDesc;
+    bufferDesc.size = sizeof(expected);
+    bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
+    wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
+
+    std::ostringstream shaderSource;
+    // clang-format off
+    shaderSource << R"(
+    @group(0) @binding(0) var<storage, read_write> dstBuf : array<u32>;
+    @group(0) @binding(1) var tex_cube : texture_cube<f32>;
+
+    @compute @workgroup_size(1, 1, 1) fn main() {
+        dstBuf[0] = textureDimensions(tex_cube).x;
+        dstBuf[1] = textureDimensions(tex_cube, 0).x;
+        dstBuf[2] = textureDimensions(tex_cube, 1).x;
+    }
+    )";
+    // clang-format on
+
+    wgpu::ComputePipelineDescriptor pipelineDescriptor;
+    pipelineDescriptor.compute.module = utils::CreateShaderModule(device, shaderSource.str());
+    wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDescriptor);
+
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    {
+        wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+        pass.SetPipeline(pipeline);
+        pass.SetBindGroup(0, utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
+                                                  {
+                                                      {0, buffer},
+                                                      {1, texViewCube},
+                                                  }));
+        pass.DispatchWorkgroups(1);
+        pass.End();
+    }
+
+    wgpu::CommandBuffer commands = encoder.Finish();
+    queue.Submit(1, &commands);
+
+    EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, 0, sizeof(expected) / sizeof(uint32_t));
+}
+
 // Test calling textureNumLevels & textureNumSamples inside function and taking a function param as
 // the argument.
 TEST_P(TextureShaderBuiltinTests, BuiltinCallInFunction) {
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index f00ab13..1cdbcac 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -1029,24 +1029,14 @@
 
     std::unordered_set<BindingPoint> seen = {};
 
-    auto sample_type_for_call_and_type = [](wgsl::BuiltinFn builtin, const core::type::Type* ty,
-                                            const Vector<const ast::Expression*, 8>& args) {
-        if (builtin == wgsl::BuiltinFn::kTextureNumLevels) {
+    auto sample_type_for_call_and_type = [](wgsl::BuiltinFn builtin) {
+        if (builtin == wgsl::BuiltinFn::kTextureNumLevels ||
+            builtin == wgsl::BuiltinFn::kTextureDimensions ||
+            builtin == wgsl::BuiltinFn::kTextureLoad) {
             return TextureQueryType::kTextureNumLevels;
         }
-        if (builtin == wgsl::BuiltinFn::kTextureDimensions && args.Length() > 1) {
-            // When textureDimension takes level as the input,
-            // it requires calls to textureNumLevels to clamp mip levels.
-            return TextureQueryType::kTextureNumLevels;
-        }
-        if (builtin == wgsl::BuiltinFn::kTextureLoad) {
-            if (!ty->UnwrapRef()
-                     ->IsAnyOf<core::type::MultisampledTexture,
-                               core::type::DepthMultisampledTexture>()) {
-                return TextureQueryType::kTextureNumLevels;
-            }
-        }
 
+        TINT_ASSERT(builtin == wgsl::BuiltinFn::kTextureNumSamples);
         return TextureQueryType::kTextureNumSamples;
     };
 
@@ -1101,19 +1091,27 @@
                 call->Target(),
                 [&](const sem::BuiltinFn* builtin) {
                     if (builtin->Fn() != wgsl::BuiltinFn::kTextureNumLevels &&
-                        builtin->Fn() != wgsl::BuiltinFn::kTextureDimensions &&
                         builtin->Fn() != wgsl::BuiltinFn::kTextureNumSamples &&
-                        builtin->Fn() != wgsl::BuiltinFn::kTextureLoad) {
+                        builtin->Fn() != wgsl::BuiltinFn::kTextureLoad &&
+                        // When textureDimension takes level as the input,
+                        // it requires calls to textureNumLevels to clamp mip levels.
+                        !(builtin->Fn() == wgsl::BuiltinFn::kTextureDimensions &&
+                          call->Declaration()->args.Length() > 1)) {
                         return;
                     }
 
                     auto* texture_expr = call->Declaration()->args[0];
                     auto* texture_sem = sem.GetVal(texture_expr)->RootIdentifier();
                     TINT_ASSERT(texture_sem);
+                    if (builtin->Fn() == wgsl::BuiltinFn::kTextureLoad &&
+                        texture_sem->Type()
+                            ->UnwrapRef()
+                            ->IsAnyOf<core::type::MultisampledTexture,
+                                      core::type::DepthMultisampledTexture>()) {
+                        return;
+                    }
 
-                    auto type = sample_type_for_call_and_type(builtin->Fn(), texture_sem->Type(),
-                                                              call->Declaration()->args);
-
+                    auto type = sample_type_for_call_and_type(builtin->Fn());
                     tint::Switch(
                         texture_sem,  //
                         [&](const sem::GlobalVariable* global) { save_if_needed(global, type); },
diff --git a/src/tint/lang/wgsl/inspector/inspector_test.cc b/src/tint/lang/wgsl/inspector/inspector_test.cc
index 8d1a4b3..7468ccc 100644
--- a/src/tint/lang/wgsl/inspector/inspector_test.cc
+++ b/src/tint/lang/wgsl/inspector/inspector_test.cc
@@ -3931,22 +3931,20 @@
     Inspector& inspector = Initialize(shader);
     auto info = inspector.GetTextureQueries("main");
 
-    ASSERT_EQ(1u, info.size());
-
-    EXPECT_EQ(Inspector::TextureQueryType::kTextureNumSamples, info[0].type);
-    EXPECT_EQ(2u, info[0].group);
-    EXPECT_EQ(3u, info[0].binding);
+    ASSERT_EQ(0u, info.size());
 }
 
 TEST_F(InspectorTextureTest, TextureLoadMultipleInEP) {
     std::string shader = R"(
 @group(2) @binding(3) var tex1: texture_2d<f32>;
 @group(1) @binding(4) var tex2: texture_multisampled_2d<f32>;
+@group(0) @binding(1) var tex3: texture_2d<f32>;
 
 @compute @workgroup_size(1)
 fn main() {
   let num1 = textureLoad(tex1, vec2(0, 0), 0);
   let num2 = textureLoad(tex2, vec2(0, 0), 0);
+  let num3 = textureLoad(tex3, vec2(0, 0), 0);
 })";
 
     Inspector& inspector = Initialize(shader);
@@ -3957,9 +3955,9 @@
     EXPECT_EQ(Inspector::TextureQueryType::kTextureNumLevels, info[0].type);
     EXPECT_EQ(2u, info[0].group);
     EXPECT_EQ(3u, info[0].binding);
-    EXPECT_EQ(Inspector::TextureQueryType::kTextureNumSamples, info[1].type);
-    EXPECT_EQ(1u, info[1].group);
-    EXPECT_EQ(4u, info[1].binding);
+    EXPECT_EQ(Inspector::TextureQueryType::kTextureNumLevels, info[1].type);
+    EXPECT_EQ(0u, info[1].group);
+    EXPECT_EQ(1u, info[1].binding);
 }
 
 TEST_F(InspectorTextureTest, TextureInSubfunction) {