dawn: use binding information for HLSL interface
Bug: tint:2133
Change-Id: Ia06a4ca92cb524ba01dbc5de4fb716f4bf80d1e0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/170682
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
index 7968a61..6ab1873 100644
--- a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
+++ b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
@@ -112,44 +112,72 @@
break;
}
- tint::BindingRemapperOptions bindingRemapper;
-
const BindingInfoArray& moduleBindingInfo = entryPoint.bindings;
- for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
- const BindGroupLayout* groupLayout = ToBackend(layout->GetBindGroupLayout(group));
- const auto& indices = layout->GetBindingIndexInfo()[group];
- const auto& groupBindingInfo = moduleBindingInfo[group];
+ tint::hlsl::writer::Bindings bindings;
- for (const auto& [binding, bindingInfo] : groupBindingInfo) {
- BindingIndex bindingIndex = groupLayout->GetBindingIndex(binding);
+ for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
+ const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
+ const auto& indices = layout->GetBindingIndexInfo()[group];
+ const BindingGroupInfoMap& moduleGroupBindingInfo = moduleBindingInfo[group];
+
+ for (const auto& [binding, shaderBindingInfo] : moduleGroupBindingInfo) {
+ BindingIndex bindingIndex = bgl->GetBindingIndex(binding);
tint::BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
static_cast<uint32_t>(binding)};
tint::BindingPoint dstBindingPoint{0u, indices[bindingIndex]};
- if (srcBindingPoint != dstBindingPoint) {
- bindingRemapper.binding_points.emplace(srcBindingPoint, dstBindingPoint);
- }
- }
+ auto* const bufferBindingInfo =
+ std::get_if<BufferBindingInfo>(&shaderBindingInfo.bindingInfo);
- // Tint will add two bindings (plane1, params) for one external texture binding.
- // We need to remap the binding points for the two bindings.
- // we cannot specified the final slot of those two bindings in
- // req.hlsl.externalTextureOptions because the final slots may be conflict with
- // existing other bindings, and then they will be remapped again with bindingRemapper
- // incorrectly. So we have to use intermediate binding slots in
- // req.hlsl.externalTextureOptions, and then map them to the final slots with
- // bindingRemapper.
- for (const auto& [_, expansion] : groupLayout->GetExternalTextureBindingExpansionMap()) {
- uint32_t plane1Slot = indices[groupLayout->GetBindingIndex(expansion.plane1)];
- uint32_t paramsSlot = indices[groupLayout->GetBindingIndex(expansion.params)];
- bindingRemapper.binding_points.emplace(
- tint::BindingPoint{static_cast<uint32_t>(group),
- static_cast<uint32_t>(expansion.plane1)},
- tint::BindingPoint{0u, plane1Slot});
- bindingRemapper.binding_points.emplace(
- tint::BindingPoint{static_cast<uint32_t>(group),
- static_cast<uint32_t>(expansion.params)},
- tint::BindingPoint{0u, paramsSlot});
+ if (bufferBindingInfo) {
+ switch (bufferBindingInfo->type) {
+ case wgpu::BufferBindingType::Uniform:
+ bindings.uniform.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Uniform{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ break;
+ case kInternalStorageBufferBinding:
+ case wgpu::BufferBindingType::Storage:
+ case wgpu::BufferBindingType::ReadOnlyStorage:
+ bindings.storage.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Storage{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ break;
+ case wgpu::BufferBindingType::Undefined:
+ DAWN_UNREACHABLE();
+ break;
+ }
+ } else if (std::holds_alternative<SamplerBindingInfo>(shaderBindingInfo.bindingInfo)) {
+ bindings.sampler.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Sampler{dstBindingPoint.group,
+ dstBindingPoint.binding});
+ } else if (std::holds_alternative<SampledTextureBindingInfo>(
+ shaderBindingInfo.bindingInfo)) {
+ bindings.texture.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Texture{dstBindingPoint.group,
+ dstBindingPoint.binding});
+ } else if (std::holds_alternative<StorageTextureBindingInfo>(
+ shaderBindingInfo.bindingInfo)) {
+ bindings.storage_texture.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::StorageTexture{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ } else if (std::holds_alternative<ExternalTextureBindingInfo>(
+ shaderBindingInfo.bindingInfo)) {
+ const auto& etBindingMap = bgl->GetExternalTextureBindingExpansionMap();
+ const auto& expansion = etBindingMap.find(binding);
+ DAWN_ASSERT(expansion != etBindingMap.end());
+
+ const auto& bindingExpansion = expansion->second;
+ tint::hlsl::writer::binding::BindingInfo plane0{
+ 0u, indices[bgl->GetBindingIndex(bindingExpansion.plane0)]};
+ tint::hlsl::writer::binding::BindingInfo plane1{
+ 0u, indices[bgl->GetBindingIndex(bindingExpansion.plane1)]};
+ tint::hlsl::writer::binding::BindingInfo metadata{
+ 0u, indices[bgl->GetBindingIndex(bindingExpansion.params)]};
+ bindings.external_texture.emplace(
+ srcBindingPoint,
+ tint::hlsl::writer::binding::ExternalTexture{metadata, plane0, plane1});
+ }
}
}
@@ -173,7 +201,10 @@
// D3D11 (HLSL SM5.0) doesn't support spaces, so we have to put the firstIndex in the
// default space(0)
tint::BindingPoint dstBindingPoint{0u, PipelineLayout::kFirstIndexOffsetConstantBufferSlot};
- bindingRemapper.binding_points.emplace(srcBindingPoint, dstBindingPoint);
+
+ bindings.uniform.emplace(
+ srcBindingPoint,
+ tint::hlsl::writer::binding::Uniform{dstBindingPoint.group, dstBindingPoint.binding});
}
req.hlsl.substituteOverrideConfig = std::move(substituteOverrideConfig);
@@ -184,8 +215,7 @@
req.hlsl.tintOptions.disable_robustness = !device->IsRobustnessEnabled();
req.hlsl.tintOptions.disable_workgroup_init =
device->IsToggleEnabled(Toggle::DisableWorkgroupInit);
- req.hlsl.tintOptions.binding_remapper_options = std::move(bindingRemapper);
- req.hlsl.tintOptions.external_texture_options = BuildExternalTextureTransformBindings(layout);
+ req.hlsl.tintOptions.bindings = std::move(bindings);
if (entryPoint.usesNumWorkgroups) {
// D3D11 (HLSL SM5.0) doesn't support spaces, so we have to put the numWorkgroups in the
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index 431efd2..10390e1 100644
--- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -179,17 +179,16 @@
using tint::BindingPoint;
- tint::BindingRemapperOptions bindingRemapper;
- std::unordered_map<BindingPoint, tint::core::Access> accessControls;
-
tint::ArrayLengthFromUniformOptions arrayLengthFromUniform;
arrayLengthFromUniform.ubo_binding = {layout->GetDynamicStorageBufferLengthsRegisterSpace(),
layout->GetDynamicStorageBufferLengthsShaderRegister()};
+ tint::hlsl::writer::Bindings bindings;
+
const BindingInfoArray& moduleBindingInfo = entryPoint.bindings;
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
- const auto& moduleGroupBindingInfo = moduleBindingInfo[group];
+ const BindingGroupInfoMap& moduleGroupBindingInfo = moduleBindingInfo[group];
// d3d12::BindGroupLayout packs the bindings per HLSL register-space. We modify
// the Tint AST to make the "bindings" decoration match the offset chosen by
@@ -201,80 +200,123 @@
static_cast<uint32_t>(binding)};
BindingPoint dstBindingPoint{static_cast<uint32_t>(group),
bgl->GetShaderRegister(bindingIndex)};
- if (srcBindingPoint != dstBindingPoint) {
- bindingRemapper.binding_points.emplace(srcBindingPoint, dstBindingPoint);
- }
- const auto* bufferBindingInfo =
+ auto* const bufferBindingInfo =
std::get_if<BufferBindingInfo>(&shaderBindingInfo.bindingInfo);
- if (bufferBindingInfo == nullptr) {
- continue;
+
+ if (bufferBindingInfo) {
+ switch (bufferBindingInfo->type) {
+ case wgpu::BufferBindingType::Uniform:
+ bindings.uniform.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Uniform{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ break;
+ case kInternalStorageBufferBinding:
+ case wgpu::BufferBindingType::Storage:
+ case wgpu::BufferBindingType::ReadOnlyStorage:
+ bindings.storage.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Storage{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ break;
+ case wgpu::BufferBindingType::Undefined:
+ DAWN_UNREACHABLE();
+ break;
+ }
+ } else if (std::holds_alternative<SamplerBindingInfo>(shaderBindingInfo.bindingInfo)) {
+ bindings.sampler.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Sampler{dstBindingPoint.group,
+ dstBindingPoint.binding});
+ } else if (std::holds_alternative<SampledTextureBindingInfo>(
+ shaderBindingInfo.bindingInfo)) {
+ bindings.texture.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::Texture{dstBindingPoint.group,
+ dstBindingPoint.binding});
+ } else if (std::holds_alternative<StorageTextureBindingInfo>(
+ shaderBindingInfo.bindingInfo)) {
+ bindings.storage_texture.emplace(
+ srcBindingPoint, tint::hlsl::writer::binding::StorageTexture{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ } else if (std::holds_alternative<ExternalTextureBindingInfo>(
+ shaderBindingInfo.bindingInfo)) {
+ const auto& etBindingMap = bgl->GetExternalTextureBindingExpansionMap();
+ const auto& expansion = etBindingMap.find(binding);
+ DAWN_ASSERT(expansion != etBindingMap.end());
+
+ const auto& bindingExpansion = expansion->second;
+ tint::hlsl::writer::binding::BindingInfo plane0{
+ static_cast<uint32_t>(group),
+ bgl->GetShaderRegister(bgl->GetBindingIndex(bindingExpansion.plane0))};
+ tint::hlsl::writer::binding::BindingInfo plane1{
+ static_cast<uint32_t>(group),
+ bgl->GetShaderRegister(bgl->GetBindingIndex(bindingExpansion.plane1))};
+ tint::hlsl::writer::binding::BindingInfo metadata{
+ static_cast<uint32_t>(group),
+ bgl->GetShaderRegister(bgl->GetBindingIndex(bindingExpansion.params))};
+ bindings.external_texture.emplace(
+ srcBindingPoint,
+ tint::hlsl::writer::binding::ExternalTexture{metadata, plane0, plane1});
}
- const auto& bindingLayout =
- std::get<BufferBindingLayout>(bgl->GetBindingInfo(bindingIndex).bindingLayout);
+ if (bufferBindingInfo) {
+ const auto& bindingLayout =
+ std::get<BufferBindingLayout>(bgl->GetBindingInfo(bindingIndex).bindingLayout);
- // Declaring a read-only storage buffer in HLSL but specifying a storage
- // buffer in the BGL produces the wrong output. Force read-only storage
- // buffer bindings to be treated as UAV instead of SRV. Internal storage
- // buffer is a storage buffer used in the internal pipeline.
- const bool forceStorageBufferAsUAV =
- (bufferBindingInfo->type == wgpu::BufferBindingType::ReadOnlyStorage &&
- (bindingLayout.type == wgpu::BufferBindingType::Storage ||
- bindingLayout.type == kInternalStorageBufferBinding));
- if (forceStorageBufferAsUAV) {
- accessControls.emplace(srcBindingPoint, tint::core::Access::kReadWrite);
- }
-
- // On D3D12 backend all storage buffers without Dynamic Buffer Offset will always be
- // bound to root descriptor tables, where D3D12 runtime can guarantee that OOB-read will
- // always return 0 and OOB-write will always take no action, so we don't need to do
- // robustness transform on them. Note that we still need to do robustness transform on
- // uniform buffers because only sized array is allowed in uniform buffers, so FXC will
- // report compilation error when the indexing to the array in a cBuffer is out of bound
- // and can be checked at compilation time. Storage buffers are OK because they are
- // always translated with RWByteAddressBuffers, which has no such sized arrays.
- //
- // For example below WGSL shader will cause compilation error when we skip robustness
- // transform on uniform buffers:
- //
- // struct TestData {
- // data: array<vec4<u32>, 3>,
- // };
- // @group(0) @binding(0) var<uniform> s: TestData;
- //
- // fn test() -> u32 {
- // let index = 1000000u;
- // if (s.data[index][0] != 0u) { // error X3504: array index out of bounds
- // return 0x1004u;
- // }
- // return 0u;
- // }
- if ((bufferBindingInfo->type == wgpu::BufferBindingType::Storage ||
- bufferBindingInfo->type == wgpu::BufferBindingType::ReadOnlyStorage) &&
- !bindingLayout.hasDynamicOffset) {
- req.hlsl.tintOptions.binding_points_ignored_in_robustness_transform.emplace_back(
- srcBindingPoint);
- }
- }
-
- // Add arrayLengthFromUniform options
- {
- for (const auto& bindingAndRegisterOffset :
- layout->GetDynamicStorageBufferLengthInfo()[group].bindingAndRegisterOffsets) {
- BindingNumber binding = bindingAndRegisterOffset.binding;
- uint32_t registerOffset = bindingAndRegisterOffset.registerOffset;
-
- BindingPoint bindingPoint{static_cast<uint32_t>(group),
- static_cast<uint32_t>(binding)};
- // Get the renamed binding point if it was remapped.
- auto it = bindingRemapper.binding_points.find(bindingPoint);
- if (it != bindingRemapper.binding_points.end()) {
- bindingPoint = it->second;
+ // Declaring a read-only storage buffer in HLSL but specifying a storage
+ // buffer in the BGL produces the wrong output. Force read-only storage
+ // buffer bindings to be treated as UAV instead of SRV. Internal storage
+ // buffer is a storage buffer used in the internal pipeline.
+ const bool forceStorageBufferAsUAV =
+ (bufferBindingInfo->type == wgpu::BufferBindingType::ReadOnlyStorage &&
+ (bindingLayout.type == wgpu::BufferBindingType::Storage ||
+ bindingLayout.type == kInternalStorageBufferBinding));
+ if (forceStorageBufferAsUAV) {
+ bindings.access_controls.emplace(srcBindingPoint,
+ tint::core::Access::kReadWrite);
}
- arrayLengthFromUniform.bindpoint_to_size_index.emplace(bindingPoint,
- registerOffset);
+ // On D3D12 backend all storage buffers without Dynamic Buffer Offset will always be
+ // bound to root descriptor tables, where D3D12 runtime can guarantee that OOB-read
+ // will always return 0 and OOB-write will always take no action, so we don't need
+ // to do robustness transform on them. Note that we still need to do robustness
+ // transform on uniform buffers because only sized array is allowed in uniform
+ // buffers, so FXC will report compilation error when the indexing to the array in a
+ // cBuffer is out of bound and can be checked at compilation time. Storage buffers
+ // are OK because they are always translated with RWByteAddressBuffers, which has no
+ // such sized arrays.
+ //
+ // For example below WGSL shader will cause compilation error when we skip
+ // robustness transform on uniform buffers:
+ //
+ // struct TestData {
+ // data: array<vec4<u32>, 3>,
+ // };
+ // @group(0) @binding(0) var<uniform> s: TestData;
+ //
+ // fn test() -> u32 {
+ // let index = 1000000u;
+ // if (s.data[index][0] != 0u) { // error X3504: array index out of bounds
+ // return 0x1004u;
+ // }
+ // return 0u;
+ // }
+ if ((bufferBindingInfo->type == wgpu::BufferBindingType::Storage ||
+ bufferBindingInfo->type == wgpu::BufferBindingType::ReadOnlyStorage) &&
+ !bindingLayout.hasDynamicOffset) {
+ bindings.ignored_by_robustness_transform.emplace_back(srcBindingPoint);
+ }
+ }
+
+ // Add arrayLengthFromUniform options
+ {
+ for (const auto& bindingAndRegisterOffset :
+ layout->GetDynamicStorageBufferLengthInfo()[group].bindingAndRegisterOffsets) {
+ BindingNumber bindingNum = bindingAndRegisterOffset.binding;
+ uint32_t registerOffset = bindingAndRegisterOffset.registerOffset;
+ BindingPoint bindingPoint{static_cast<uint32_t>(group),
+ static_cast<uint32_t>(bindingNum)};
+ arrayLengthFromUniform.bindpoint_to_size_index.emplace(bindingPoint,
+ registerOffset);
+ }
}
}
}
@@ -295,9 +337,7 @@
req.hlsl.tintOptions.disable_robustness = !device->IsRobustnessEnabled();
req.hlsl.tintOptions.disable_workgroup_init =
device->IsToggleEnabled(Toggle::DisableWorkgroupInit);
- req.hlsl.tintOptions.binding_remapper_options = std::move(bindingRemapper);
- req.hlsl.tintOptions.access_controls = std::move(accessControls);
- req.hlsl.tintOptions.external_texture_options = BuildExternalTextureTransformBindings(layout);
+ req.hlsl.tintOptions.bindings = std::move(bindings);
if (entryPoint.usesNumWorkgroups) {
req.hlsl.tintOptions.root_constant_binding_point = tint::BindingPoint{
diff --git a/src/tint/cmd/loopy/BUILD.bazel b/src/tint/cmd/loopy/BUILD.bazel
index 1b0859f..9a2c3ad 100644
--- a/src/tint/cmd/loopy/BUILD.bazel
+++ b/src/tint/cmd/loopy/BUILD.bazel
@@ -51,6 +51,7 @@
"//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
"//src/tint/lang/hlsl/writer/common",
+ "//src/tint/lang/hlsl/writer/helpers",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/common",
diff --git a/src/tint/cmd/loopy/BUILD.cmake b/src/tint/cmd/loopy/BUILD.cmake
index 2597a47..ad75e1a 100644
--- a/src/tint/cmd/loopy/BUILD.cmake
+++ b/src/tint/cmd/loopy/BUILD.cmake
@@ -52,6 +52,7 @@
tint_lang_core_ir
tint_lang_core_type
tint_lang_hlsl_writer_common
+ tint_lang_hlsl_writer_helpers
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_common
diff --git a/src/tint/cmd/loopy/BUILD.gn b/src/tint/cmd/loopy/BUILD.gn
index 5176168..f578df9 100644
--- a/src/tint/cmd/loopy/BUILD.gn
+++ b/src/tint/cmd/loopy/BUILD.gn
@@ -51,6 +51,7 @@
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/hlsl/writer/common",
+ "${tint_src_dir}/lang/hlsl/writer/helpers",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
"${tint_src_dir}/lang/wgsl/common",
diff --git a/src/tint/cmd/loopy/main.cc b/src/tint/cmd/loopy/main.cc
index ccd8b23..89bbcb3 100644
--- a/src/tint/cmd/loopy/main.cc
+++ b/src/tint/cmd/loopy/main.cc
@@ -37,6 +37,7 @@
#endif // TINT_BUILD_GLSL_WRITER
#if TINT_BUILD_HLSL_WRITER
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
#include "src/tint/lang/hlsl/writer/writer.h"
#endif // TINT_BUILD_HLSL_WRITER
@@ -282,8 +283,7 @@
bool GenerateHlsl(const tint::Program& program) {
#if TINT_BUILD_HLSL_WRITER
tint::hlsl::writer::Options gen_options;
- gen_options.external_texture_options.bindings_map =
- tint::cmd::GenerateExternalTextureBindings(program);
+ gen_options.bindings = tint::hlsl::writer::GenerateBindings(program);
auto result = tint::hlsl::writer::Generate(program, gen_options);
if (result != tint::Success) {
tint::cmd::PrintWGSL(std::cerr, program);
diff --git a/src/tint/cmd/tint/BUILD.bazel b/src/tint/cmd/tint/BUILD.bazel
index fbc1286..d77264b 100644
--- a/src/tint/cmd/tint/BUILD.bazel
+++ b/src/tint/cmd/tint/BUILD.bazel
@@ -51,6 +51,7 @@
"//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
"//src/tint/lang/hlsl/writer/common",
+ "//src/tint/lang/hlsl/writer/helpers",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
"//src/tint/lang/wgsl/ast/transform",
diff --git a/src/tint/cmd/tint/BUILD.cmake b/src/tint/cmd/tint/BUILD.cmake
index 9a02dfe..f354d49 100644
--- a/src/tint/cmd/tint/BUILD.cmake
+++ b/src/tint/cmd/tint/BUILD.cmake
@@ -52,6 +52,7 @@
tint_lang_core_ir
tint_lang_core_type
tint_lang_hlsl_writer_common
+ tint_lang_hlsl_writer_helpers
tint_lang_wgsl
tint_lang_wgsl_ast
tint_lang_wgsl_ast_transform
diff --git a/src/tint/cmd/tint/BUILD.gn b/src/tint/cmd/tint/BUILD.gn
index 5d0447f..e51fbf4 100644
--- a/src/tint/cmd/tint/BUILD.gn
+++ b/src/tint/cmd/tint/BUILD.gn
@@ -51,6 +51,7 @@
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/hlsl/writer/common",
+ "${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",
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 7b04c72..38d695b 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -83,6 +83,7 @@
#if TINT_BUILD_HLSL_WRITER
#include "src/tint/lang/hlsl/validate/validate.h"
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
#include "src/tint/lang/hlsl/writer/writer.h"
#endif // TINT_BUILD_HLSL_WRITER
@@ -915,8 +916,7 @@
tint::hlsl::writer::Options gen_options;
gen_options.disable_robustness = !options.enable_robustness;
gen_options.disable_workgroup_init = options.disable_workgroup_init;
- gen_options.external_texture_options.bindings_map =
- tint::cmd::GenerateExternalTextureBindings(program);
+ gen_options.bindings = tint::hlsl::writer::GenerateBindings(program);
gen_options.root_constant_binding_point = options.hlsl_root_constant_binding_point;
gen_options.pixel_local_options = options.pixel_local_options;
gen_options.polyfill_dot_4x8_packed = options.hlsl_shader_model < kMinShaderModelForDP4aInHLSL;
diff --git a/src/tint/fuzzers/BUILD.gn b/src/tint/fuzzers/BUILD.gn
index b570ed4c..bf83f01 100644
--- a/src/tint/fuzzers/BUILD.gn
+++ b/src/tint/fuzzers/BUILD.gn
@@ -85,6 +85,7 @@
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/glsl/writer",
"${tint_src_dir}/lang/hlsl/writer",
+ "${tint_src_dir}/lang/hlsl/writer/helpers",
"${tint_src_dir}/lang/msl/writer",
"${tint_src_dir}/lang/msl/writer/helpers",
"${tint_src_dir}/lang/spirv/writer",
diff --git a/src/tint/fuzzers/CMakeLists.txt b/src/tint/fuzzers/CMakeLists.txt
index 136afd3..134f6ca 100644
--- a/src/tint/fuzzers/CMakeLists.txt
+++ b/src/tint/fuzzers/CMakeLists.txt
@@ -51,6 +51,7 @@
tint_spvheaders_compile_options(${NAME})
tint_spvtools_compile_options(${NAME})
endif()
+ target_link_libraries(${NAME} PRIVATE tint_lang_hlsl_writer_helpers)
target_link_libraries(${NAME} PRIVATE tint_lang_msl_writer_helpers)
target_link_libraries(${NAME} PRIVATE tint_lang_spirv_writer_helpers)
target_compile_options(${NAME} PRIVATE -Wno-missing-prototypes)
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt b/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
index fbdb3b9..d4a7050 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
+++ b/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
@@ -27,8 +27,9 @@
function(add_tint_ast_fuzzer NAME)
add_executable(${NAME} ${NAME}.cc ${AST_FUZZER_SOURCES})
- target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_spirv_writer_helpers)
+ target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_hlsl_writer_helpers)
target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_msl_writer_helpers)
+ target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_spirv_writer_helpers)
tint_fuzzer_compile_options(${NAME})
if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
tint_spvheaders_compile_options(${NAME})
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index be477d3..a50ca8e 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -62,6 +62,10 @@
#include "src/tint/lang/msl/writer/helpers/generate_bindings.h"
#endif // TINT_BUILD_MSL_WRITER
+#if TINT_BUILD_HLSL_WRITER
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
+#endif // TINT_BUILD_MSL_WRITER
+
namespace tint::fuzzers {
namespace {
@@ -272,6 +276,9 @@
#endif // TINT_BUILD_MSL_WRITER
break;
case OutputFormat::kHLSL:
+#if TINT_BUILD_HLSL_WRITER
+ options_hlsl_.bindings = tint::hlsl::writer::GenerateBindings(program);
+#endif // TINT_BUILD_HLSL_WRITER
break;
case OutputFormat::kSpv:
#if TINT_BUILD_SPV_WRITER
@@ -282,51 +289,6 @@
break;
}
- // For the generates which use MultiPlanar, make sure the configuration options are provided so
- // that the transformer will execute.
- if (output_ == OutputFormat::kHLSL) {
- // Gather external texture binding information
- // Collect next valid binding number per group
- std::unordered_map<uint32_t, uint32_t> group_to_next_binding_number;
- std::vector<BindingPoint> ext_tex_bps;
- for (auto* var : program.AST().GlobalVariables()) {
- if (auto* sem_var = program.Sem().Get(var)->As<sem::GlobalVariable>()) {
- if (auto bp = sem_var->Attributes().binding_point) {
- auto& n = group_to_next_binding_number[bp->group];
- n = std::max(n, bp->binding + 1);
-
- if (sem_var->Type()->UnwrapRef()->Is<core::type::ExternalTexture>()) {
- ext_tex_bps.emplace_back(*bp);
- }
- }
- }
- }
-
- ExternalTextureOptions::BindingsMap new_bindings_map;
- for (auto bp : ext_tex_bps) {
- uint32_t g = bp.group;
- uint32_t& next_num = group_to_next_binding_number[g];
- auto new_bps = ExternalTextureOptions::BindingPoints{{g, next_num++}, {g, next_num++}};
-
- new_bindings_map[bp] = new_bps;
- }
-
- switch (output_) {
- case OutputFormat::kMSL: {
- break;
- }
- case OutputFormat::kHLSL: {
- options_hlsl_.external_texture_options.bindings_map = new_bindings_map;
- break;
- }
- case OutputFormat::kSpv: {
- break;
- }
- default:
- break;
- }
- }
-
switch (output_) {
case OutputFormat::kWGSL: {
#if TINT_BUILD_WGSL_WRITER
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt b/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt
index b6f0043..337acdd 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt
+++ b/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt
@@ -27,8 +27,9 @@
function(add_tint_regex_fuzzer NAME)
add_executable(${NAME} ${NAME}.cc ${REGEX_FUZZER_SOURCES})
- target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_spirv_writer_helpers)
+ target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_hlsl_writer_helpers)
target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_msl_writer_helpers)
+ target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_spirv_writer_helpers)
tint_fuzzer_compile_options(${NAME})
tint_spvtools_compile_options(${NAME})
target_compile_definitions(${NAME} PRIVATE CUSTOM_MUTATOR)
diff --git a/src/tint/lang/hlsl/writer/BUILD.cmake b/src/tint/lang/hlsl/writer/BUILD.cmake
index 5a19a3c..a40f368 100644
--- a/src/tint/lang/hlsl/writer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/BUILD.cmake
@@ -37,6 +37,7 @@
include(lang/hlsl/writer/ast_printer/BUILD.cmake)
include(lang/hlsl/writer/ast_raise/BUILD.cmake)
include(lang/hlsl/writer/common/BUILD.cmake)
+include(lang/hlsl/writer/helpers/BUILD.cmake)
if(TINT_BUILD_HLSL_WRITER)
################################################################################
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index cc97b5e..4552722 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -50,6 +50,7 @@
#include "src/tint/lang/hlsl/writer/ast_raise/pixel_local.h"
#include "src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.h"
#include "src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h"
+#include "src/tint/lang/hlsl/writer/common/option_helpers.h"
#include "src/tint/lang/wgsl/ast/call_statement.h"
#include "src/tint/lang/wgsl/ast/internal_attribute.h"
#include "src/tint/lang/wgsl/ast/interpolate_attribute.h"
@@ -206,10 +207,9 @@
manager.Add<ast::transform::Robustness>();
ast::transform::Robustness::Config config = {};
-
config.bindings_ignored = std::unordered_set<BindingPoint>(
- options.binding_points_ignored_in_robustness_transform.cbegin(),
- options.binding_points_ignored_in_robustness_transform.cend());
+ options.bindings.ignored_by_robustness_transform.cbegin(),
+ options.bindings.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
@@ -219,20 +219,24 @@
data.Add<ast::transform::Robustness::Config>(config);
}
- // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
- data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
- options.external_texture_options.bindings_map);
- manager.Add<ast::transform::MultiplanarExternalTexture>();
+ ExternalTextureOptions external_texture_options{};
+ RemapperData remapper_data{};
+ ArrayLengthFromUniformOptions array_length_from_uniform_options{};
+ PopulateBindingRelatedOptions(options, remapper_data, external_texture_options,
+ array_length_from_uniform_options);
- // BindingRemapper must come after MultiplanarExternalTexture
manager.Add<ast::transform::BindingRemapper>();
-
// D3D11 and 12 registers like `t3` and `c3` have the same bindingOffset number in
// the remapping but should not be considered a collision because they have
// different types.
data.Add<ast::transform::BindingRemapper::Remappings>(
- options.binding_remapper_options.binding_points, options.access_controls,
- /* allow_collisions */ true);
+ remapper_data, options.bindings.access_controls, /* allow_collisions */ true);
+
+ // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
+ // MultiplanarExternalTexture must come after BindingRemapper
+ data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
+ external_texture_options.bindings_map, /* may_collide */ true);
+ manager.Add<ast::transform::MultiplanarExternalTexture>();
{ // Builtin polyfills
ast::transform::BuiltinPolyfill::Builtins polyfills;
@@ -330,11 +334,10 @@
manager.Add<ast::transform::RemovePhonies>();
// Build the config for the internal ArrayLengthFromUniform transform.
- auto& array_length_from_uniform = options.array_length_from_uniform;
ast::transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
- array_length_from_uniform.ubo_binding);
+ array_length_from_uniform_options.ubo_binding);
array_length_from_uniform_cfg.bindpoint_to_size_index =
- array_length_from_uniform.bindpoint_to_size_index;
+ std::move(array_length_from_uniform_options.bindpoint_to_size_index);
// DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
// ExpandCompoundAssignment.
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.bazel b/src/tint/lang/hlsl/writer/common/BUILD.bazel
index 93cb98f..333c5e5 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/common/BUILD.bazel
@@ -39,18 +39,27 @@
cc_library(
name = "common",
srcs = [
+ "option_helpers.cc",
"options.cc",
],
hdrs = [
+ "option_helpers.h",
"options.h",
],
deps = [
"//src/tint/api/common",
"//src/tint/api/options",
"//src/tint/lang/core",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
"//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/text",
"//src/tint/utils/traits",
],
copts = COPTS,
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.cmake b/src/tint/lang/hlsl/writer/common/BUILD.cmake
index 1a5415e..75293b9 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/common/BUILD.cmake
@@ -39,6 +39,8 @@
# Kind: lib
################################################################################
tint_add_target(tint_lang_hlsl_writer_common lib
+ lang/hlsl/writer/common/option_helpers.cc
+ lang/hlsl/writer/common/option_helpers.h
lang/hlsl/writer/common/options.cc
lang/hlsl/writer/common/options.h
)
@@ -47,8 +49,15 @@
tint_api_common
tint_api_options
tint_lang_core
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
tint_utils_macros
tint_utils_math
+ tint_utils_memory
tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
tint_utils_traits
)
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.gn b/src/tint/lang/hlsl/writer/common/BUILD.gn
index 39c9b06..b8d369d 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/common/BUILD.gn
@@ -40,6 +40,8 @@
libtint_source_set("common") {
sources = [
+ "option_helpers.cc",
+ "option_helpers.h",
"options.cc",
"options.h",
]
@@ -47,9 +49,16 @@
"${tint_src_dir}/api/common",
"${tint_src_dir}/api/options",
"${tint_src_dir}/lang/core",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
"${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/text",
"${tint_src_dir}/utils/traits",
]
}
diff --git a/src/tint/lang/hlsl/writer/common/option_helpers.cc b/src/tint/lang/hlsl/writer/common/option_helpers.cc
new file mode 100644
index 0000000..aace10b
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/common/option_helpers.cc
@@ -0,0 +1,231 @@
+/// Copyright 2024 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.
+
+#include "src/tint/lang/hlsl/writer/common/option_helpers.h"
+
+#include <utility>
+
+#include "src/tint/utils/containers/hashset.h"
+
+namespace tint::hlsl::writer {
+
+/// binding::BindingInfo to tint::BindingPoint map
+using InfoToPointMap = tint::Hashmap<binding::BindingInfo, tint::BindingPoint, 8>;
+
+Result<SuccessType> ValidateBindingOptions(const Options& options) {
+ diag::List diagnostics;
+
+ tint::Hashmap<tint::BindingPoint, binding::BindingInfo, 8> seen_wgsl_bindings{};
+
+ InfoToPointMap seen_hlsl_buffer_bindings{};
+ InfoToPointMap seen_hlsl_texture_bindings{};
+ InfoToPointMap seen_hlsl_sampler_bindings{};
+
+ // Both wgsl_seen and spirv_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 doesn't
+ // match, then we report an error about a duplicate binding point.
+
+ auto wgsl_seen = [&diagnostics, &seen_wgsl_bindings](const tint::BindingPoint& src,
+ const binding::BindingInfo& dst) -> bool {
+ if (auto binding = seen_wgsl_bindings.Get(src)) {
+ if (*binding != dst) {
+ std::stringstream str;
+ str << "found duplicate WGSL binding point: " << src;
+
+ diagnostics.AddError(diag::System::Writer, str.str());
+ return true;
+ }
+ }
+ seen_wgsl_bindings.Add(src, dst);
+ return false;
+ };
+
+ auto hlsl_seen = [&diagnostics](InfoToPointMap& map, const binding::BindingInfo& src,
+ const tint::BindingPoint& dst) -> bool {
+ if (auto binding = map.Get(src)) {
+ if (*binding != dst) {
+ std::stringstream str;
+ str << "found duplicate MSL binding point: [binding: " << src.binding << "]";
+ diagnostics.AddError(diag::System::Writer, str.str());
+ return true;
+ }
+ }
+ map.Add(src, dst);
+ return false;
+ };
+
+ auto valid = [&wgsl_seen, &hlsl_seen](InfoToPointMap& map, const auto& hsh) -> bool {
+ for (const auto& it : hsh) {
+ const auto& src_binding = it.first;
+ const auto& dst_binding = it.second;
+
+ if (wgsl_seen(src_binding, dst_binding)) {
+ return false;
+ }
+
+ if (hlsl_seen(map, dst_binding, src_binding)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ // Storage and uniform are both [[buffer()]]
+ if (!valid(seen_hlsl_buffer_bindings, options.bindings.uniform)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing uniform", {});
+ return Failure{std::move(diagnostics)};
+ }
+ if (!valid(seen_hlsl_buffer_bindings, options.bindings.storage)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing storage", {});
+ return Failure{std::move(diagnostics)};
+ }
+
+ // Sampler is [[sampler()]]
+ if (!valid(seen_hlsl_sampler_bindings, options.bindings.sampler)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing sampler", {});
+ return Failure{std::move(diagnostics)};
+ }
+
+ // Texture and storage texture are [[texture()]]
+ if (!valid(seen_hlsl_texture_bindings, options.bindings.texture)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing texture", {});
+ return Failure{std::move(diagnostics)};
+ }
+ if (!valid(seen_hlsl_texture_bindings, options.bindings.storage_texture)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing storage_texture", {});
+ return Failure{std::move(diagnostics)};
+ }
+
+ for (const auto& it : options.bindings.external_texture) {
+ const auto& src_binding = it.first;
+ const auto& plane0 = it.second.plane0;
+ const auto& plane1 = it.second.plane1;
+ const auto& metadata = it.second.metadata;
+
+ // Validate with the actual source regardless of what the remapper will do
+ if (wgsl_seen(src_binding, plane0)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ return Failure{std::move(diagnostics)};
+ }
+
+ // Plane0 & Plane1 are [[texture()]]
+ if (hlsl_seen(seen_hlsl_texture_bindings, plane0, src_binding)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ return Failure{std::move(diagnostics)};
+ }
+ if (hlsl_seen(seen_hlsl_texture_bindings, plane1, src_binding)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ return Failure{std::move(diagnostics)};
+ }
+ // Metadata is [[buffer()]]
+ if (hlsl_seen(seen_hlsl_buffer_bindings, metadata, src_binding)) {
+ diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+ return Failure{std::move(diagnostics)};
+ }
+ }
+
+ return Success;
+}
+
+// The remapped binding data and external texture data need to coordinate in order to put things in
+// the correct place when we're done. The binding remapper is run first, so make sure that the
+// external texture uses the new binding point.
+//
+// When the data comes in we have a list of all WGSL origin (group,binding) pairs to HLSL
+// (group,binding) in the `uniform`, `storage`, `texture`, and `sampler` arrays.
+void PopulateBindingRelatedOptions(
+ const Options& options,
+ RemapperData& remapper_data,
+ ExternalTextureOptions& external_texture,
+ ArrayLengthFromUniformOptions& array_length_from_uniform_options) {
+ auto create_remappings = [&remapper_data](const auto& hsh) {
+ for (const auto& it : hsh) {
+ const BindingPoint& src_binding_point = it.first;
+ const binding::BindingInfo& dst_binding_info = it.second;
+
+ BindingPoint dst_binding_point{dst_binding_info.group, dst_binding_info.binding};
+
+ // Skip redundant bindings
+ if (src_binding_point == dst_binding_point) {
+ continue;
+ }
+
+ remapper_data.emplace(src_binding_point, dst_binding_point);
+ }
+ };
+
+ create_remappings(options.bindings.uniform);
+ create_remappings(options.bindings.storage);
+ create_remappings(options.bindings.texture);
+ create_remappings(options.bindings.storage_texture);
+ create_remappings(options.bindings.sampler);
+
+ // External textures are re-bound to their plane0 location
+ for (const auto& it : options.bindings.external_texture) {
+ const BindingPoint& src_binding_point = it.first;
+ const binding::BindingInfo& plane0 = it.second.plane0;
+ const binding::BindingInfo& plane1 = it.second.plane1;
+ const binding::BindingInfo& metadata = it.second.metadata;
+
+ BindingPoint plane0_binding_point{plane0.group, plane0.binding};
+ BindingPoint plane1_binding_point{plane1.group, plane1.binding};
+ BindingPoint metadata_binding_point{metadata.group, metadata.binding};
+
+ // Use the re-bound HLSL plane0 value for the lookup key.
+ external_texture.bindings_map.emplace(
+ plane0_binding_point,
+ ExternalTextureOptions::BindingPoints{plane1_binding_point, metadata_binding_point});
+
+ // Bindings which go to the same slot in HLSL do not need to be re-bound.
+ if (src_binding_point == plane0_binding_point) {
+ continue;
+ }
+
+ remapper_data.emplace(src_binding_point, plane0_binding_point);
+ }
+
+ // ArrayLengthFromUniformOptions bindpoints may need to be remapped
+ {
+ std::unordered_map<BindingPoint, uint32_t> bindpoint_to_size_index;
+ for (auto& [bindpoint, index] : options.array_length_from_uniform.bindpoint_to_size_index) {
+ auto it = remapper_data.find(bindpoint);
+ if (it != remapper_data.end()) {
+ bindpoint_to_size_index.emplace(it->second, index);
+ } else {
+ bindpoint_to_size_index.emplace(bindpoint, index);
+ }
+ }
+
+ array_length_from_uniform_options.ubo_binding =
+ options.array_length_from_uniform.ubo_binding;
+ array_length_from_uniform_options.bindpoint_to_size_index =
+ std::move(bindpoint_to_size_index);
+ }
+}
+
+} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/common/option_helpers.h b/src/tint/lang/hlsl/writer/common/option_helpers.h
new file mode 100644
index 0000000..bcfc083
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/common/option_helpers.h
@@ -0,0 +1,62 @@
+/// Copyright 2024 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_LANG_HLSL_WRITER_COMMON_OPTION_HELPERS_H_
+#define SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTION_HELPERS_H_
+
+#include <unordered_map>
+
+#include "src/tint/api/common/binding_point.h"
+#include "src/tint/api/options/external_texture.h"
+#include "src/tint/lang/hlsl/writer/common/options.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/result/result.h"
+
+namespace tint::hlsl::writer {
+
+/// The remapper data
+using RemapperData = std::unordered_map<BindingPoint, BindingPoint>;
+
+/// @param options the options
+/// @returns success or failure
+Result<SuccessType> ValidateBindingOptions(const Options& options);
+
+/// Populates binding-related option from the writer options
+/// @param options the writer options
+/// @param remapper_data where to put the remapper data
+/// @param external_texture where to store the external texture options
+/// @param array_length_from_uniform_options where to store the ArrayLengthFromUniform options
+/// Note, these are populated together because there are dependencies between the two types of data.
+void PopulateBindingRelatedOptions(
+ const Options& options,
+ RemapperData& remapper_data,
+ ExternalTextureOptions& external_texture,
+ ArrayLengthFromUniformOptions& array_length_from_uniform_options);
+
+} // namespace tint::hlsl::writer
+
+#endif // SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTION_HELPERS_H_
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index b8d9a75..eb038de 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -39,10 +39,111 @@
#include "src/tint/api/options/external_texture.h"
#include "src/tint/api/options/pixel_local.h"
#include "src/tint/lang/core/access.h"
+#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/reflection/reflection.h"
namespace tint::hlsl::writer {
+namespace binding {
+
+/// Generic binding point
+struct BindingInfo {
+ /// The group
+ uint32_t group = 0;
+ /// 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 group == rhs.group && 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); }
+
+ /// @returns the hash code of the BindingInfo
+ size_t HashCode() const { return Hash(group, binding); }
+
+ /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+ TINT_REFLECT(BindingInfo, group, binding);
+};
+/// Ensure that all the fields of BindingInfo are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingInfo);
+
+using Uniform = BindingInfo;
+using Storage = BindingInfo;
+using Texture = BindingInfo;
+using StorageTexture = BindingInfo;
+using Sampler = BindingInfo;
+
+/// 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);
+};
+
+/// Ensure that all the fields of ExternalTexture are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTexture);
+
+} // namespace binding
+
+/// Maps the WGSL binding point to the SPIR-V group,binding for uniforms
+using UniformBindings = std::unordered_map<BindingPoint, binding::Uniform>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for storage
+using StorageBindings = std::unordered_map<BindingPoint, binding::Storage>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for textures
+using TextureBindings = std::unordered_map<BindingPoint, binding::Texture>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for storage textures
+using StorageTextureBindings = std::unordered_map<BindingPoint, binding::StorageTexture>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for samplers
+using SamplerBindings = std::unordered_map<BindingPoint, binding::Sampler>;
+/// Maps the WGSL binding point to the plane0, plane1, and metadata for external textures
+using ExternalTextureBindings = std::unordered_map<BindingPoint, binding::ExternalTexture>;
+
+/// Binding information
+struct Bindings {
+ /// Uniform bindings
+ UniformBindings uniform{};
+ /// Storage bindings
+ StorageBindings storage{};
+ /// Texture bindings
+ TextureBindings texture{};
+ /// Storage texture bindings
+ StorageTextureBindings storage_texture{};
+ /// Sampler bindings
+ SamplerBindings 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;
+
+ /// 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);
+};
+
+/// Ensure that all the fields of Bindings are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Bindings);
+
/// kMaxInterStageLocations == D3D11_PS_INPUT_REGISTER_COUNT - 2
/// D3D11_PS_INPUT_REGISTER_COUNT == D3D12_PS_INPUT_REGISTER_COUNT
constexpr uint32_t kMaxInterStageLocations = 30;
@@ -92,17 +193,8 @@
/// The binding point to use for information passed via root constants.
std::optional<BindingPoint> root_constant_binding_point;
- /// Options used in the binding mappings for external textures
- ExternalTextureOptions external_texture_options = {};
-
- /// Options used in the bindings remapper
- BindingRemapperOptions binding_remapper_options = {};
-
- /// The binding points that will be ignored in the rebustness transform.
- std::vector<BindingPoint> binding_points_ignored_in_robustness_transform;
-
- /// AccessControls is a map of old binding point to new access control
- std::unordered_map<BindingPoint, core::Access> access_controls;
+ /// The bindings
+ Bindings bindings;
/// Options used to deal with pixel local storage variables
PixelLocalOptions pixel_local_options = {};
@@ -119,10 +211,7 @@
array_length_from_uniform,
interstage_locations,
root_constant_binding_point,
- external_texture_options,
- binding_remapper_options,
- binding_points_ignored_in_robustness_transform,
- access_controls,
+ bindings,
pixel_local_options);
};
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.bazel b/src/tint/lang/hlsl/writer/helpers/BUILD.bazel
new file mode 100644
index 0000000..24a3b69
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.bazel
@@ -0,0 +1,76 @@
+# Copyright 2024 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "helpers",
+ srcs = [
+ "generate_bindings.cc",
+ ],
+ hdrs = [
+ "generate_bindings.h",
+ ],
+ 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/hlsl/writer/common",
+ "//src/tint/lang/wgsl",
+ "//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/features",
+ "//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",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.cmake b/src/tint/lang/hlsl/writer/helpers/BUILD.cmake
new file mode 100644
index 0000000..6332974
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.cmake
@@ -0,0 +1,71 @@
+# Copyright 2024 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_lang_hlsl_writer_helpers
+# Kind: lib
+################################################################################
+tint_add_target(tint_lang_hlsl_writer_helpers lib
+ lang/hlsl/writer/helpers/generate_bindings.cc
+ lang/hlsl/writer/helpers/generate_bindings.h
+)
+
+tint_target_add_dependencies(tint_lang_hlsl_writer_helpers lib
+ tint_api_common
+ tint_api_options
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_type
+ tint_lang_hlsl_writer_common
+ tint_lang_wgsl
+ tint_lang_wgsl_ast
+ tint_lang_wgsl_features
+ 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/hlsl/writer/helpers/BUILD.gn b/src/tint/lang/hlsl/writer/helpers/BUILD.gn
new file mode 100644
index 0000000..8583f77
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.gn
@@ -0,0 +1,72 @@
+# Copyright 2024 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+libtint_source_set("helpers") {
+ sources = [
+ "generate_bindings.cc",
+ "generate_bindings.h",
+ ]
+ 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/hlsl/writer/common",
+ "${tint_src_dir}/lang/wgsl",
+ "${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/features",
+ "${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/hlsl/writer/helpers/generate_bindings.cc b/src/tint/lang/hlsl/writer/helpers/generate_bindings.cc
new file mode 100644
index 0000000..b10d2f6
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/generate_bindings.cc
@@ -0,0 +1,121 @@
+// Copyright 2023 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.
+
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
+
+#include <algorithm>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "src/tint/api/common/binding_point.h"
+#include "src/tint/lang/core/type/external_texture.h"
+#include "src/tint/lang/core/type/storage_texture.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/program/program.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/utils/containers/hashmap.h"
+#include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace tint::hlsl::writer {
+
+Bindings GenerateBindings(const Program& program) {
+ // TODO(tint:1491): Use Inspector once we can get binding info for all
+ // variables, not just those referenced by entry points.
+
+ Bindings bindings{};
+
+ // Collect next valid binding number per group
+ Hashmap<uint32_t, uint32_t, 4> group_to_next_binding_number;
+ Vector<tint::BindingPoint, 4> ext_tex_bps;
+ for (auto* var : program.AST().GlobalVariables()) {
+ if (auto* sem_var = program.Sem().Get(var)->As<sem::GlobalVariable>()) {
+ if (auto bp = sem_var->Attributes().binding_point) {
+ if (auto val = group_to_next_binding_number.Get(bp->group)) {
+ *val = std::max(*val, bp->binding + 1);
+ } else {
+ group_to_next_binding_number.Add(bp->group, bp->binding + 1);
+ }
+
+ // Store up the external textures, we'll add them in the next step
+ if (sem_var->Type()->UnwrapRef()->Is<core::type::ExternalTexture>()) {
+ ext_tex_bps.Push(*bp);
+ continue;
+ }
+
+ binding::BindingInfo info{bp->group, bp->binding};
+ switch (sem_var->AddressSpace()) {
+ case core::AddressSpace::kHandle:
+ Switch(
+ sem_var->Type()->UnwrapRef(), //
+ [&](const core::type::Sampler*) {
+ bindings.sampler.emplace(*bp, info);
+ },
+ [&](const core::type::StorageTexture*) {
+ bindings.storage_texture.emplace(*bp, info);
+ },
+ [&](const core::type::Texture*) {
+ bindings.texture.emplace(*bp, info);
+ });
+ break;
+ case core::AddressSpace::kStorage:
+ bindings.storage.emplace(*bp, info);
+ break;
+ case core::AddressSpace::kUniform:
+ bindings.uniform.emplace(*bp, info);
+ break;
+
+ case core::AddressSpace::kUndefined:
+ case core::AddressSpace::kPixelLocal:
+ case core::AddressSpace::kPrivate:
+ case core::AddressSpace::kPushConstant:
+ case core::AddressSpace::kIn:
+ case core::AddressSpace::kOut:
+ case core::AddressSpace::kFunction:
+ case core::AddressSpace::kWorkgroup:
+ break;
+ }
+ }
+ }
+ }
+
+ for (auto bp : ext_tex_bps) {
+ uint32_t g = bp.group;
+ uint32_t& next_num = group_to_next_binding_number.GetOrAddZero(g);
+
+ binding::BindingInfo plane0{bp.group, bp.binding};
+ binding::BindingInfo plane1{g, next_num++};
+ binding::BindingInfo metadata{g, next_num++};
+
+ bindings.external_texture.emplace(bp, binding::ExternalTexture{metadata, plane0, plane1});
+ }
+
+ return bindings;
+}
+
+} // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/helpers/generate_bindings.h b/src/tint/lang/hlsl/writer/helpers/generate_bindings.h
new file mode 100644
index 0000000..249075a
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/generate_bindings.h
@@ -0,0 +1,44 @@
+// Copyright 2023 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_LANG_HLSL_WRITER_HELPERS_GENERATE_BINDINGS_H_
+#define SRC_TINT_LANG_HLSL_WRITER_HELPERS_GENERATE_BINDINGS_H_
+
+#include "src/tint/lang/hlsl/writer/common/options.h"
+
+// Forward declarations
+namespace tint {
+class Program;
+}
+
+namespace tint::hlsl::writer {
+
+Bindings GenerateBindings(const Program& program);
+
+} // namespace tint::hlsl::writer
+
+#endif // SRC_TINT_LANG_HLSL_WRITER_HELPERS_GENERATE_BINDINGS_H_
diff --git a/src/tint/lang/msl/writer/common/option_helpers.cc b/src/tint/lang/msl/writer/common/option_helpers.cc
index 433f256..d72d984 100644
--- a/src/tint/lang/msl/writer/common/option_helpers.cc
+++ b/src/tint/lang/msl/writer/common/option_helpers.cc
@@ -164,7 +164,7 @@
auto create_remappings = [&remapper_data](const auto& hsh) {
for (const auto& it : hsh) {
const BindingPoint& src_binding_point = it.first;
- const binding::Uniform& dst_binding_point = it.second;
+ const binding::BindingInfo& dst_binding_point = it.second;
// Bindings which go to the same slot in MSL do not need to be re-bound.
if (src_binding_point.group == 0 &&
@@ -210,19 +210,3 @@
}
} // namespace tint::msl::writer
-
-namespace std {
-
-/// Custom std::hash specialization for tint::msl::writer::binding::BindingInfo so
-/// they can be used as keys for std::unordered_map and std::unordered_set.
-template <>
-class hash<tint::msl::writer::binding::BindingInfo> {
- public:
- /// @param info the binding to create a hash for
- /// @return the hash value
- inline std::size_t operator()(const tint::msl::writer::binding::BindingInfo& info) const {
- return tint::Hash(info.binding);
- }
-};
-
-} // namespace std
diff --git a/src/tint/lang/msl/writer/common/options.h b/src/tint/lang/msl/writer/common/options.h
index 3b359ab..2f5e770 100644
--- a/src/tint/lang/msl/writer/common/options.h
+++ b/src/tint/lang/msl/writer/common/options.h
@@ -52,6 +52,9 @@
/// @returns true if this BindingInfo is not equal to `rhs`
inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
+ /// @returns the hash code of the BindingInfo
+ size_t HashCode() const { return Hash(binding); }
+
/// Reflect the fields of this class so taht it can be used by tint::ForeachField()
TINT_REFLECT(BindingInfo, binding);
};
diff --git a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
index 346f46d..d76a591 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
@@ -109,10 +109,7 @@
RemapperData remapper_data{};
PopulateRemapperAndMultiplanarOptions(options, remapper_data, external_texture_options);
- // BindingRemapper must come before MultiplanarExternalTexture. Note, this is flipped to the
- // other generators which run Multiplanar first and then binding remapper.
manager.Add<ast::transform::BindingRemapper>();
-
data.Add<ast::transform::BindingRemapper::Remappings>(
remapper_data, std::unordered_map<BindingPoint, core::Access>{},
/* allow_collisions */ false);
diff --git a/src/tint/lang/spirv/writer/common/option_helper.cc b/src/tint/lang/spirv/writer/common/option_helper.cc
index 93873c3..37f2377 100644
--- a/src/tint/lang/spirv/writer/common/option_helper.cc
+++ b/src/tint/lang/spirv/writer/common/option_helper.cc
@@ -187,7 +187,7 @@
auto create_remappings = [&remapper_data](const auto& hsh) {
for (const auto& it : hsh) {
const BindingPoint& src_binding_point = it.first;
- const binding::Uniform& dst_binding_point = it.second;
+ const binding::BindingInfo& dst_binding_point = it.second;
// Bindings which go to the same slot in SPIR-V do not need to be re-bound.
if (src_binding_point.group == dst_binding_point.group &&
@@ -233,19 +233,3 @@
}
} // namespace tint::spirv::writer
-
-namespace std {
-
-/// Custom std::hash specialization for tint::spirv::writer::binding::BindingInfo so
-/// they can be used as keys for std::unordered_map and std::unordered_set.
-template <>
-class hash<tint::spirv::writer::binding::BindingInfo> {
- public:
- /// @param info the binding to create a hash for
- /// @return the hash value
- inline std::size_t operator()(const tint::spirv::writer::binding::BindingInfo& info) const {
- return tint::Hash(info.group, info.binding);
- }
-};
-
-} // namespace std
diff --git a/src/tint/lang/spirv/writer/common/options.h b/src/tint/lang/spirv/writer/common/options.h
index 4fcbafe..0fd6f8c 100644
--- a/src/tint/lang/spirv/writer/common/options.h
+++ b/src/tint/lang/spirv/writer/common/options.h
@@ -54,6 +54,9 @@
/// @returns true if this BindingInfo is not equal to `rhs`
inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
+ /// @returns the hash code of the BindingInfo
+ size_t HashCode() const { return Hash(group, binding); }
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(BindingInfo, group, binding);
};