Vulkan: Enable sampleRateShading for WGSL builtin variable [[sample_index]]

This patch enables VkPhysicalDeviceFeatures.sampleRateShading as is required
by the SPIR-V Capability (SampleRateShading) for the implementation of
WGSL built-in variable [[sample_index]] (gl_SampleID). Without enabling
smapleRateShading on the creation of VkDevice the Vulkan validation layer
will generate below error message:

Warning: Validation Error: [ VUID-VkShaderModuleCreateInfo-pCode-01091 ]
Object 0: handle = xxx, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xa7bb8db6 |
vkCreateShaderModule(): The SPIR-V Capability (SampleRateShading) was declared,
but none of the requirements were met to use it. The Vulkan spec states: If
pCode declares any of the capabilities listed in the SPIR-V Environment appendix,
one of the corresponding requirements must be satisfied.

BUG=tint:471, dawn:802
TEST=dawn_end2end_tests

Change-Id: Id0c91fa48dfae37b2548ee9f3922d93dfa1da5d9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/59900
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn_native/vulkan/AdapterVk.cpp b/src/dawn_native/vulkan/AdapterVk.cpp
index 2226d9a..6250edb 100644
--- a/src/dawn_native/vulkan/AdapterVk.cpp
+++ b/src/dawn_native/vulkan/AdapterVk.cpp
@@ -109,6 +109,9 @@
         if (!mDeviceInfo.features.independentBlend) {
             return DAWN_INTERNAL_ERROR("Vulkan independentBlend feature required.");
         }
+        if (!mDeviceInfo.features.sampleRateShading) {
+            return DAWN_INTERNAL_ERROR("Vulkan sampleRateShading feature required.");
+        }
 
         // Check base WebGPU limits are supported.
         const VkPhysicalDeviceLimits& limits = mDeviceInfo.properties.limits;
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index ad9dce7..2f1e4d9 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -322,6 +322,7 @@
         usedKnobs.features.fullDrawIndexUint32 = VK_TRUE;
         usedKnobs.features.imageCubeArray = VK_TRUE;
         usedKnobs.features.independentBlend = VK_TRUE;
+        usedKnobs.features.sampleRateShading = VK_TRUE;
 
         if (IsRobustnessEnabled()) {
             usedKnobs.features.robustBufferAccess = VK_TRUE;
diff --git a/src/tests/end2end/ShaderTests.cpp b/src/tests/end2end/ShaderTests.cpp
index 5c53bd5..fa427aa 100644
--- a/src/tests/end2end/ShaderTests.cpp
+++ b/src/tests/end2end/ShaderTests.cpp
@@ -366,6 +366,33 @@
     device.CreateRenderPipeline(&rpDesc);
 }
 
+// Test that WGSL built-in variable [[sample_index]] can be used in fragment shaders.
+TEST_P(ShaderTests, SampleIndex) {
+    wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
+[[stage(vertex)]]
+fn main([[location(0)]] pos : vec4<f32>) -> [[builtin(position)]] vec4<f32> {
+    return pos;
+})");
+
+    wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
+[[stage(fragment)]] fn main([[builtin(sample_index)]] sampleIndex : u32)
+    -> [[location(0)]] vec4<f32> {
+    return vec4<f32>(f32(sampleIndex), 1.0, 0.0, 1.0);
+})");
+
+    utils::ComboRenderPipelineDescriptor descriptor;
+    descriptor.vertex.module = vsModule;
+    descriptor.cFragment.module = fsModule;
+    descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
+    descriptor.vertex.bufferCount = 1;
+    descriptor.cBuffers[0].arrayStride = 4 * sizeof(float);
+    descriptor.cBuffers[0].attributeCount = 1;
+    descriptor.cAttributes[0].format = wgpu::VertexFormat::Float32x4;
+    descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
+
+    device.CreateRenderPipeline(&descriptor);
+}
+
 DAWN_INSTANTIATE_TEST(ShaderTests,
                       D3D12Backend(),
                       MetalBackend(),