[dawn][vulkan] Handle ResourceTableConfig when compiling to SPIR-V

Bug: 463925499
Change-Id: I27d98d0fb47df5ee641f81e8d3c754063d06def3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/279895
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index b248b89..40ce1f6 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -132,10 +132,27 @@
 #if TINT_BUILD_SPV_WRITER
     // Creation of module and spirv is deferred to this point when using tint generator
 
+    // The first VkDescriptorSetLayout is the one for the resource table if needed and pushes the
+    // bindings for all other bindgroups by 1.
+    BindGroupIndex startOfBindGroups{0};
+    std::optional<tint::ResourceTableConfig> resourceTableConfig = std::nullopt;
+    if (layout->UsesResourceTable()) {
+        startOfBindGroups = BindGroupIndex(1);
+
+        // TODO(https://issues.chromium.org/435317394): Update to not pass a DynamicBindingKind once
+        // support for dynamic binding arrays is removed.
+        auto bindingTypeOrder = GetDefaultBindingOrder(wgpu::DynamicBindingKind::SampledTexture);
+        resourceTableConfig = tint::ResourceTableConfig{
+            .resource_table_binding = tint::BindingPoint(0, 1),
+            .storage_buffer_binding = tint::BindingPoint(0, 0),
+            .default_binding_type_order = {bindingTypeOrder.begin(), bindingTypeOrder.end()},
+        };
+    }
+
     tint::Bindings bindings =
         GenerateBindingRemapping(layout, stage, [&](BindGroupIndex group, BindingIndex index) {
             return tint::BindingPoint{
-                .group = uint32_t(group),
+                .group = uint32_t(startOfBindGroups + group),
                 .binding = uint32_t(index),
             };
         });
@@ -150,7 +167,7 @@
             const auto& bindingInfo = bgl->GetBindingInfo(index);
 
             if (auto samplerIndex = bgl->GetStaticSamplerIndexForTexture(index)) {
-                tint::BindingPoint wgslBindingPoint = {.group = uint32_t(group),
+                tint::BindingPoint wgslBindingPoint = {.group = uint32_t(startOfBindGroups + group),
                                                        .binding = uint32_t(bindingInfo.binding)};
                 bindings.texture[wgslBindingPoint].binding = uint32_t(samplerIndex.value());
                 staticallyPairedTextureBindingPoints.insert(wgslBindingPoint);
@@ -167,6 +184,7 @@
         if (!bgl->HasDynamicArray()) {
             continue;
         }
+        DAWN_ASSERT(startOfBindGroups == BindGroupIndex(0));
 
         tint::BindingPoint wgslDynamicArrayBindPoint = {
             .group = uint32_t(group), .binding = uint32_t(bgl->GetAPIDynamicArrayStart())};
@@ -217,6 +235,7 @@
     };
     req.tintOptions.bindings = std::move(bindings);
     req.tintOptions.resource_binding = std::move(resourceBindingConfig);
+    req.tintOptions.resource_table = std::move(resourceTableConfig);
 
     req.tintOptions.workarounds.polyfill_unary_f32_negation =
         GetDevice()->IsToggleEnabled(Toggle::VulkanPolyfillF32Negation);
diff --git a/src/dawn/tests/end2end/ResourceTableTests.cpp b/src/dawn/tests/end2end/ResourceTableTests.cpp
index b6f4f95..18af22f 100644
--- a/src/dawn/tests/end2end/ResourceTableTests.cpp
+++ b/src/dawn/tests/end2end/ResourceTableTests.cpp
@@ -106,6 +106,46 @@
     MakePipelineLayoutWithTable({testBgl, testBgl, testBgl}, 4);
 }
 
+// Test that creating pipelines that use resource tables doesn't crash in backends.
+TEST_P(ResourceTableTests, ShaderWithResourceTableCreation) {
+    wgpu::ComputePipelineDescriptor csDesc;
+
+    // Test compiling a pipeline using only the resource table.
+    csDesc.compute.module = utils::CreateShaderModule(device, R"(
+        enable chromium_experimental_resource_table;
+        @compute @workgroup_size(1) fn main() {
+            _ = hasResource<texture_2d<f32>>(0);
+        }
+    )");
+    device.CreateComputePipeline(&csDesc);
+
+    // Test compiling a pipeline using the resource table and a bindgroup.
+    csDesc.compute.module = utils::CreateShaderModule(device, R"(
+        enable chromium_experimental_resource_table;
+        @group(0) @binding(0) var t0 : texture_2d<f32>;
+        @compute @workgroup_size(1) fn main() {
+            _ = hasResource<texture_2d<f32>>(0);
+            _ = t0;
+        }
+    )");
+    device.CreateComputePipeline(&csDesc);
+
+    // Test compiling a pipeline using the resource table and many bindgroup.
+    csDesc.compute.module = utils::CreateShaderModule(device, R"(
+        enable chromium_experimental_resource_table;
+        @group(0) @binding(0) var t0 : texture_2d<f32>;
+        @group(1) @binding(0) var t1 : texture_2d<f32>;
+        @group(2) @binding(0) var t2 : texture_2d<f32>;
+        @compute @workgroup_size(1) fn main() {
+            _ = hasResource<texture_2d<f32>>(0);
+            _ = t0;
+            _ = t1;
+            _ = t2;
+        }
+    )");
+    device.CreateComputePipeline(&csDesc);
+}
+
 DAWN_INSTANTIATE_TEST(ResourceTableTests, D3D12Backend(), MetalBackend(), VulkanBackend());
 
 }  // anonymous namespace