[glsl] Cleanup CombineSamplers data

This CL moves the options for the `CombineSamplers` transform out of the
generic `Options` struct for GLSL and into a
`CombinedTextuerSamplerInfo` structure. This makes it clearer which
options are specifically for the given transform.

Bug: 340582170
Change-Id: Id27ae61e520cdfcdee8c66721088368e300a3627
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/188301
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 5801211..b2d3aef 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -71,15 +71,16 @@
 using BindingMap = std::unordered_map<tint::BindingPoint, tint::BindingPoint>;
 
 opengl::CombinedSampler* AppendCombinedSampler(opengl::CombinedSamplerInfo* info,
-                                               tint::inspector::SamplerTexturePair pair,
+                                               tint::BindingPoint texture,
+                                               tint::BindingPoint sampler,
                                                tint::BindingPoint placeholderBindingPoint) {
     info->emplace_back();
     opengl::CombinedSampler* combinedSampler = &info->back();
-    combinedSampler->usePlaceholderSampler = pair.sampler_binding_point == placeholderBindingPoint;
-    combinedSampler->samplerLocation.group = BindGroupIndex(pair.sampler_binding_point.group);
-    combinedSampler->samplerLocation.binding = BindingNumber(pair.sampler_binding_point.binding);
-    combinedSampler->textureLocation.group = BindGroupIndex(pair.texture_binding_point.group);
-    combinedSampler->textureLocation.binding = BindingNumber(pair.texture_binding_point.binding);
+    combinedSampler->usePlaceholderSampler = sampler == placeholderBindingPoint;
+    combinedSampler->samplerLocation.group = BindGroupIndex(sampler.group);
+    combinedSampler->samplerLocation.binding = BindingNumber(sampler.binding);
+    combinedSampler->textureLocation.group = BindGroupIndex(texture.group);
+    combinedSampler->textureLocation.binding = BindingNumber(texture.binding);
     return combinedSampler;
 }
 
@@ -334,24 +335,34 @@
     CombinedSamplerInfo combinedSamplerInfo;
     for (const auto& use : uses) {
         CombinedSampler* info =
-            AppendCombinedSampler(&combinedSamplerInfo, use, placeholderBindingPoint);
+            AppendCombinedSampler(&combinedSamplerInfo, use.texture_binding_point,
+                                  use.sampler_binding_point, placeholderBindingPoint);
 
         if (info->usePlaceholderSampler) {
             *needsPlaceholderSampler = true;
-            req.tintOptions.placeholder_binding_point = placeholderBindingPoint;
+            req.tintOptions.combined_samplers_info.placeholder_sampler_binding =
+                placeholderBindingPoint;
         }
-        req.tintOptions.binding_map[use] = info->GetName();
+
+        tint::glsl::writer::binding::CombinedTextureSamplerPair pair;
+        pair.texture = use.texture_binding_point;
+        pair.sampler = use.sampler_binding_point;
+
+        req.tintOptions.combined_samplers_info.sampler_texture_to_name[pair] = info->GetName();
 
         // If the texture has an associated plane1 texture (ie., it's an external texture),
         // append a new combined sampler with the same sampler and the plane1 texture.
         BindingMap::iterator plane1Texture =
             externalTextureExpansionMap.find(use.texture_binding_point);
         if (plane1Texture != externalTextureExpansionMap.end()) {
-            tint::inspector::SamplerTexturePair plane1Use{use.sampler_binding_point,
-                                                          plane1Texture->second};
+            tint::glsl::writer::binding::CombinedTextureSamplerPair plane1Use{
+                plane1Texture->second, use.sampler_binding_point};
+
             CombinedSampler* plane1Info =
-                AppendCombinedSampler(&combinedSamplerInfo, plane1Use, placeholderBindingPoint);
-            req.tintOptions.binding_map[plane1Use] = plane1Info->GetName();
+                AppendCombinedSampler(&combinedSamplerInfo, plane1Use.texture, plane1Use.sampler,
+                                      placeholderBindingPoint);
+            req.tintOptions.combined_samplers_info.sampler_texture_to_name[plane1Use] =
+                plane1Info->GetName();
         }
     }
 
