Consolidate binding information where possible.

This CL consolidates the binding configuration options for the HLSL, MSL
and SPIR-V backends into a common `api/common/bindings.h` file. The
bindings are similar for the three backends. The major differences are:

* `input_attachment` is now available to all backends even though it
  mostly isn't used
* A couple extra HLSL options have been pulled out of bindings and into
  the higher level configuration structure.

Change-Id: I50c15292a86db12e7ea6e9303040f190828f5629
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/263294
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Auto-Submit: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
index 3e73891..d57ba62 100644
--- a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
+++ b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
@@ -117,7 +117,7 @@
 
     const BindingInfoArray& moduleBindingInfo = entryPoint.bindings;
 
-    tint::hlsl::writer::Bindings bindings;
+    tint::Bindings bindings;
 
     for (BindGroupIndex group : layout->GetBindGroupLayoutsMask()) {
         const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
@@ -176,8 +176,7 @@
                     tint::BindingPoint metadata{
                         0u, indices[bgl->GetBindingIndex(bindingExpansion.params)][stage]};
                     bindings.external_texture.emplace(
-                        srcBindingPoint,
-                        tint::hlsl::writer::ExternalTexture{metadata, plane0, plane1});
+                        srcBindingPoint, tint::ExternalTexture{metadata, plane0, plane1});
                 },
 
                 [](const InputAttachmentBindingInfo&) { DAWN_UNREACHABLE(); });
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index a6f1814..e507abd 100644
--- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -169,7 +169,9 @@
     arrayLengthFromUniform.ubo_binding = {layout->GetDynamicStorageBufferLengthsRegisterSpace(),
                                           layout->GetDynamicStorageBufferLengthsShaderRegister()};
 
-    tint::hlsl::writer::Bindings bindings;
+    tint::Bindings bindings;
+    std::vector<BindingPoint> ignored_by_robustness;
+    std::unordered_map<BindingPoint, tint::core::Access> access_controls;
 
     const BindingInfoArray& moduleBindingInfo = entryPoint.bindings;
     for (BindGroupIndex group : layout->GetBindGroupLayoutsMask()) {
@@ -237,8 +239,7 @@
                         bgl->GetShaderRegister(bgl->GetBindingIndex(bindingExpansion.params))};
 
                     bindings.external_texture.emplace(
-                        srcBindingPoint,
-                        tint::hlsl::writer::ExternalTexture{metadata, plane0, plane1});
+                        srcBindingPoint, tint::ExternalTexture{metadata, plane0, plane1});
                 },
 
                 [](const InputAttachmentBindingInfo&) { DAWN_UNREACHABLE(); });
