Use generic Bindings options for GLSL

This CL moves GLSL to use the same `Binding` structure as the other
writers. The extra maps used by GLSL are moved to the higher level
options structure.

Fixed: 447156878
Change-Id: I106a5e926f619fcf9c55a56d4568d5765b1e5b80
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/265554
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/dawn/native/opengl/ShaderModuleGL.cpp b/src/dawn/native/opengl/ShaderModuleGL.cpp
index aca3b80..4e3cd14 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -114,10 +114,11 @@
 // the Tint GLSL writer uses post-remapping BindingPoints.
 void GenerateCombinedSamplerInfo(
     const EntryPointMetadata& metadata,
-    const tint::glsl::writer::Bindings& bindings,
+    const tint::Bindings& bindings,
     const PipelineLayout* layout,
     std::vector<CombinedSampler>* combinedSamplers,
-    tint::glsl::writer::CombinedTextureSamplerInfo* samplerTextureToName) {
+    tint::glsl::writer::CombinedTextureSamplerInfo* samplerTextureToName,
+    tint::BindingPoint* placeholder_sampler_bind_point) {
     // Helper to avoid duplicated logic for when a CombinedSampler is determined. It takes a bunch
     // of information for both the texture and the sampler and translate to what Dawn/Tint need.
     struct CombinedBindingInfo {
@@ -125,8 +126,9 @@
         BindGroupIndex group;
         BindingIndex index;
         BindingIndex shaderArraySize = BindingIndex(1);
+
         // Tint takes the post-remapping binding point.
-        tint::glsl::writer::BindingInfo remappedBinding;
+        tint::BindingPoint remappedBinding;
     };
     auto AddCombinedSampler = [&](CombinedBindingInfo texture,
                                   std::optional<CombinedBindingInfo> sampler,
@@ -150,7 +152,7 @@
         combinedSamplers->push_back(combinedSampler);
 
         // Let Tint know to generate a new GLSL sampler for this combination.
-        tint::BindingPoint samplerRemapped = bindings.placeholder_sampler_bind_point;
+        tint::BindingPoint samplerRemapped = *placeholder_sampler_bind_point;
         if (sampler.has_value()) {
             samplerRemapped = {0, sampler->remappedBinding.binding};
         }
@@ -214,14 +216,16 @@
 void GenerateTextureBuiltinFromUniformData(
     const EntryPointMetadata& metadata,
     const PipelineLayout* layout,
-    const tint::glsl::writer::Bindings& bindings,
+    const tint::Bindings& bindings,
     EmulatedTextureBuiltinRegistrar* emulatedTextureBuiltins,
     tint::glsl::writer::TextureBuiltinsFromUniformOptions* textureBuiltinsFromUniform) {
     // Tell Tint where the uniform containing the builtin data will be (in post-remapping space),
     // only when this shader stage uses some builtin metadata.
     if (!metadata.textureQueries.empty()) {
         textureBuiltinsFromUniform->ubo_binding = {
-            uint32_t(layout->GetInternalTextureBuiltinsUniformBinding())};
+            .group = 0,
+            .binding = uint32_t(layout->GetInternalTextureBuiltinsUniformBinding()),
+        };
     }
 
     for (auto [i, query] : Enumerate(metadata.textureQueries)) {
@@ -246,20 +250,24 @@
         // Tint uses post-remapping binding points for textureBuiltinFromUniform options.
         tint::BindingPoint wgslBindPoint = {.group = query.group, .binding = query.binding};
 
-        tint::glsl::writer::BindingInfo remappedBinding;
+        tint::BindingPoint remappedBinding;
         if (bindings.texture.contains(wgslBindPoint)) {
             remappedBinding = bindings.texture.at(wgslBindPoint);
         } else {
             remappedBinding = bindings.storage_texture.at(wgslBindPoint);
         }
-        textureBuiltinsFromUniform->ubo_contents.push_back(
-            {.offset = offset, .count = 1, .binding = remappedBinding});
+        textureBuiltinsFromUniform->ubo_contents.push_back({
+            .offset = offset,
+            .count = 1,
+            .binding = remappedBinding,
+        });
     }
 }
 
-bool GenerateArrayLengthFromuniformData(const BindingInfoArray& moduleBindingInfo,
-                                        const PipelineLayout* layout,
-                                        tint::glsl::writer::Bindings& bindings) {
+bool GenerateArrayLengthFromuniformData(
+    const BindingInfoArray& moduleBindingInfo,
+    const PipelineLayout* layout,
+    tint::glsl::writer::ArrayLengthFromUniformOptions& options) {
     const PipelineLayout::BindingIndexInfo& indexInfo = layout->GetBindingIndexInfo();
 
     for (BindGroupIndex group : layout->GetBindGroupLayoutsMask()) {
@@ -278,8 +286,7 @@
                     tint::BindingPoint srcBindingPoint = {uint32_t(group),
                                                           uint32_t(bindingInfo.binding)};
                     FlatBindingIndex ssboIndex = indexInfo[group][binding];
-                    bindings.array_length_from_uniform.bindpoint_to_size_index.emplace(
-                        srcBindingPoint, uint32_t(ssboIndex));
+                    options.bindpoint_to_size_index.emplace(srcBindingPoint, uint32_t(ssboIndex));
                     break;
                 }
                 default:
@@ -288,7 +295,7 @@
         }
     }
 
-    return bindings.array_length_from_uniform.bindpoint_to_size_index.size() > 0;
+    return options.bindpoint_to_size_index.size() > 0;
 }
 
 }  // namespace