diff --git a/src/tint/api/BUILD.bazel b/src/tint/api/BUILD.bazel
index 9f218bd..c830679 100644
--- a/src/tint/api/BUILD.bazel
+++ b/src/tint/api/BUILD.bazel
@@ -54,6 +54,7 @@
     "//src/tint/lang/hlsl/writer/common",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/ast/transform",
     "//src/tint/lang/wgsl/common",
     "//src/tint/lang/wgsl/features",
     "//src/tint/lang/wgsl/program",
diff --git a/src/tint/api/BUILD.cmake b/src/tint/api/BUILD.cmake
index 9551324..8f269d5 100644
--- a/src/tint/api/BUILD.cmake
+++ b/src/tint/api/BUILD.cmake
@@ -56,6 +56,7 @@
   tint_lang_hlsl_writer_common
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
   tint_lang_wgsl_common
   tint_lang_wgsl_features
   tint_lang_wgsl_program
diff --git a/src/tint/api/BUILD.gn b/src/tint/api/BUILD.gn
index 80382c0..6cd4598 100644
--- a/src/tint/api/BUILD.gn
+++ b/src/tint/api/BUILD.gn
@@ -53,6 +53,7 @@
     "${tint_src_dir}/lang/hlsl/writer/common",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
+    "${tint_src_dir}/lang/wgsl/ast/transform",
     "${tint_src_dir}/lang/wgsl/common",
     "${tint_src_dir}/lang/wgsl/features",
     "${tint_src_dir}/lang/wgsl/program",
diff --git a/src/tint/cmd/loopy/BUILD.bazel b/src/tint/cmd/loopy/BUILD.bazel
index 9a2c3ad..a218fad 100644
--- a/src/tint/cmd/loopy/BUILD.bazel
+++ b/src/tint/cmd/loopy/BUILD.bazel
@@ -54,6 +54,7 @@
     "//src/tint/lang/hlsl/writer/helpers",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/ast/transform",
     "//src/tint/lang/wgsl/common",
     "//src/tint/lang/wgsl/features",
     "//src/tint/lang/wgsl/helpers",
diff --git a/src/tint/cmd/loopy/BUILD.cmake b/src/tint/cmd/loopy/BUILD.cmake
index ad75e1a..bfa2a27 100644
--- a/src/tint/cmd/loopy/BUILD.cmake
+++ b/src/tint/cmd/loopy/BUILD.cmake
@@ -55,6 +55,7 @@
   tint_lang_hlsl_writer_helpers
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
   tint_lang_wgsl_common
   tint_lang_wgsl_features
   tint_lang_wgsl_helpers
diff --git a/src/tint/cmd/loopy/BUILD.gn b/src/tint/cmd/loopy/BUILD.gn
index f578df9..4f67f81 100644
--- a/src/tint/cmd/loopy/BUILD.gn
+++ b/src/tint/cmd/loopy/BUILD.gn
@@ -54,6 +54,7 @@
     "${tint_src_dir}/lang/hlsl/writer/helpers",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
+    "${tint_src_dir}/lang/wgsl/ast/transform",
     "${tint_src_dir}/lang/wgsl/common",
     "${tint_src_dir}/lang/wgsl/features",
     "${tint_src_dir}/lang/wgsl/helpers",
diff --git a/src/tint/lang/glsl/writer/BUILD.bazel b/src/tint/lang/glsl/writer/BUILD.bazel
index 0d24e42..8ecd6b7 100644
--- a/src/tint/lang/glsl/writer/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/BUILD.bazel
@@ -55,6 +55,7 @@
     "//src/tint/lang/glsl/writer/raise",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/ast/transform",
     "//src/tint/lang/wgsl/features",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
@@ -98,6 +99,7 @@
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/ast/transform",
     "//src/tint/lang/wgsl/features",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/glsl/writer/BUILD.cmake b/src/tint/lang/glsl/writer/BUILD.cmake
index 35e7e21..6939a35 100644
--- a/src/tint/lang/glsl/writer/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/BUILD.cmake
@@ -62,6 +62,7 @@
   tint_lang_glsl_writer_raise
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
   tint_lang_wgsl_features
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
@@ -109,6 +110,7 @@
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
   tint_lang_wgsl_features
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
@@ -156,6 +158,7 @@
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
   tint_lang_wgsl_features
   tint_lang_wgsl_inspector
   tint_lang_wgsl_program