@@ -253,7 +254,7 @@
 
             if (bufferInfo.type == wgpu::BufferBindingType::Storage ||
                 bufferInfo.type == kInternalStorageBufferBinding) {
-                bindings.access_controls.emplace(
+                access_controls.emplace(
                     tint::BindingPoint{.group = uint32_t(group),
                                        .binding = uint32_t(bindingInfo.binding)},
                     tint::core::Access::kReadWrite);
@@ -292,7 +293,7 @@
             if ((bufferInfo.type == wgpu::BufferBindingType::Storage ||
                  bufferInfo.type == wgpu::BufferBindingType::ReadOnlyStorage) &&
                 !bufferInfo.hasDynamicOffset) {
-                bindings.ignored_by_robustness_transform.emplace_back(tint::BindingPoint{
+                ignored_by_robustness.emplace_back(tint::BindingPoint{
                     .group = uint32_t(group), .binding = uint32_t(bindingInfo.binding)});
             }
         }
@@ -317,6 +318,8 @@
     req.hlsl.tintOptions.disable_workgroup_init =
         device->IsToggleEnabled(Toggle::DisableWorkgroupInit);
     req.hlsl.tintOptions.bindings = std::move(bindings);
+    req.hlsl.tintOptions.access_controls = std::move(access_controls);
+    req.hlsl.tintOptions.ignored_by_robustness_transform = std::move(ignored_by_robustness);
 
     req.hlsl.tintOptions.compiler = req.bytecode.compiler == d3d::Compiler::FXC
                                         ? tint::hlsl::writer::Options::Compiler::kFXC
diff --git a/src/dawn/native/metal/ShaderModuleMTL.mm b/src/dawn/native/metal/ShaderModuleMTL.mm
index 7b1604a..5fa5926 100644
--- a/src/dawn/native/metal/ShaderModuleMTL.mm
+++ b/src/dawn/native/metal/ShaderModuleMTL.mm
@@ -127,13 +127,12 @@
 
 namespace {
 
-tint::msl::writer::Bindings GenerateBindingInfo(
-    SingleShaderStage stage,
-    const PipelineLayout* layout,
-    const BindingInfoArray& moduleBindingInfo,
-    tint::msl::writer::ArrayLengthOptions& arrayLengthFromConstants,
-    bool useArgumentBuffers) {
-    tint::msl::writer::Bindings bindings;
+tint::Bindings GenerateBindingInfo(SingleShaderStage stage,
+                                   const PipelineLayout* layout,
+                                   const BindingInfoArray& moduleBindingInfo,
+                                   tint::msl::writer::ArrayLengthOptions& arrayLengthFromConstants,
+                                   bool useArgumentBuffers) {
+    tint::Bindings bindings;
 
     for (BindGroupIndex group : layout->GetBindGroupLayoutsMask()) {
         const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
@@ -217,8 +216,7 @@
                     };
 
                     bindings.external_texture.emplace(
-                        srcBindingPoint,
-                        tint::msl::writer::ExternalTexture{metadata, plane0, plane1});
+                        srcBindingPoint, tint::ExternalTexture{metadata, plane0, plane1});
                 },
                 [](const InputAttachmentBindingInfo&) { DAWN_UNREACHABLE(); });
         }
@@ -294,8 +292,8 @@
 
     bool useArgumentBuffers = device->IsToggleEnabled(Toggle::MetalUseArgumentBuffers);
 
-    tint::msl::writer::Bindings bindings = GenerateBindingInfo(
-        stage, layout, moduleBindingInfo, arrayLengthFromConstants, useArgumentBuffers);
+    tint::Bindings bindings = GenerateBindingInfo(stage, layout, moduleBindingInfo,
+                                                  arrayLengthFromConstants, useArgumentBuffers);
 
     std::unordered_map<uint32_t, tint::msl::writer::ArgumentBufferInfo> argumentBufferInfo =
         GenerateArgumentBufferInfo(stage, layout, moduleBindingInfo, useArgumentBuffers);
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index 1753936..ec42b72 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -143,7 +143,7 @@
 #if TINT_BUILD_SPV_WRITER
     // Creation of module and spirv is deferred to this point when using tint generator
 
-    tint::spirv::writer::Bindings bindings;
+    tint::Bindings bindings;
     std::unordered_set<tint::BindingPoint> statically_paired_texture_binding_points;
 
     const BindingInfoArray& moduleBindingInfo =
@@ -218,8 +218,7 @@
                         static_cast<uint32_t>(bgl->GetBindingIndex(bindingExpansion.params))};
 
                     bindings.external_texture.emplace(
-                        srcBindingPoint,
-                        tint::spirv::writer::ExternalTexture{metadata, plane0, plane1});
+                        srcBindingPoint, tint::ExternalTexture{metadata, plane0, plane1});
                 },
                 [&](const InputAttachmentBindingInfo& bindingInfo) {
                     bindings.input_attachment.emplace(srcBindingPoint, dstBindingPoint);
diff --git a/src/tint/api/common/BUILD.bazel b/src/tint/api/common/BUILD.bazel
index d5e80a5..379cb81 100644
--- a/src/tint/api/common/BUILD.bazel
+++ b/src/tint/api/common/BUILD.bazel
@@ -43,6 +43,7 @@
   ],
   hdrs = [
     "binding_point.h",
+    "bindings.h",
     "override_id.h",
     "resource_binding_config.h",
     "resource_type.h",
diff --git a/src/tint/api/common/BUILD.cmake b/src/tint/api/common/BUILD.cmake
index a813c99..ebe0072 100644
--- a/src/tint/api/common/BUILD.cmake
+++ b/src/tint/api/common/BUILD.cmake
@@ -40,6 +40,7 @@
 ################################################################################
 tint_add_target(tint_api_common lib
   api/common/binding_point.h
+  api/common/bindings.h
   api/common/override_id.h
   api/common/resource_binding_config.h
   api/common/resource_type.h
diff --git a/src/tint/api/common/BUILD.gn b/src/tint/api/common/BUILD.gn
index 2d7c914..f60ecc8 100644
--- a/src/tint/api/common/BUILD.gn
+++ b/src/tint/api/common/BUILD.gn
@@ -46,6 +46,7 @@
 libtint_source_set("common") {
   sources = [
     "binding_point.h",
+    "bindings.h",
     "override_id.h",
     "resource_binding_config.h",
     "resource_type.h",
diff --git a/src/tint/api/common/bindings.h b/src/tint/api/common/bindings.h
new file mode 100644
index 0000000..8972170
--- /dev/null
+++ b/src/tint/api/common/bindings.h
@@ -0,0 +1,90 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_API_COMMON_BINDINGS_H_
+#define SRC_TINT_API_COMMON_BINDINGS_H_
+
+#include <unordered_map>
+
+#include "src/tint/api/common/binding_point.h"
+#include "src/tint/utils/reflection.h"
+
+namespace tint {
+
+/// An external texture
+struct ExternalTexture {
+    /// Metadata
+    BindingPoint metadata{};
+    /// Plane0 binding data
+    BindingPoint plane0{};
+    /// Plane1 binding data
+    BindingPoint plane1{};
+
+    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
+
+    TINT_REFLECT_EQUALS(ExternalTexture);
+    TINT_REFLECT_HASH_CODE(ExternalTexture);
+};
+
+using BindingMap = std::unordered_map<BindingPoint, BindingPoint>;
+using ExternalTextureBindings = std::unordered_map<BindingPoint, ExternalTexture>;
+
+/// Binding information
+struct Bindings {
+    /// Uniform bindings
+    BindingMap uniform{};
+    /// Storage bindings
+    BindingMap storage{};
+    /// Texture bindings
+    BindingMap texture{};
+    /// Storage texture bindings
+    BindingMap storage_texture{};
+    /// Sampler bindings
+    BindingMap sampler{};
+    /// External bindings
+    ExternalTextureBindings external_texture{};
+    /// Input attachment bindings
+    BindingMap input_attachment{};
+
+    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+    TINT_REFLECT(Bindings,
+                 uniform,
+                 storage,
+                 texture,
+                 storage_texture,
+                 sampler,
+                 external_texture,
+                 input_attachment);
+
+    TINT_REFLECT_EQUALS(Bindings);
+    TINT_REFLECT_HASH_CODE(Bindings);
+};
+
+}  // namespace tint
+
+#endif  // SRC_TINT_API_COMMON_BINDINGS_H_
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index 95bbbdd..619c4c3 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -35,61 +35,13 @@
 #include <vector>
 
 #include "src/tint/api/common/binding_point.h"
+#include "src/tint/api/common/bindings.h"
 #include "src/tint/lang/core/enums.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/reflection.h"
 
 namespace tint::hlsl::writer {
 
-/// An external texture
-struct ExternalTexture {
-    /// Metadata
-    BindingPoint metadata{};
-    /// Plane0 binding data
-    BindingPoint plane0{};
-    /// Plane1 binding data;
-    BindingPoint plane1{};
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
-};
-
-using BindingMap = std::unordered_map<BindingPoint, BindingPoint>;
-using ExternalTextureBindings = std::unordered_map<BindingPoint, ExternalTexture>;
-
-/// Binding information
-struct Bindings {
-    /// Uniform bindings
-    BindingMap uniform{};
-    /// Storage bindings
-    BindingMap storage{};
-    /// Texture bindings
-    BindingMap texture{};
-    /// Storage texture bindings
-    BindingMap storage_texture{};
-    /// Sampler bindings
-    BindingMap sampler{};
-    /// External bindings
-    ExternalTextureBindings external_texture{};
-    /// Mapping of BindingPoint to new Access
-    std::unordered_map<BindingPoint, tint::core::Access> access_controls;
-    /// The binding points that will be ignored by the rebustness transform.
-    std::vector<BindingPoint> ignored_by_robustness_transform;
-
-    bool operator==(const Bindings& other) const = default;
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(Bindings,
-                 uniform,
-                 storage,
-                 texture,
-                 storage_texture,
-                 sampler,
-                 external_texture,
-                 access_controls,
-                 ignored_by_robustness_transform);
-};
-
 /// kMaxInterStageLocations == D3D11_PS_INPUT_REGISTER_COUNT - 2
 /// D3D11_PS_INPUT_REGISTER_COUNT == D3D12_PS_INPUT_REGISTER_COUNT
 constexpr uint32_t kMaxInterStageLocations = 30;
@@ -227,6 +179,12 @@
     /// The bindings
     Bindings bindings;
 
+    /// Mapping of BindingPoint to new Access
+    std::unordered_map<BindingPoint, tint::core::Access> access_controls;
+
+    /// The binding points that will be ignored by the rebustness transform.
+    std::vector<BindingPoint> ignored_by_robustness_transform;
+
     /// Pixel local configuration
     PixelLocalOptions pixel_local;
 
@@ -255,6 +213,8 @@
                  first_instance_offset,
                  num_workgroups_start_offset,
                  bindings,
+                 access_controls,
+                 ignored_by_robustness_transform,
                  pixel_local);
 };
 
diff --git a/src/tint/lang/hlsl/writer/raise/raise.cc b/src/tint/lang/hlsl/writer/raise/raise.cc
index 8332bb3..40b7393 100644
--- a/src/tint/lang/hlsl/writer/raise/raise.cc
+++ b/src/tint/lang/hlsl/writer/raise/raise.cc
@@ -122,9 +122,9 @@
 
     if (!options.disable_robustness) {
         core::ir::transform::RobustnessConfig config{};
-        config.bindings_ignored = std::unordered_set<BindingPoint>(
-            options.bindings.ignored_by_robustness_transform.cbegin(),
-            options.bindings.ignored_by_robustness_transform.cend());
+        config.bindings_ignored =
+            std::unordered_set<BindingPoint>(options.ignored_by_robustness_transform.cbegin(),
+                                             options.ignored_by_robustness_transform.cend());
 
         // Direct3D guarantees to return zero for any resource that is accessed out of bounds, and
         // according to the description of the assembly store_uav_typed, out of bounds addressing
diff --git a/src/tint/lang/msl/writer/common/options.h b/src/tint/lang/msl/writer/common/options.h
index 9ba9a91..c1bcd4a 100644
--- a/src/tint/lang/msl/writer/common/options.h
+++ b/src/tint/lang/msl/writer/common/options.h
@@ -33,50 +33,12 @@
 #include <unordered_map>
 
 #include "src/tint/api/common/binding_point.h"
+#include "src/tint/api/common/bindings.h"
 #include "src/tint/api/common/vertex_pulling_config.h"
 #include "src/tint/utils/reflection.h"
 
 namespace tint::msl::writer {
 
-/// An external texture
-struct ExternalTexture {
-    /// Metadata
-    BindingPoint metadata{};
-    /// Plane0 binding data
-    BindingPoint plane0{};
-    /// Plane1 binding data;
-    BindingPoint plane1{};
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
-    TINT_REFLECT_EQUALS(ExternalTexture);
-    TINT_REFLECT_HASH_CODE(ExternalTexture);
-};
-
-using BindingMap = std::unordered_map<BindingPoint, BindingPoint>;
-using ExternalTextureBindings = std::unordered_map<BindingPoint, ExternalTexture>;
-
-/// Binding information
-struct Bindings {
-    /// Uniform bindings
-    BindingMap uniform{};
-    /// Storage bindings
-    BindingMap storage{};
-    /// Texture bindings
-    BindingMap texture{};
-    /// Storage texture bindings
-    BindingMap storage_texture{};
-    /// Sampler bindings
-    BindingMap sampler{};
-    /// External bindings
-    ExternalTextureBindings external_texture{};
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(Bindings, uniform, storage, texture, storage_texture, sampler, external_texture);
-    TINT_REFLECT_EQUALS(Bindings);
-    TINT_REFLECT_HASH_CODE(Bindings);
-};
-
 /// Options used to specify a mapping of binding points to indices into a UBO
 /// from which to load buffer sizes.
 /// TODO(crbug.com/366291600): Remove ubo_binding after switch to immediates.
diff --git a/src/tint/lang/spirv/writer/common/options.h b/src/tint/lang/spirv/writer/common/options.h
index 9f09b85..521faf3 100644
--- a/src/tint/lang/spirv/writer/common/options.h
+++ b/src/tint/lang/spirv/writer/common/options.h
@@ -30,59 +30,15 @@
 
 #include <optional>
 #include <string>
-#include <unordered_map>
 #include <unordered_set>
 
 #include "src/tint/api/common/binding_point.h"
+#include "src/tint/api/common/bindings.h"
 #include "src/tint/api/common/resource_binding_config.h"
 #include "src/tint/utils/reflection.h"
 
 namespace tint::spirv::writer {
 
-/// An external texture
-struct ExternalTexture {
-    /// Metadata
-    BindingPoint metadata{};
-    /// Plane0 binding data
-    BindingPoint plane0{};
-    /// Plane1 binding data
-    BindingPoint plane1{};
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
-};
-
-using BindingMap = std::unordered_map<BindingPoint, BindingPoint>;
-using ExternalTextureBindings = std::unordered_map<BindingPoint, ExternalTexture>;
-
-/// Binding information
-struct Bindings {
-    /// Uniform bindings
-    BindingMap uniform{};
-    /// Storage bindings
-    BindingMap storage{};
-    /// Texture bindings
-    BindingMap texture{};
-    /// Storage texture bindings
-    BindingMap storage_texture{};
-    /// Sampler bindings
-    BindingMap sampler{};
-    /// External bindings
-    ExternalTextureBindings external_texture{};
-    /// Input attachment bindings
-    BindingMap input_attachment{};
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(Bindings,
-                 uniform,
-                 storage,
-                 texture,
-                 storage_texture,
-                 sampler,
-                 external_texture,
-                 input_attachment);
-};
-
 /// Supported SPIR-V binary versions.
 /// If a new version is added here, also add it to:
 /// * Writer::CanGenerate