@@ -339,11 +346,11 @@
                            std::vector<tint::wgsl::Extension> internalExtensions)
     : ShaderModuleBase(device, descriptor, std::move(internalExtensions)) {}
 
-tint::glsl::writer::Bindings GenerateBindingInfo(SingleShaderStage stage,
-                                                 const PipelineLayout* layout,
-                                                 const BindingInfoArray& moduleBindingInfo,
-                                                 GLSLCompilationRequest& req) {
-    tint::glsl::writer::Bindings bindings;
+tint::Bindings GenerateBindingInfo(SingleShaderStage stage,
+                                   const PipelineLayout* layout,
+                                   const BindingInfoArray& moduleBindingInfo,
+                                   GLSLCompilationRequest& req) {
+    tint::Bindings bindings;
 
     for (BindGroupIndex group : layout->GetBindGroupLayoutsMask()) {
         const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
@@ -356,14 +363,16 @@
             };
 
             auto ComputeDestinationBindingPoint = [&](BindingIndex bindingIndex) {
-                return tint::glsl::writer::BindingInfo{
-                    .binding = uint32_t(bindingIndexInfo[bindingIndex])};
+                return tint::BindingPoint{
+                    .group = 0,
+                    .binding = uint32_t(bindingIndexInfo[bindingIndex]),
+                };
             };
 
             MatchVariant(
                 bgl->GetAPIBindingInfo(apiBindingIndex).bindingLayout,
                 [&](const BufferBindingInfo& bindingInfo) {
-                    tint::glsl::writer::BindingInfo dstBindingPoint =
+                    tint::BindingPoint dstBindingPoint =
                         ComputeDestinationBindingPoint(bgl->AsBindingIndex(apiBindingIndex));
                     switch (bindingInfo.type) {
                         case wgpu::BufferBindingType::Uniform:
@@ -408,7 +417,7 @@
                 [&](const ExternalTextureBindingInfo& bindingInfo) {
                     bindings.external_texture.emplace(
                         srcBindingPoint,
-                        tint::glsl::writer::ExternalTexture{
+                        tint::ExternalTexture{
                             .metadata = ComputeDestinationBindingPoint(bindingInfo.metadata),
                             .plane0 = ComputeDestinationBindingPoint(bindingInfo.plane0),
                             .plane1 = ComputeDestinationBindingPoint(bindingInfo.plane1)});
@@ -450,28 +459,26 @@
 
     // When textures are accessed without a sampler (e.g., textureLoad()), returned
     // CombinedSamplerInfo should use this sentinel value as sampler binding point.
-    bindings.placeholder_sampler_bind_point = {static_cast<uint32_t>(kMaxBindGroupsTyped), 0};
+    req.tintOptions.placeholder_sampler_bind_point = {
+        .group = static_cast<uint32_t>(kMaxBindGroupsTyped),
+        .binding = 0,
+    };
 
     // Compute the metadata necessary for translating to GL's combined textures and samplers, both
     // for Dawn and for the Tint translation to GLSL.
     {
         std::vector<CombinedSampler> combinedSamplers;
-        tint::glsl::writer::CombinedTextureSamplerInfo samplerTextureToName;
         GenerateCombinedSamplerInfo(entryPointMetaData, bindings, layout, &combinedSamplers,
-                                    &samplerTextureToName);
-
-        bindings.sampler_texture_to_name = std::move(samplerTextureToName);
+                                    &(req.tintOptions.sampler_texture_to_name),
+                                    &(req.tintOptions.placeholder_sampler_bind_point));
         *combinedSamplersOut = std::move(combinedSamplers);
     }
 
     // Compute the metadata necessary to emulate some of the texture "getter" builtins not present
     // in GLSL, both for Dawn and for the Tint translation to GLSL.
-    {
-        tint::glsl::writer::TextureBuiltinsFromUniformOptions textureBuiltinsFromUniform;
-        GenerateTextureBuiltinFromUniformData(entryPointMetaData, layout, bindings,
-                                              emulatedTextureBuiltins, &textureBuiltinsFromUniform);
-        bindings.texture_builtins_from_uniform = std::move(textureBuiltinsFromUniform);
-    }
+    GenerateTextureBuiltinFromUniformData(entryPointMetaData, layout, bindings,
+                                          emulatedTextureBuiltins,
+                                          &(req.tintOptions.texture_builtins_from_uniform));
 
     req.stage = stage;
     req.entryPointName = programmableStage.entryPoint;
@@ -481,14 +488,20 @@
         LimitsForCompilationRequest::Create(GetDevice()->GetAdapter()->GetLimits().v1));
 
     if (GetDevice()->IsToggleEnabled(Toggle::GLUseArrayLengthFromUniform)) {
-        *needsSSBOLengthUniformBuffer =
-            GenerateArrayLengthFromuniformData(moduleBindingInfo, layout, bindings);
+        *needsSSBOLengthUniformBuffer = GenerateArrayLengthFromuniformData(
+            moduleBindingInfo, layout, req.tintOptions.array_length_from_uniform);
         if (*needsSSBOLengthUniformBuffer) {
             req.tintOptions.use_array_length_from_uniform = true;
-            bindings.array_length_from_uniform.ubo_binding = {kMaxBindGroups + 2, 0};
-            bindings.uniform.emplace(bindings.array_length_from_uniform.ubo_binding,
-                                     tint::glsl::writer::BindingInfo{
-                                         uint32_t(layout->GetInternalArrayLengthUniformBinding())});
+            req.tintOptions.array_length_from_uniform.ubo_binding = {
+                .group = kMaxBindGroups + 2,
+                .binding = 0,
+            };
+            bindings.uniform.emplace(
+                req.tintOptions.array_length_from_uniform.ubo_binding,
+                tint::BindingPoint{
+                    .group = 0,
+                    .binding = uint32_t(layout->GetInternalArrayLengthUniformBinding()),
+                });
         }
     }
 
diff --git a/src/tint/cmd/bench/glsl/BUILD.bazel b/src/tint/cmd/bench/glsl/BUILD.bazel
index 3d0cf28..a22b758 100644
--- a/src/tint/cmd/bench/glsl/BUILD.bazel
+++ b/src/tint/cmd/bench/glsl/BUILD.bazel
@@ -51,7 +51,6 @@
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
-    "//src/tint/lang/wgsl/inspector",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/utils",
diff --git a/src/tint/cmd/bench/glsl/BUILD.cmake b/src/tint/cmd/bench/glsl/BUILD.cmake
index fea9b0a..76ae468 100644
--- a/src/tint/cmd/bench/glsl/BUILD.cmake
+++ b/src/tint/cmd/bench/glsl/BUILD.cmake
@@ -53,7 +53,6 @@
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
-  tint_lang_wgsl_inspector
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
   tint_utils
diff --git a/src/tint/cmd/bench/glsl/BUILD.gn b/src/tint/cmd/bench/glsl/BUILD.gn
index df79aec..5d713ec 100644
--- a/src/tint/cmd/bench/glsl/BUILD.gn
+++ b/src/tint/cmd/bench/glsl/BUILD.gn
@@ -57,7 +57,6 @@
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
         "${tint_src_dir}/lang/wgsl/ast",
-        "${tint_src_dir}/lang/wgsl/inspector",
         "${tint_src_dir}/lang/wgsl/program",
         "${tint_src_dir}/lang/wgsl/sem",
         "${tint_src_dir}/utils",
diff --git a/src/tint/cmd/bench/glsl/writer_bench.cc b/src/tint/cmd/bench/glsl/writer_bench.cc
index 9f63f85..6cc5710 100644
--- a/src/tint/cmd/bench/glsl/writer_bench.cc
+++ b/src/tint/cmd/bench/glsl/writer_bench.cc
@@ -25,15 +25,10 @@
 // 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.
 
-#include <string>
-
 #include "src/tint/cmd/bench/bench.h"
 #include "src/tint/lang/core/ir/transform/single_entry_point.h"
 #include "src/tint/lang/glsl/writer/helpers/generate_bindings.h"
 #include "src/tint/lang/glsl/writer/writer.h"
-#include "src/tint/lang/wgsl/ast/identifier.h"
-#include "src/tint/lang/wgsl/ast/module.h"
-#include "src/tint/lang/wgsl/inspector/inspector.h"
 #include "src/tint/lang/wgsl/reader/reader.h"
 
 namespace tint::glsl::writer {
@@ -55,7 +50,9 @@
             state.SkipWithError(ir.Failure().reason);
             return;
         }
-        gen_options.bindings = tint::glsl::writer::GenerateBindings(ir.Get());
+        auto data = tint::glsl::writer::GenerateBindings(ir.Get());
+        gen_options.bindings = std::move(data.bindings);
+        gen_options.texture_builtins_from_uniform = std::move(data.texture_builtins_from_uniform);
 
         // Get the list of entry point names.
         for (auto func : ir->functions) {
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 54c59bc..b3223bf 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -1253,7 +1253,9 @@
     }
 
     // Generate binding options.
-    gen_options.bindings = tint::glsl::writer::GenerateBindings(ir);
+    auto data = tint::glsl::writer::GenerateBindings(ir);
+    gen_options.bindings = std::move(data.bindings);
+    gen_options.texture_builtins_from_uniform = std::move(data.texture_builtins_from_uniform);
 
     // Check that the module and options are supported by the backend.
     auto check = tint::glsl::writer::CanGenerate(ir, gen_options);
diff --git a/src/tint/lang/glsl/writer/builtin_test.cc b/src/tint/lang/glsl/writer/builtin_test.cc
index 487a8ef..6f67435 100644
--- a/src/tint/lang/glsl/writer/builtin_test.cc
+++ b/src/tint/lang/glsl/writer/builtin_test.cc
@@ -878,9 +878,8 @@
 
     Options opts{};
     opts.bindings.texture[{0, 0}] = {0};
-    opts.bindings.texture_builtins_from_uniform.ubo_binding = {0};
-    opts.bindings.texture_builtins_from_uniform.ubo_contents = {
-        {.offset = 0, .count = 1, .binding = {0}}};
+    opts.texture_builtins_from_uniform.ubo_binding = {.group = 0, .binding = 0};
+    opts.texture_builtins_from_uniform.ubo_contents = {{.offset = 0, .count = 1, .binding = {0}}};
     ASSERT_TRUE(Generate(opts)) << err_ << output_.glsl;
     EXPECT_EQ(output_.glsl, GlslHeader() + R"(precision highp float;
 precision highp int;
diff --git a/src/tint/lang/glsl/writer/common/option_helpers.cc b/src/tint/lang/glsl/writer/common/option_helpers.cc
index bf37890..a26f5aa 100644
--- a/src/tint/lang/glsl/writer/common/option_helpers.cc
+++ b/src/tint/lang/glsl/writer/common/option_helpers.cc
@@ -68,10 +68,10 @@
 Result<SuccessType> ValidateBindingOptions(const Options& options) {
     diag::List diagnostics;
 
-    tint::Hashmap<tint::BindingPoint, BindingInfo, 8> seen_wgsl_bindings{};
-    tint::Hashmap<BindingInfo, tint::BindingPoint, 8> seen_glsl_texture_bindings{};
-    tint::Hashmap<BindingInfo, tint::BindingPoint, 8> seen_glsl_sampler_bindings{};
-    tint::Hashmap<BindingInfo, tint::BindingPoint, 8> seen_glsl_other_bindings{};
+    tint::Hashmap<tint::BindingPoint, BindingPoint, 8> seen_wgsl_bindings{};
+    tint::Hashmap<BindingPoint, tint::BindingPoint, 8> seen_glsl_texture_bindings{};
+    tint::Hashmap<BindingPoint, tint::BindingPoint, 8> seen_glsl_sampler_bindings{};
+    tint::Hashmap<BindingPoint, tint::BindingPoint, 8> seen_glsl_other_bindings{};
     // Both wgsl_seen and glsl_seen check to see if the pair of [src, dst] are unique. If
     // we have multiple entries that map the same [src, dst] pair, that's fine. We treat it as valid
     // as it's possible for multiple entry points to use the remapper at the same time. If the pair
@@ -79,7 +79,7 @@
     // For glsl_seen it is also valid for a texture and a sampler have the same GLSL side binding
     // point.
     auto wgsl_seen = [&diagnostics, &seen_wgsl_bindings](const tint::BindingPoint& src,
-                                                         const BindingInfo& dst) -> bool {
+                                                         const BindingPoint& dst) -> bool {
         if (auto binding = seen_wgsl_bindings.Add(src, dst); binding.value != dst) {
             diagnostics.AddError(Source{}) << "found duplicate WGSL binding point: " << src;
             return true;
@@ -88,12 +88,12 @@
     };
 
     auto glsl_seen = [&diagnostics, &seen_glsl_texture_bindings, &seen_glsl_sampler_bindings,
-                      &seen_glsl_other_bindings](const BindingInfo& src,
+                      &seen_glsl_other_bindings](const BindingPoint& src,
                                                  const tint::BindingPoint& dst,
                                                  BindingType type) -> bool {
         auto disallowed_duplicate =
-            [&diagnostics, &src,
-             &dst](const tint::Hashmap<BindingInfo, tint::BindingPoint, 8>& seen_bindings) -> bool {
+            [&diagnostics, &src, &dst](
+                const tint::Hashmap<BindingPoint, tint::BindingPoint, 8>& seen_bindings) -> bool {
             if (auto binding = seen_bindings.Get(src)) {
                 if (*binding != dst) {
                     diagnostics.AddError(Source{})
@@ -196,7 +196,7 @@
     auto create_remappings = [&remapper_data](const auto& hsh) {
         for (const auto& it : hsh) {
             const BindingPoint& src_binding_point = it.first;
-            const BindingInfo& dst_binding_point = it.second;
+            const BindingPoint& dst_binding_point = it.second;
 
             // Bindings which go to the same slot in GLSL do not need to be re-bound.
             if (src_binding_point.group == 0 &&
@@ -204,7 +204,7 @@
                 continue;
             }
 
-            remapper_data.emplace(src_binding_point, BindingPoint{0, dst_binding_point.binding});
+            remapper_data.emplace(src_binding_point, dst_binding_point);
         }
     };
 
@@ -218,30 +218,25 @@
     for (const auto& it : options.bindings.external_texture) {
         const BindingPoint& src_binding_point = it.first;
 
-        const BindingInfo& plane0 = it.second.plane0;
-        const BindingInfo& plane1 = it.second.plane1;
-        const BindingInfo& metadata = it.second.metadata;
-
-        const BindingPoint plane0_binding_point{0, plane0.binding};
-        const BindingPoint plane1_binding_point{0, plane1.binding};
-        const BindingPoint metadata_binding_point{0, metadata.binding};
+        const BindingPoint& plane0 = it.second.plane0;
+        const BindingPoint& plane1 = it.second.plane1;
+        const BindingPoint& metadata = it.second.metadata;
 
         // Use the re-bound glsl plane0 value for the lookup key.
-        multiplanar_map.emplace(BindingPoint{0, plane0_binding_point.binding},
-                                tint::transform::multiplanar::BindingPoints{
-                                    plane1_binding_point, metadata_binding_point});
+        multiplanar_map.emplace(plane0,
+                                tint::transform::multiplanar::BindingPoints{plane1, metadata});
 
         // Bindings which go to the same slot in GLSL do not need to be re-bound.
-        if (src_binding_point == plane0_binding_point) {
+        if (src_binding_point == plane0) {
             continue;
         }
 
-        remapper_data.emplace(src_binding_point, plane0_binding_point);
+        remapper_data.emplace(src_binding_point, plane0);
     }
 
     // Update the non-plane1 bindings in the combined texture sampler info to be the
     // remapped bindings.
-    for (const auto& it : options.bindings.sampler_texture_to_name) {
+    for (const auto& it : options.sampler_texture_to_name) {
         auto pair = it.first;
         auto name = it.second;
 
diff --git a/src/tint/lang/glsl/writer/common/options.cc b/src/tint/lang/glsl/writer/common/options.cc
index f77edf7..3b0eb9b 100644
--- a/src/tint/lang/glsl/writer/common/options.cc
+++ b/src/tint/lang/glsl/writer/common/options.cc
@@ -29,10 +29,6 @@
 
 namespace tint::glsl::writer {
 
-Bindings::Bindings() = default;
-
-Bindings::~Bindings() = default;
-
 Options::Options() = default;
 
 Options::~Options() = default;
diff --git a/src/tint/lang/glsl/writer/common/options.h b/src/tint/lang/glsl/writer/common/options.h
index 8937116..68ac2e9 100644
--- a/src/tint/lang/glsl/writer/common/options.h
+++ b/src/tint/lang/glsl/writer/common/options.h
@@ -35,41 +35,11 @@
 #include <vector>
 
 #include "src/tint/api/common/binding_point.h"
+#include "src/tint/api/common/bindings.h"
 #include "src/tint/lang/glsl/writer/common/version.h"
 
 namespace tint::glsl::writer {
 
-/// Generic binding point
-struct BindingInfo {
-    /// The binding
-    uint32_t binding = 0;
-
-    /// Equality operator
-    /// @param rhs the BindingInfo to compare against
-    /// @returns true if this BindingInfo is equal to `rhs`
-    inline bool operator==(const BindingInfo& rhs) const { return binding == rhs.binding; }
-    /// Inequality operator
-    /// @param rhs the BindingInfo to compare against
-    /// @returns true if this BindingInfo is not equal to `rhs`
-    inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(BindingInfo, binding);
-};
-
-/// An external texture
-struct ExternalTexture {
-    /// Metadata
-    BindingInfo metadata{};
-    /// Plane0 binding data
-    BindingInfo plane0{};
-    /// Plane1 binding data
-    BindingInfo plane1{};
-
-    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
-};
-
 /// A combined texture/sampler pair
 // Note, these are the WGSL binding points that are used to create the combined samplers
 struct CombinedTextureSamplerPair {
@@ -109,17 +79,6 @@
 
 namespace std {
 
-/// Custom std::hash specialization for tint::glsl::writer::BindingInfo
-template <>
-class hash<tint::glsl::writer::BindingInfo> {
-  public:
-    /// @param n the binding info
-    /// @return the hash value
-    inline std::size_t operator()(const tint::glsl::writer::BindingInfo& n) const {
-        return tint::Hash(n.binding);
-    }
-};
-
 /// Custom std::hash specialization for tint::glsl::writer::CombinedTextureSamplerPair
 template <>
 class hash<tint::glsl::writer::CombinedTextureSamplerPair> {
@@ -135,8 +94,6 @@
 
 namespace tint::glsl::writer {
 
-using BindingMap = std::unordered_map<BindingPoint, BindingInfo>;
-using ExternalTextureBindings = std::unordered_map<BindingPoint, ExternalTexture>;
 using CombinedTextureSamplerInfo = std::unordered_map<CombinedTextureSamplerPair, std::string>;
 
 /// Options used to specify a mapping of binding points to indices into a UBO
@@ -144,14 +101,14 @@
 struct TextureBuiltinsFromUniformOptions {
     /// The binding point to use to generate a uniform buffer from which to read texture builtin
     /// values. Note that this is a post-remapping binding.
-    BindingInfo ubo_binding = {};
+    BindingPoint ubo_binding = {};
 
     /// Ordered list of post-remapping bindings in the uniform buffer for polyfilling
     /// `textureNumSamples` and `textureNumLevels`.
     struct EmulatedBuiltin {
         uint32_t offset;
         uint32_t count;
-        BindingInfo binding;
+        BindingPoint binding;
 
         TINT_REFLECT(EmulatedBuiltin, offset, count, binding);
     };
@@ -174,63 +131,6 @@
     TINT_REFLECT(ArrayLengthFromUniformOptions, ubo_binding, bindpoint_to_size_index);
 };
 
-/// Binding information
-struct Bindings {
-    /// Constructor
-    Bindings();
-    /// Destructor
-    ~Bindings();
-
-    /// Copy constructor
-    Bindings(const Bindings&) = default;
-
-    /// Copy assign
-    Bindings& operator=(const Bindings&) = default;
-
-    /// 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{};
-
-    /// A map of SamplerTexturePair to combined sampler names for the
-    /// CombineSamplers transform
-    CombinedTextureSamplerInfo sampler_texture_to_name;
-
-    /// The binding point to use for placeholder samplers.
-    BindingPoint placeholder_sampler_bind_point;
-
-    /// Options used to map WGSL textureNumLevels/textureNumSamples builtins to internal uniform
-    /// buffer values. If not specified, emits corresponding GLSL builtins
-    /// textureQueryLevels/textureSamples directly.
-    TextureBuiltinsFromUniformOptions texture_builtins_from_uniform = {};
-
-    /// Options used to specify a mapping of binding points to indices into a UBO
-    /// from which to load buffer sizes. If not specified, emits corresponding GLSL builtins
-    /// length() directly
-    ArrayLengthFromUniformOptions array_length_from_uniform = {};
-
-    /// 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,
-                 sampler_texture_to_name,
-                 placeholder_sampler_bind_point,
-                 texture_builtins_from_uniform,
-                 array_length_from_uniform);
-};
-
 /// Configuration options used for generating GLSL.
 struct Options {
     struct RangeOffsets {
@@ -285,6 +185,23 @@
     /// Vertex inputs to perform BGRA swizzle on.
     std::unordered_set<uint32_t> bgra_swizzle_locations;
 
+    /// Options used to map WGSL textureNumLevels/textureNumSamples builtins to internal uniform
+    /// buffer values. If not specified, emits corresponding GLSL builtins
+    /// textureQueryLevels/textureSamples directly.
+    TextureBuiltinsFromUniformOptions texture_builtins_from_uniform = {};
+
+    /// Options used to specify a mapping of binding points to indices into a UBO
+    /// from which to load buffer sizes. If not specified, emits corresponding GLSL builtins
+    /// length() directly
+    ArrayLengthFromUniformOptions array_length_from_uniform = {};
+
+    /// A map of SamplerTexturePair to combined sampler names for the
+    /// CombineSamplers transform
+    CombinedTextureSamplerInfo sampler_texture_to_name;
+
+    /// The binding point to use for placeholder samplers.
+    BindingPoint placeholder_sampler_bind_point;
+
     /// The bindings
     Bindings bindings{};
 
@@ -301,6 +218,10 @@
                  first_instance_offset,
                  depth_range_offsets,
                  bgra_swizzle_locations,
+                 texture_builtins_from_uniform,
+                 array_length_from_uniform,
+                 sampler_texture_to_name,
+                 placeholder_sampler_bind_point,
                  bindings);
 };
 
diff --git a/src/tint/lang/glsl/writer/helpers/generate_bindings.cc b/src/tint/lang/glsl/writer/helpers/generate_bindings.cc
index d575782..2732738 100644
--- a/src/tint/lang/glsl/writer/helpers/generate_bindings.cc
+++ b/src/tint/lang/glsl/writer/helpers/generate_bindings.cc
@@ -27,9 +27,6 @@
 
 #include "src/tint/lang/glsl/writer/helpers/generate_bindings.h"
 
-#include <algorithm>
-#include <unordered_set>
-
 #include "src/tint/api/common/binding_point.h"
 #include "src/tint/lang/core/ir/module.h"
 #include "src/tint/lang/core/ir/var.h"
@@ -42,10 +39,12 @@
 
 namespace tint::glsl::writer {
 
-Bindings GenerateBindings(const core::ir::Module& module) {
-    Bindings bindings{};
-    // Set a next_binding point for the texture-builtins-from-uniform buffer.
-    bindings.texture_builtins_from_uniform.ubo_binding = {0u};
+BindingData GenerateBindings(const core::ir::Module& module) {
+    BindingData data{
+        .bindings = {},
+        .texture_builtins_from_uniform = {.ubo_binding = {.group = 0, .binding = 0u}},
+    };
+
     uint32_t texture_builtin_offset = 0;
 
     // Track the next available GLSL binding number.
@@ -80,7 +79,10 @@
                 continue;
             }
 
-            BindingInfo info{get_binding(bp.value())};
+            BindingPoint info{
+                .group = 0,
+                .binding = get_binding(bp.value()),
+            };
             switch (ptr_type->AddressSpace()) {
                 case core::AddressSpace::kHandle: {
                     // Handle binding_array<handle> before logic dependent on the base handle type.
@@ -95,15 +97,17 @@
 
                     Switch(
                         handle_type,
-                        [&](const core::type::Sampler*) { bindings.sampler.emplace(*bp, info); },
+                        [&](const core::type::Sampler*) {
+                            data.bindings.sampler.emplace(*bp, info);
+                        },
                         [&](const core::type::StorageTexture*) {
-                            bindings.storage_texture.emplace(*bp, info);
+                            data.bindings.storage_texture.emplace(*bp, info);
                         },
                         [&](const core::type::Texture*) {
-                            bindings.texture.emplace(*bp, info);
+                            data.bindings.texture.emplace(*bp, info);
 
                             // Add all texture variables to the texture-builtin-from-uniform map.
-                            bindings.texture_builtins_from_uniform.ubo_contents.push_back(
+                            data.texture_builtins_from_uniform.ubo_contents.push_back(
                                 {.offset = texture_builtin_offset,
                                  .count = count,
                                  .binding = info});
@@ -112,10 +116,10 @@
                     break;
                 }
                 case core::AddressSpace::kStorage:
-                    bindings.storage.emplace(*bp, info);
+                    data.bindings.storage.emplace(*bp, info);
                     break;
                 case core::AddressSpace::kUniform:
-                    bindings.uniform.emplace(*bp, info);
+                    data.bindings.uniform.emplace(*bp, info);
                     break;
 
                 case core::AddressSpace::kUndefined:
@@ -132,14 +136,14 @@
     }
 
     for (auto bp : ext_tex_bps) {
-        BindingInfo plane0{get_binding(bp)};
-        BindingInfo plane1{next_binding++};
-        BindingInfo metadata{next_binding++};
+        BindingPoint plane0{.group = 0, .binding = get_binding(bp)};
+        BindingPoint plane1{.group = 0, .binding = next_binding++};
+        BindingPoint metadata{.group = 0, .binding = next_binding++};
 
-        bindings.external_texture.emplace(bp, ExternalTexture{metadata, plane0, plane1});
+        data.bindings.external_texture.emplace(bp, ExternalTexture{metadata, plane0, plane1});
     }
 
-    return bindings;
+    return data;
 }
 
 }  // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/helpers/generate_bindings.h b/src/tint/lang/glsl/writer/helpers/generate_bindings.h
index ec0b7f6..5704bd9 100644
--- a/src/tint/lang/glsl/writer/helpers/generate_bindings.h
+++ b/src/tint/lang/glsl/writer/helpers/generate_bindings.h
@@ -37,10 +37,15 @@
 
 namespace tint::glsl::writer {
 
+struct BindingData {
+    Bindings bindings;
+    TextureBuiltinsFromUniformOptions texture_builtins_from_uniform;
+};
+
 /// Generate the resource bindings
 /// @param module the module to generate from
 /// @returns the bindings
-Bindings GenerateBindings(const core::ir::Module& module);
+BindingData GenerateBindings(const core::ir::Module& module);
 
 }  // namespace tint::glsl::writer
 
diff --git a/src/tint/lang/glsl/writer/printer/printer.cc b/src/tint/lang/glsl/writer/printer/printer.cc
index 7484288..0ce4042 100644
--- a/src/tint/lang/glsl/writer/printer/printer.cc
+++ b/src/tint/lang/glsl/writer/printer/printer.cc
@@ -806,7 +806,8 @@
         // anything it depends on will emit to the preamble first, and then it copies the text
         // buffer into the preamble.
         TextBuffer str_buf;
-        Line(&str_buf) << "\n" << "struct " << StructName(str) << " {";
+        Line(&str_buf) << "\n"
+                       << "struct " << StructName(str) << " {";
 
         str_buf.IncrementIndent();
 
@@ -1107,8 +1108,8 @@
         if (auto* combined_texture_sampler = var->As<ir::CombinedTextureSamplerVar>()) {
             CombinedTextureSamplerPair key{combined_texture_sampler->TextureBindingPoint(),
                                            combined_texture_sampler->SamplerBindingPoint()};
-            auto itr = options_.bindings.sampler_texture_to_name.find(key);
-            if (itr != options_.bindings.sampler_texture_to_name.end()) {
+            auto itr = options_.sampler_texture_to_name.find(key);
+            if (itr != options_.sampler_texture_to_name.end()) {
                 names_.Add(var->Result(), itr->second);
             }
         }
diff --git a/src/tint/lang/glsl/writer/raise/raise.cc b/src/tint/lang/glsl/writer/raise/raise.cc
index b50f90b..cd8b3a9 100644
--- a/src/tint/lang/glsl/writer/raise/raise.cc
+++ b/src/tint/lang/glsl/writer/raise/raise.cc
@@ -114,8 +114,8 @@
     // _post-remapping_ data.
     if (options.use_array_length_from_uniform) {
         RUN_TRANSFORM(core::ir::transform::ArrayLengthFromUniform, module,
-                      options.bindings.array_length_from_uniform.ubo_binding,
-                      options.bindings.array_length_from_uniform.bindpoint_to_size_index);
+                      options.array_length_from_uniform.ubo_binding,
+                      options.array_length_from_uniform.bindpoint_to_size_index);
     }
 
     tint::transform::multiplanar::BindingsMap multiplanar_map{};
@@ -175,8 +175,7 @@
     // Note, this must come after remapping as it uses post-remapping indices for its options.
     // Note, this must come after DirectVariableAccess as it doesn't handle tracing through function
     // calls.
-    RUN_TRANSFORM(raise::TextureBuiltinsFromUniform, module,
-                  options.bindings.texture_builtins_from_uniform);
+    RUN_TRANSFORM(raise::TextureBuiltinsFromUniform, module, options.texture_builtins_from_uniform);
 
     if (!options.disable_workgroup_init) {
         RUN_TRANSFORM(core::ir::transform::ZeroInitWorkgroupMemory, module);
@@ -192,7 +191,7 @@
     {
         // Must come after DirectVariableAccess
         raise::TexturePolyfillConfig tex_config;
-        tex_config.placeholder_sampler_bind_point = options.bindings.placeholder_sampler_bind_point;
+        tex_config.placeholder_sampler_bind_point = options.placeholder_sampler_bind_point;
         RUN_TRANSFORM(raise::TexturePolyfill, module, tex_config);
     }
 
diff --git a/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform.cc b/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform.cc
index c1ae06d..9814a93 100644
--- a/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform.cc
+++ b/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform.cc
@@ -58,7 +58,7 @@
     core::ir::Var* texture_uniform_data_ = nullptr;
 
     /// Map from binding point to index into uniform structure
-    Hashmap<BindingInfo, uint32_t, 2> binding_point_to_uniform_offset_{};
+    Hashmap<BindingPoint, uint32_t, 2> binding_point_to_uniform_offset_{};
 
     /// Process the module.
     void Process() {
@@ -152,7 +152,10 @@
     core::ir::Value* GetAccessFromUniform(core::ir::Value* arg) {
         auto path = PathForTexture(arg);
 
-        BindingInfo binding = {path.var->BindingPoint()->binding};
+        BindingPoint binding = {
+            .group = 0,
+            .binding = path.var->BindingPoint()->binding,
+        };
         uint32_t metadata_offset = *binding_point_to_uniform_offset_.Get(binding);
 
         // Returns the u32 at `metadata_offset` + `path.index` (if present) in
diff --git a/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform_test.cc b/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform_test.cc
index c67b370..560232d 100644
--- a/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform_test.cc
+++ b/src/tint/lang/glsl/writer/raise/texture_builtins_from_uniform_test.cc
@@ -101,7 +101,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 0, .count = 1, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 0, .count = 1, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
@@ -158,7 +160,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 0, .count = 1, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 0, .count = 1, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
@@ -215,7 +219,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 42, .count = 1, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 42, .count = 1, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
@@ -277,7 +283,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 0, .count = 3, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 0, .count = 3, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
@@ -340,7 +348,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 0, .count = 3, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 0, .count = 3, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
@@ -405,7 +415,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 0, .count = 3, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 0, .count = 3, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
@@ -471,7 +483,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 0, .count = 1, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 0, .count = 1, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
@@ -537,7 +551,9 @@
 }
 )";
 
-    TextureBuiltinsFromUniformOptions cfg = {{30u}, {{.offset = 0, .count = 1, .binding = {0}}}};
+    TextureBuiltinsFromUniformOptions cfg = {
+        {.group = 0, .binding = 30u},
+        {{.offset = 0, .count = 1, .binding = {.group = 0, .binding = 0}}}};
     Run(TextureBuiltinsFromUniform, cfg);
     EXPECT_EQ(expect, str());
 }
diff --git a/src/tint/lang/glsl/writer/writer.cc b/src/tint/lang/glsl/writer/writer.cc
index f85e94e..45f43d6 100644
--- a/src/tint/lang/glsl/writer/writer.cc
+++ b/src/tint/lang/glsl/writer/writer.cc
@@ -93,7 +93,7 @@
                 !handle_type->IsAnyOf<core::type::StorageTexture, core::type::ExternalTexture>()) {
                 bool found = false;
                 auto binding = options.bindings.texture.at(var->BindingPoint().value());
-                for (auto& bp : options.bindings.texture_builtins_from_uniform.ubo_contents) {
+                for (auto& bp : options.texture_builtins_from_uniform.ubo_contents) {
                     if (bp.binding == binding) {
                         if (bp.count < count) {
                             return Failure(
diff --git a/src/tint/lang/glsl/writer/writer_fuzz.cc b/src/tint/lang/glsl/writer/writer_fuzz.cc
index 814c652..e4f3004 100644
--- a/src/tint/lang/glsl/writer/writer_fuzz.cc
+++ b/src/tint/lang/glsl/writer/writer_fuzz.cc
@@ -46,7 +46,10 @@
     options.disable_robustness = false;
     options.disable_workgroup_init = false;
     options.disable_polyfill_integer_div_mod = false;
-    options.bindings = GenerateBindings(module);
+
+    auto data = GenerateBindings(module);
+    options.bindings = std::move(data.bindings);
+    options.texture_builtins_from_uniform = std::move(data.texture_builtins_from_uniform);
 
     // Leave some room for user-declared immediate data.
     uint32_t next_immediate_offset = 0x800;
diff --git a/src/tint/lang/glsl/writer/writer_test.cc b/src/tint/lang/glsl/writer/writer_test.cc
index f126f74..f9e5f33 100644
--- a/src/tint/lang/glsl/writer/writer_test.cc
+++ b/src/tint/lang/glsl/writer/writer_test.cc
@@ -109,7 +109,7 @@
 
     Options options;
     options.strip_all_names = true;
-    options.bindings.sampler_texture_to_name.insert(
+    options.sampler_texture_to_name.insert(
         {CombinedTextureSamplerPair{texture_bp, sampler_bp}, "tint_combined_texture_sampler"});
     ASSERT_TRUE(Generate(options)) << err_ << output_.glsl;
     EXPECT_EQ(output_.glsl, GlslHeader() + R"(precision highp float;