diff --git a/src/tint/lang/glsl/writer/BUILD.gn b/src/tint/lang/glsl/writer/BUILD.gn
index 2f908e4..4b6b514 100644
--- a/src/tint/lang/glsl/writer/BUILD.gn
+++ b/src/tint/lang/glsl/writer/BUILD.gn
@@ -58,6 +58,7 @@
       "${tint_src_dir}/lang/glsl/writer/raise",
       "${tint_src_dir}/lang/wgsl",
       "${tint_src_dir}/lang/wgsl/ast",
+      "${tint_src_dir}/lang/wgsl/ast/transform",
       "${tint_src_dir}/lang/wgsl/features",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/sem",
@@ -100,6 +101,7 @@
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
         "${tint_src_dir}/lang/wgsl/ast",
+        "${tint_src_dir}/lang/wgsl/ast/transform",
         "${tint_src_dir}/lang/wgsl/features",
         "${tint_src_dir}/lang/wgsl/program",
         "${tint_src_dir}/lang/wgsl/sem",
@@ -138,6 +140,7 @@
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/wgsl",
       "${tint_src_dir}/lang/wgsl/ast",
+      "${tint_src_dir}/lang/wgsl/ast/transform",
       "${tint_src_dir}/lang/wgsl/features",
       "${tint_src_dir}/lang/wgsl/inspector",
       "${tint_src_dir}/lang/wgsl/program",
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index f03e863..4046eb6 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -234,7 +234,7 @@
         options.texture_builtins_from_uniform.ubo_binding,
         options.texture_builtins_from_uniform.ubo_bindingpoint_ordering);
 
-    data.Add<CombineSamplers::BindingInfo>(options.binding_map, options.placeholder_binding_point);
+    data.Add<CombineSamplersInfo>(options.combined_samplers_info);
     manager.Add<CombineSamplers>();
 
     data.Add<ast::transform::BindingRemapper::Remappings>(
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel b/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
index c23fd29..49e220f 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
@@ -52,6 +52,7 @@
   ],
   deps = [
     "//src/tint/api/common",
+    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
@@ -76,7 +77,12 @@
     "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
-  ],
+  ] + select({
+    ":tint_build_glsl_writer": [
+      "//src/tint/lang/glsl/writer/common",
+    ],
+    "//conditions:default": [],
+  }),
   copts = COPTS,
   visibility = ["//visibility:public"],
 )
@@ -91,6 +97,7 @@
   ],
   deps = [
     "//src/tint/api/common",
+    "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/ir",
@@ -120,6 +127,7 @@
   ] + select({
     ":tint_build_glsl_writer": [
       "//src/tint/lang/glsl/writer/ast_raise",
+      "//src/tint/lang/glsl/writer/common",
     ],
     "//conditions:default": [],
   }) + select({
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake b/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
index 1a658c0..ab41d85 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
@@ -53,6 +53,7 @@
 
 tint_target_add_dependencies(tint_lang_glsl_writer_ast_raise lib
   tint_api_common
+  tint_api_options
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
@@ -79,6 +80,12 @@
   tint_utils_traits
 )
 
+if(TINT_BUILD_GLSL_WRITER)
+  tint_target_add_dependencies(tint_lang_glsl_writer_ast_raise lib
+    tint_lang_glsl_writer_common
+  )
+endif(TINT_BUILD_GLSL_WRITER)
+
 endif(TINT_BUILD_GLSL_WRITER)
 if(TINT_BUILD_GLSL_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
 ################################################################################
@@ -95,6 +102,7 @@
 
 tint_target_add_dependencies(tint_lang_glsl_writer_ast_raise_test test
   tint_api_common
+  tint_api_options
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_ir
@@ -129,6 +137,7 @@
 if(TINT_BUILD_GLSL_WRITER)
   tint_target_add_dependencies(tint_lang_glsl_writer_ast_raise_test test
     tint_lang_glsl_writer_ast_raise
+    tint_lang_glsl_writer_common
   )
 endif(TINT_BUILD_GLSL_WRITER)
 
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
index 166a313..75216fd 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
@@ -55,6 +55,7 @@
     ]
     deps = [
       "${tint_src_dir}/api/common",
+      "${tint_src_dir}/api/options",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
       "${tint_src_dir}/lang/core/type",
@@ -80,6 +81,10 @@
       "${tint_src_dir}/utils/text",
       "${tint_src_dir}/utils/traits",
     ]
+
+    if (tint_build_glsl_writer) {
+      deps += [ "${tint_src_dir}/lang/glsl/writer/common" ]
+    }
   }
 }
 if (tint_build_unittests) {
@@ -95,6 +100,7 @@
       deps = [
         "${tint_src_dir}:gmock_and_gtest",
         "${tint_src_dir}/api/common",
+        "${tint_src_dir}/api/options",
         "${tint_src_dir}/lang/core",
         "${tint_src_dir}/lang/core/constant",
         "${tint_src_dir}/lang/core/ir",
@@ -123,7 +129,10 @@
       ]
 
       if (tint_build_glsl_writer) {
-        deps += [ "${tint_src_dir}/lang/glsl/writer/ast_raise" ]
+        deps += [
+          "${tint_src_dir}/lang/glsl/writer/ast_raise",
+          "${tint_src_dir}/lang/glsl/writer/common",
+        ]
       }
 
       if (tint_build_wgsl_reader) {
diff --git a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
index fcaef5e..66f5236 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
@@ -32,6 +32,7 @@
 #include <utility>
 #include <vector>
 
+#include "src/tint/lang/glsl/writer/common/options.h"
 #include "src/tint/lang/wgsl/program/clone_context.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
@@ -41,7 +42,7 @@
 #include "src/tint/utils/containers/map.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::glsl::writer::CombineSamplers);
-TINT_INSTANTIATE_TYPEINFO(tint::glsl::writer::CombineSamplers::BindingInfo);
+TINT_INSTANTIATE_TYPEINFO(tint::glsl::writer::CombineSamplersInfo);
 
 namespace {
 
@@ -55,11 +56,13 @@
 namespace tint::glsl::writer {
 
 using namespace tint::core::number_suffixes;  // NOLINT
+                                              //
+CombineSamplersInfo::CombineSamplersInfo() = default;
 
-CombineSamplers::BindingInfo::BindingInfo(const BindingMap& map, const BindingPoint& placeholder)
-    : binding_map(map), placeholder_binding_point(placeholder) {}
-CombineSamplers::BindingInfo::BindingInfo(const BindingInfo& other) = default;
-CombineSamplers::BindingInfo::~BindingInfo() = default;
+CombineSamplersInfo::CombineSamplersInfo(CombinedTextureSamplerInfo map, BindingPoint placeholder)
+    : sampler_texture_to_name(std::move(map)), placeholder_sampler_binding(placeholder) {}
+
+CombineSamplersInfo::~CombineSamplersInfo() = default;
 
 /// PIMPL state for the transform
 struct CombineSamplers::State {
@@ -70,8 +73,8 @@
     /// The clone context
     program::CloneContext ctx = {&b, &src, /* auto_clone_symbols */ true};
 
-    /// The binding info
-    const BindingInfo* binding_info;
+    /// The combined sampler information
+    const CombineSamplersInfo* combined_samplers_info;
 
     /// Map from a texture/sampler pair to the corresponding combined sampler
     /// variable
@@ -104,7 +107,8 @@
     /// Constructor
     /// @param program the source program
     /// @param info the binding map information
-    State(const Program& program, const BindingInfo* info) : src(program), binding_info(info) {}
+    State(const Program& program, const CombineSamplersInfo* info)
+        : src(program), combined_samplers_info(info) {}
 
     /// Creates a combined sampler global variables.
     /// (Note this is actually a Texture node at the AST level, but it will be
@@ -116,15 +120,15 @@
     const ast::Variable* CreateCombinedGlobal(const sem::Variable* texture_var,
                                               const sem::Variable* sampler_var,
                                               std::string name) {
-        SamplerTexturePair bp_pair;
-        bp_pair.texture_binding_point =
-            texture_var ? *texture_var->As<sem::GlobalVariable>()->Attributes().binding_point
-                        : binding_info->placeholder_binding_point;
-        bp_pair.sampler_binding_point =
-            sampler_var ? *sampler_var->As<sem::GlobalVariable>()->Attributes().binding_point
-                        : binding_info->placeholder_binding_point;
-        auto it = binding_info->binding_map.find(bp_pair);
-        if (it != binding_info->binding_map.end()) {
+        binding::CombinedTextureSamplerPair st_pair;
+        st_pair.texture = texture_var
+                              ? *texture_var->As<sem::GlobalVariable>()->Attributes().binding_point
+                              : combined_samplers_info->placeholder_sampler_binding;
+        st_pair.sampler = sampler_var
+                              ? *sampler_var->As<sem::GlobalVariable>()->Attributes().binding_point
+                              : combined_samplers_info->placeholder_sampler_binding;
+        auto it = combined_samplers_info->sampler_texture_to_name.find(st_pair);
+        if (it != combined_samplers_info->sampler_texture_to_name.end()) {
             name = it->second;
         }
         ast::Type type = CreateCombinedASTTypeFor(texture_var, sampler_var);
@@ -438,14 +442,14 @@
 ast::transform::Transform::ApplyResult CombineSamplers::Apply(const Program& src,
                                                               const ast::transform::DataMap& inputs,
                                                               ast::transform::DataMap&) const {
-    auto* binding_info = inputs.Get<BindingInfo>();
-    if (!binding_info) {
+    auto* info = inputs.Get<CombineSamplersInfo>();
+    if (!info) {
         ProgramBuilder b;
         b.Diagnostics().AddError(Source{}) << "missing transform data for " << TypeInfo().name;
         return resolver::Resolve(b);
     }
 
-    return State(src, binding_info).Run();
+    return State(src, info).Run();
 }
 
 }  // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.h b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.h
index 5f1c976..24b5354 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.h
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.h
@@ -32,7 +32,6 @@
 #include <unordered_map>
 
 #include "src/tint/lang/wgsl/ast/transform/transform.h"
-#include "src/tint/lang/wgsl/sem/sampler_texture_pair.h"
 
 namespace tint::glsl::writer {
 
@@ -67,34 +66,6 @@
 /// (Tint) Textures as (GLSL) Samplers.
 class CombineSamplers final : public Castable<CombineSamplers, ast::transform::Transform> {
   public:
-    /// A pair of binding points.
-    using SamplerTexturePair = sem::SamplerTexturePair;
-
-    /// A map from a sampler/texture pair to a named global.
-    using BindingMap = std::unordered_map<SamplerTexturePair, std::string>;
-
-    /// The client-provided mapping from separate texture and sampler binding
-    /// points to combined sampler binding point.
-    struct BindingInfo final : public Castable<BindingInfo, ast::transform::Data> {
-        /// Constructor
-        /// @param map the map of all (texture, sampler) -> (combined) pairs
-        /// @param placeholder the binding point to use for placeholder samplers.
-        BindingInfo(const BindingMap& map, const BindingPoint& placeholder);
-
-        /// Copy constructor
-        /// @param other the other BindingInfo to copy
-        BindingInfo(const BindingInfo& other);
-
-        /// Destructor
-        ~BindingInfo() override;
-
-        /// A map of bindings from (texture, sampler) -> combined sampler.
-        BindingMap binding_map;
-
-        /// The binding point to use for placeholder samplers.
-        BindingPoint placeholder_binding_point;
-    };
-
     /// Constructor
     CombineSamplers();
 
diff --git a/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc b/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc
index e611149..575f428 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc
@@ -30,6 +30,7 @@
 #include <memory>
 #include <utility>
 
+#include "src/tint/lang/glsl/writer/common/options.h"
 #include "src/tint/lang/wgsl/ast/transform/helper_test.h"
 
 namespace tint::glsl::writer {
@@ -42,7 +43,7 @@
     auto* expect = "";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -69,7 +70,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -96,7 +97,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -131,7 +132,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -166,7 +167,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -193,15 +194,14 @@
 )";
 
     ast::transform::DataMap data;
-    CombineSamplers::BindingMap map;
-    sem::SamplerTexturePair pair;
-    pair.texture_binding_point.group = 0;
-    pair.texture_binding_point.binding = 1;
-    pair.sampler_binding_point.group = 2;
-    pair.sampler_binding_point.binding = 3;
+    CombinedTextureSamplerInfo map;
+    binding::CombinedTextureSamplerPair pair;
+    pair.texture = {0, 1};
+    pair.sampler = {2, 3};
     map[pair] = "fuzzy";
+
     BindingPoint placeholder{1024, 0};
-    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    data.Add<CombineSamplersInfo>(map, placeholder);
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -228,15 +228,14 @@
 )";
 
     ast::transform::DataMap data;
-    CombineSamplers::BindingMap map;
-    sem::SamplerTexturePair pair;
-    pair.texture_binding_point.group = 3;
-    pair.texture_binding_point.binding = 2;
-    pair.sampler_binding_point.group = 1;
-    pair.sampler_binding_point.binding = 0;
+    CombinedTextureSamplerInfo map;
+    binding::CombinedTextureSamplerPair pair;
+    pair.texture = {3, 2};
+    pair.sampler = {1, 0};
     map[pair] = "fuzzy";
+
     BindingPoint placeholder{1024, 0};
-    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    data.Add<CombineSamplersInfo>(map, placeholder);
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -276,7 +275,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -314,7 +313,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -357,7 +356,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -399,7 +398,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -442,7 +441,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -505,7 +504,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -552,7 +551,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -599,7 +598,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -638,7 +637,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -675,7 +674,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -714,7 +713,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -751,7 +750,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -781,16 +780,16 @@
 }
 )";
 
-    BindingPoint placeholder{1024, 0};
-    sem::SamplerTexturePair pair;
-    pair.texture_binding_point.group = 0;
-    pair.texture_binding_point.binding = 0;
-    pair.sampler_binding_point.group = placeholder.group;
-    pair.sampler_binding_point.binding = placeholder.binding;
-    CombineSamplers::BindingMap map;
+    CombinedTextureSamplerInfo map;
+    binding::CombinedTextureSamplerPair pair;
+    pair.texture = {0, 0};
+    pair.sampler = {1024, 0};
     map[pair] = "fred";
+
+    BindingPoint placeholder{pair.sampler.group, pair.sampler.binding};
+
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    data.Add<CombineSamplersInfo>(map, placeholder);
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -819,20 +818,21 @@
     BindingPoint placeholder{1024, 0};
     BindingPoint tex{0, 0};
     BindingPoint samp{0, 1};
-    sem::SamplerTexturePair pair, placeholder_pair;
-    pair.texture_binding_point.group = tex.group;
-    pair.texture_binding_point.binding = tex.binding;
-    pair.sampler_binding_point.group = samp.group;
-    pair.sampler_binding_point.binding = samp.binding;
-    placeholder_pair.texture_binding_point.group = tex.group;
-    placeholder_pair.texture_binding_point.binding = tex.binding;
-    placeholder_pair.sampler_binding_point.group = placeholder.group;
-    placeholder_pair.sampler_binding_point.binding = placeholder.binding;
-    CombineSamplers::BindingMap map;
+
+    CombinedTextureSamplerInfo map;
+    binding::CombinedTextureSamplerPair pair;
+    pair.texture = {tex.group, tex.binding};
+    pair.sampler = {samp.group, samp.binding};
+
+    binding::CombinedTextureSamplerPair placeholder_pair;
+    placeholder_pair.texture = {tex.group, tex.binding};
+    placeholder_pair.sampler = {placeholder.group, placeholder.binding};
+
     map[pair] = "barney";
     map[placeholder_pair] = "fred";
+
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    data.Add<CombineSamplersInfo>(map, placeholder);
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -859,7 +859,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -894,7 +894,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -928,7 +928,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -959,7 +959,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -989,7 +989,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -1020,7 +1020,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -1051,7 +1051,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -1086,7 +1086,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -1125,7 +1125,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -1164,7 +1164,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
@@ -1208,7 +1208,7 @@
 )";
 
     ast::transform::DataMap data;
-    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), BindingPoint());
+    data.Add<CombineSamplersInfo>(CombinedTextureSamplerInfo(), BindingPoint());
     auto got = Run<CombineSamplers>(src, data);
 
     EXPECT_EQ(expect, str(got));
diff --git a/src/tint/lang/glsl/writer/common/BUILD.bazel b/src/tint/lang/glsl/writer/common/BUILD.bazel
index d4e3192..a3df865 100644
--- a/src/tint/lang/glsl/writer/common/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/common/BUILD.bazel
@@ -50,10 +50,18 @@
   deps = [
     "//src/tint/api/common",
     "//src/tint/api/options",
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/wgsl",
+    "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/ast/transform",
+    "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
+    "//src/tint/utils/id",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
     "//src/tint/utils/memory",
@@ -61,6 +69,7 @@
     "//src/tint/utils/result",
     "//src/tint/utils/rtti",
     "//src/tint/utils/strconv",
+    "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
@@ -77,16 +86,25 @@
   deps = [
     "//src/tint/api/common",
     "//src/tint/api/options",
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/wgsl",
+    "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/ast/transform",
+    "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
+    "//src/tint/utils/id",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
     "//src/tint/utils/memory",
     "//src/tint/utils/reflection",
     "//src/tint/utils/result",
     "//src/tint/utils/rtti",
+    "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
     "@gtest",
diff --git a/src/tint/lang/glsl/writer/common/BUILD.cmake b/src/tint/lang/glsl/writer/common/BUILD.cmake
index 80cc0a8..19ce276 100644
--- a/src/tint/lang/glsl/writer/common/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/common/BUILD.cmake
@@ -51,10 +51,18 @@
 tint_target_add_dependencies(tint_lang_glsl_writer_common lib
   tint_api_common
   tint_api_options
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
+  tint_lang_wgsl_program
   tint_lang_wgsl_sem
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
+  tint_utils_id
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
@@ -62,6 +70,7 @@
   tint_utils_result
   tint_utils_rtti
   tint_utils_strconv
+  tint_utils_symbol
   tint_utils_text
   tint_utils_traits
 )
@@ -81,16 +90,25 @@
 tint_target_add_dependencies(tint_lang_glsl_writer_common_test test
   tint_api_common
   tint_api_options
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
+  tint_lang_wgsl_program
   tint_lang_wgsl_sem
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
+  tint_utils_id
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
   tint_utils_reflection
   tint_utils_result
   tint_utils_rtti
+  tint_utils_symbol
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/lang/glsl/writer/common/BUILD.gn b/src/tint/lang/glsl/writer/common/BUILD.gn
index c9caccd..2994d84 100644
--- a/src/tint/lang/glsl/writer/common/BUILD.gn
+++ b/src/tint/lang/glsl/writer/common/BUILD.gn
@@ -53,10 +53,18 @@
     deps = [
       "${tint_src_dir}/api/common",
       "${tint_src_dir}/api/options",
+      "${tint_src_dir}/lang/core",
+      "${tint_src_dir}/lang/core/constant",
+      "${tint_src_dir}/lang/core/type",
+      "${tint_src_dir}/lang/wgsl",
+      "${tint_src_dir}/lang/wgsl/ast",
+      "${tint_src_dir}/lang/wgsl/ast/transform",
+      "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/sem",
       "${tint_src_dir}/utils/containers",
       "${tint_src_dir}/utils/diagnostic",
       "${tint_src_dir}/utils/ice",
+      "${tint_src_dir}/utils/id",
       "${tint_src_dir}/utils/macros",
       "${tint_src_dir}/utils/math",
       "${tint_src_dir}/utils/memory",
@@ -64,6 +72,7 @@
       "${tint_src_dir}/utils/result",
       "${tint_src_dir}/utils/rtti",
       "${tint_src_dir}/utils/strconv",
+      "${tint_src_dir}/utils/symbol",
       "${tint_src_dir}/utils/text",
       "${tint_src_dir}/utils/traits",
     ]
@@ -80,16 +89,25 @@
         "${tint_src_dir}:gmock_and_gtest",
         "${tint_src_dir}/api/common",
         "${tint_src_dir}/api/options",
+        "${tint_src_dir}/lang/core",
+        "${tint_src_dir}/lang/core/constant",
+        "${tint_src_dir}/lang/core/type",
+        "${tint_src_dir}/lang/wgsl",
+        "${tint_src_dir}/lang/wgsl/ast",
+        "${tint_src_dir}/lang/wgsl/ast/transform",
+        "${tint_src_dir}/lang/wgsl/program",
         "${tint_src_dir}/lang/wgsl/sem",
         "${tint_src_dir}/utils/containers",
         "${tint_src_dir}/utils/diagnostic",
         "${tint_src_dir}/utils/ice",
+        "${tint_src_dir}/utils/id",
         "${tint_src_dir}/utils/macros",
         "${tint_src_dir}/utils/math",
         "${tint_src_dir}/utils/memory",
         "${tint_src_dir}/utils/reflection",
         "${tint_src_dir}/utils/result",
         "${tint_src_dir}/utils/rtti",
+        "${tint_src_dir}/utils/symbol",
         "${tint_src_dir}/utils/text",
         "${tint_src_dir}/utils/traits",
       ]
diff --git a/src/tint/lang/glsl/writer/common/options.h b/src/tint/lang/glsl/writer/common/options.h
index 19aa11d..f6f114a 100644
--- a/src/tint/lang/glsl/writer/common/options.h
+++ b/src/tint/lang/glsl/writer/common/options.h
@@ -37,12 +37,92 @@
 #include "src/tint/api/options/external_texture.h"
 #include "src/tint/api/options/texture_builtins_from_uniform.h"
 #include "src/tint/lang/glsl/writer/common/version.h"
-#include "src/tint/lang/wgsl/sem/sampler_texture_pair.h"
+#include "src/tint/lang/wgsl/ast/transform/transform.h"
+
+namespace tint::glsl::writer::binding {
+
+/// A combined texture/sampler pair
+// Note, these are the WGSL binding points that are used to create the combined samplers
+struct CombinedTextureSamplerPair {
+    /// The WGSL texture binding
+    BindingPoint texture = {};
+    /// The WGSL sampler binding
+    BindingPoint sampler = {};
+
+    /// Equality operator
+    /// @param rhs the CombinedTextureSamplerPair to compare against
+    /// @returns true if this CombinedTextureSamplerPair is equal to `rhs`
+    inline bool operator==(const CombinedTextureSamplerPair& rhs) const {
+        return texture == rhs.texture && sampler == rhs.sampler;
+    }
+
+    /// Less then operator
+    /// @param rhs the CombinedTextureSamplerPair to compare against
+    /// @returns if this is less then rhs
+    inline bool operator<(const CombinedTextureSamplerPair& rhs) const {
+        if (texture < rhs.texture) {
+            return true;
+        }
+        if (texture == rhs.texture) {
+            return sampler < rhs.sampler;
+        }
+        return false;
+    }
+
+    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+    TINT_REFLECT(CombinedTextureSamplerPair, texture, sampler);
+};
+
+}  // namespace tint::glsl::writer::binding
+
+namespace std {
+/// Custom std::hash specialization for tint::glsl::writer::binding::CombinedTextureSamplerPair
+template <>
+class hash<tint::glsl::writer::binding::CombinedTextureSamplerPair> {
+  public:
+    /// @param n the combined sampler texture pair
+    /// @return the hash value
+    inline std::size_t operator()(
+        const tint::glsl::writer::binding::CombinedTextureSamplerPair& n) const {
+        return tint::Hash(n.texture, n.sampler);
+    }
+};
+
+}  // namespace std
 
 namespace tint::glsl::writer {
 
-using SamplerTexturePair = sem::SamplerTexturePair;
-using BindingMap = std::unordered_map<SamplerTexturePair, std::string>;
+using CombinedTextureSamplerInfo =
+    std::unordered_map<binding::CombinedTextureSamplerPair, std::string>;
+
+struct CombineSamplersInfo final
+    : public Castable<CombineSamplersInfo, tint::ast::transform::Data> {
+    /// Constructor
+    CombineSamplersInfo();
+
+    /// Constructor
+    /// @param map the texture/sampler to name map
+    /// @param placeholder the sampler placeholder binding point
+    CombineSamplersInfo(CombinedTextureSamplerInfo map, BindingPoint placeholder);
+
+    CombineSamplersInfo(const CombineSamplersInfo&) = default;
+    CombineSamplersInfo(CombineSamplersInfo&&) = default;
+
+    /// Destructor
+    ~CombineSamplersInfo() override;
+
+    CombineSamplersInfo& operator=(const CombineSamplersInfo&) = default;
+    CombineSamplersInfo& operator=(CombineSamplersInfo&&) = default;
+
+    /// 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_binding;
+
+    TINT_REFLECT(CombineSamplersInfo, sampler_texture_to_name, placeholder_sampler_binding);
+};
 
 /// Configuration options used for generating GLSL.
 struct Options {
@@ -67,12 +147,8 @@
     /// The GLSL version to emit
     Version version;
 
-    /// A map of SamplerTexturePair to combined sampler names for the
-    /// CombineSamplers transform
-    BindingMap binding_map;
-
-    /// The binding point to use for placeholder samplers.
-    BindingPoint placeholder_binding_point;
+    /// Combine Samplers transform information
+    CombineSamplersInfo combined_samplers_info = {};
 
     /// Options used in the bindings remapper
     BindingRemapperOptions binding_remapper_options = {};
@@ -97,8 +173,7 @@
                  disable_workgroup_init,
                  disable_polyfill_integer_div_mod,
                  version,
-                 binding_map,
-                 placeholder_binding_point,
+                 combined_samplers_info,
                  binding_remapper_options,
                  external_texture_options,
                  first_instance_offset,