Use std::variant in ShaderBindingInfo
This patch uses std::variant to represent 4 possible member types in
ShaderBindingInfo (BufferBindingLayout, ShaderSamplerBindingInfo,
ShaderTextureBindingInfo, StorageTextureBindingLayout) as logically
at any time only one of them can be used.
Bug: dawn:527
Change-Id: Iad9eaef9706e797cd3db57761dba370047a92fc5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/171220
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn/native/PipelineLayout.cpp b/src/dawn/native/PipelineLayout.cpp
index 294d15a..f2bf900 100644
--- a/src/dawn/native/PipelineLayout.cpp
+++ b/src/dawn/native/PipelineLayout.cpp
@@ -232,57 +232,60 @@
const ExternalTextureBindingLayout* externalTextureBindingEntry)
-> BindGroupLayoutEntry {
BindGroupLayoutEntry entry = {};
- switch (shaderBinding.bindingType) {
- case BindingInfoType::Buffer:
- entry.buffer.type = shaderBinding.buffer.type;
- entry.buffer.hasDynamicOffset = shaderBinding.buffer.hasDynamicOffset;
- entry.buffer.minBindingSize = shaderBinding.buffer.minBindingSize;
- break;
- case BindingInfoType::Sampler:
- if (shaderBinding.sampler.isComparison) {
- entry.sampler.type = wgpu::SamplerBindingType::Comparison;
- } else {
- entry.sampler.type = wgpu::SamplerBindingType::Filtering;
- }
- break;
- case BindingInfoType::Texture:
- switch (shaderBinding.texture.compatibleSampleTypes) {
- case SampleTypeBit::Depth:
- entry.texture.sampleType = wgpu::TextureSampleType::Depth;
- break;
- case SampleTypeBit::Sint:
- entry.texture.sampleType = wgpu::TextureSampleType::Sint;
- break;
- case SampleTypeBit::Uint:
- entry.texture.sampleType = wgpu::TextureSampleType::Uint;
- break;
- case SampleTypeBit::Float:
- case SampleTypeBit::UnfilterableFloat:
- case SampleTypeBit::None:
- DAWN_UNREACHABLE();
- break;
- default:
- if (shaderBinding.texture.compatibleSampleTypes ==
- (SampleTypeBit::Float | SampleTypeBit::UnfilterableFloat)) {
- // Default to UnfilterableFloat. It will be promoted to Float if it
- // is used with a sampler.
- entry.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
- } else {
+
+ // TODO(dawn:2370): implement a helper in dawn/utils to simplify the call of std::visit.
+ std::visit(
+ [&](const auto& bindingInfo) {
+ using T = std::decay_t<decltype(bindingInfo)>;
+
+ if constexpr (std::is_same_v<T, BufferBindingInfo>) {
+ entry.buffer.type = bindingInfo.type;
+ entry.buffer.minBindingSize = bindingInfo.minBindingSize;
+ } else if constexpr (std::is_same_v<T, SamplerBindingInfo>) {
+ if (bindingInfo.isComparison) {
+ entry.sampler.type = wgpu::SamplerBindingType::Comparison;
+ } else {
+ entry.sampler.type = wgpu::SamplerBindingType::Filtering;
+ }
+ } else if constexpr (std::is_same_v<T, SampledTextureBindingInfo>) {
+ switch (bindingInfo.compatibleSampleTypes) {
+ case SampleTypeBit::Depth:
+ entry.texture.sampleType = wgpu::TextureSampleType::Depth;
+ break;
+ case SampleTypeBit::Sint:
+ entry.texture.sampleType = wgpu::TextureSampleType::Sint;
+ break;
+ case SampleTypeBit::Uint:
+ entry.texture.sampleType = wgpu::TextureSampleType::Uint;
+ break;
+ case SampleTypeBit::Float:
+ case SampleTypeBit::UnfilterableFloat:
+ case SampleTypeBit::None:
DAWN_UNREACHABLE();
- }
+ break;
+ default:
+ if (bindingInfo.compatibleSampleTypes ==
+ (SampleTypeBit::Float | SampleTypeBit::UnfilterableFloat)) {
+ // Default to UnfilterableFloat. It will be promoted to Float if it
+ // is used with a sampler.
+ entry.texture.sampleType =
+ wgpu::TextureSampleType::UnfilterableFloat;
+ } else {
+ DAWN_UNREACHABLE();
+ }
+ }
+ entry.texture.viewDimension = bindingInfo.viewDimension;
+ entry.texture.multisampled = bindingInfo.multisampled;
+ } else if constexpr (std::is_same_v<T, StorageTextureBindingInfo>) {
+ entry.storageTexture.access = bindingInfo.access;
+ entry.storageTexture.format = bindingInfo.format;
+ entry.storageTexture.viewDimension = bindingInfo.viewDimension;
+ } else if constexpr (std::is_same_v<T, ExternalTextureBindingInfo>) {
+ entry.nextInChain = externalTextureBindingEntry;
}
- entry.texture.viewDimension = shaderBinding.texture.viewDimension;
- entry.texture.multisampled = shaderBinding.texture.multisampled;
- break;
- case BindingInfoType::StorageTexture:
- entry.storageTexture.access = shaderBinding.storageTexture.access;
- entry.storageTexture.format = shaderBinding.storageTexture.format;
- entry.storageTexture.viewDimension = shaderBinding.storageTexture.viewDimension;
- break;
- case BindingInfoType::ExternalTexture:
- entry.nextInChain = externalTextureBindingEntry;
- break;
- }
+ },
+ shaderBinding.bindingInfo);
+
return entry;
};
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 193c992..371d7f5 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -394,7 +394,13 @@
DAWN_ASSERT(packedIdx < requiredBufferSizes.size());
const auto& shaderInfo = shaderBindings.find(bindingInfo.binding);
if (shaderInfo != shaderBindings.end()) {
- requiredBufferSizes[packedIdx] = shaderInfo->second.buffer.minBindingSize;
+ auto* shaderBufferInfo =
+ std::get_if<BufferBindingInfo>(&shaderInfo->second.bindingInfo);
+ if (shaderBufferInfo != nullptr) {
+ requiredBufferSizes[packedIdx] = shaderBufferInfo->minBindingSize;
+ } else {
+ requiredBufferSizes[packedIdx] = 0;
+ }
} else {
// We have to include buffers if they are included in the bind group's
// packed vector. We don't actually need to check these at draw time, so
@@ -409,10 +415,36 @@
bool IsShaderCompatibleWithPipelineLayoutOnStorageTextureAccess(
const BindingInfo& bindingInfo,
- const ShaderBindingInfo& shaderBindingInfo) {
- return bindingInfo.storageTexture.access == shaderBindingInfo.storageTexture.access ||
+ const StorageTextureBindingInfo& bindingLayout) {
+ return bindingInfo.storageTexture.access == bindingLayout.access ||
(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::ReadWrite &&
- shaderBindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly);
+ bindingLayout.access == wgpu::StorageTextureAccess::WriteOnly);
+}
+
+BindingInfoType GetShaderBindingType(const ShaderBindingInfo& shaderInfo) {
+ return std::visit(
+ [](const auto& bindingInfo) -> BindingInfoType {
+ using T = std::decay_t<decltype(bindingInfo)>;
+
+ if constexpr (std::is_same_v<T, BufferBindingInfo>) {
+ return BindingInfoType::Buffer;
+ }
+ if constexpr (std::is_same_v<T, StorageTextureBindingInfo>) {
+ return BindingInfoType::StorageTexture;
+ }
+ if constexpr (std::is_same_v<T, SampledTextureBindingInfo>) {
+ return BindingInfoType::Texture;
+ }
+ if constexpr (std::is_same_v<T, SamplerBindingInfo>) {
+ return BindingInfoType::Sampler;
+ }
+ if constexpr (std::is_same_v<T, ExternalTextureBindingInfo>) {
+ return BindingInfoType::ExternalTexture;
+ }
+ DAWN_UNREACHABLE();
+ return BindingInfoType::Buffer;
+ },
+ shaderInfo.bindingInfo);
}
MaybeError ValidateCompatibilityOfSingleBindingWithLayout(const DeviceBase* device,
@@ -427,7 +459,7 @@
// the shader and bgl will always mismatch at this point. Expansion info is contained in
// the bgl object, so we can still verify the bgl used to have an external texture in
// the slot corresponding to the shader reflection.
- if (shaderInfo.bindingType == BindingInfoType::ExternalTexture) {
+ if (std::holds_alternative<ExternalTextureBindingInfo>(shaderInfo.bindingInfo)) {
// If an external texture binding used to exist in the bgl, it will be found as a
// key in the ExternalTextureBindingExpansions map.
ExternalTextureBindingExpansionMap expansions =
@@ -448,9 +480,10 @@
BindingIndex bindingIndex(bindingIt->second);
const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex);
- DAWN_INVALID_IF(layoutInfo.bindingType != shaderInfo.bindingType,
+ BindingInfoType shaderBindingType = GetShaderBindingType(shaderInfo);
+ DAWN_INVALID_IF(layoutInfo.bindingType != shaderBindingType,
"Binding type in the shader (%s) doesn't match the type in the layout (%s).",
- shaderInfo.bindingType, layoutInfo.bindingType);
+ shaderBindingType, layoutInfo.bindingType);
ExternalTextureBindingExpansionMap expansions = layout->GetExternalTextureBindingExpansionMap();
DAWN_INVALID_IF(expansions.find(bindingNumber) != expansions.end(),
@@ -461,100 +494,96 @@
"Entry point's stage (%s) is not in the binding visibility in the layout (%s).",
StageBit(entryPointStage), layoutInfo.visibility);
- switch (layoutInfo.bindingType) {
- case BindingInfoType::Texture: {
- DAWN_INVALID_IF(
- layoutInfo.texture.multisampled != shaderInfo.texture.multisampled,
- "Binding multisampled flag (%u) doesn't match the layout's multisampled "
- "flag (%u)",
- layoutInfo.texture.multisampled, shaderInfo.texture.multisampled);
+ // TODO(dawn:2370): implement a helper in dawn/utils to simplify the call of std::visit.
+ return std::visit(
+ [&](const auto& bindingInfo) -> MaybeError {
+ using T = std::decay_t<decltype(bindingInfo)>;
- // TODO(dawn:563): Provide info about the sample types.
- SampleTypeBit requiredType;
- if (layoutInfo.texture.sampleType == kInternalResolveAttachmentSampleType) {
- // If the layout's texture's sample type is kInternalResolveAttachmentSampleType,
- // then the shader's compatible sample types must contain float.
- requiredType = SampleTypeBit::UnfilterableFloat;
- } else {
- requiredType = SampleTypeToSampleTypeBit(layoutInfo.texture.sampleType);
+ if constexpr (std::is_same_v<T, SampledTextureBindingInfo>) {
+ DAWN_INVALID_IF(
+ layoutInfo.texture.multisampled != bindingInfo.multisampled,
+ "Binding multisampled flag (%u) doesn't match the layout's multisampled "
+ "flag (%u)",
+ layoutInfo.texture.multisampled, bindingInfo.multisampled);
+
+ // TODO(dawn:563): Provide info about the sample types.
+ SampleTypeBit requiredType;
+ if (layoutInfo.texture.sampleType == kInternalResolveAttachmentSampleType) {
+ // If the layout's texture's sample type is
+ // kInternalResolveAttachmentSampleType, then the shader's compatible sample
+ // types must contain float.
+ requiredType = SampleTypeBit::UnfilterableFloat;
+ } else {
+ requiredType = SampleTypeToSampleTypeBit(layoutInfo.texture.sampleType);
+ }
+
+ DAWN_INVALID_IF(!(bindingInfo.compatibleSampleTypes & requiredType),
+ "The sample type in the shader is not compatible with the "
+ "sample type of the layout.");
+
+ DAWN_INVALID_IF(
+ layoutInfo.texture.viewDimension != bindingInfo.viewDimension,
+ "The shader's binding dimension (%s) doesn't match the shader's binding "
+ "dimension (%s).",
+ layoutInfo.texture.viewDimension, bindingInfo.viewDimension);
+ } else if constexpr (std::is_same_v<T, StorageTextureBindingInfo>) {
+ DAWN_ASSERT(layoutInfo.storageTexture.format != wgpu::TextureFormat::Undefined);
+ DAWN_ASSERT(bindingInfo.format != wgpu::TextureFormat::Undefined);
+
+ DAWN_INVALID_IF(
+ !IsShaderCompatibleWithPipelineLayoutOnStorageTextureAccess(layoutInfo,
+ bindingInfo),
+ "The layout's binding access (%s) isn't compatible with the shader's "
+ "binding access (%s).",
+ layoutInfo.storageTexture.access, bindingInfo.access);
+
+ DAWN_INVALID_IF(
+ layoutInfo.storageTexture.format != bindingInfo.format,
+ "The layout's binding format (%s) doesn't match the shader's binding "
+ "format (%s).",
+ layoutInfo.storageTexture.format, bindingInfo.format);
+
+ DAWN_INVALID_IF(
+ layoutInfo.storageTexture.viewDimension != bindingInfo.viewDimension,
+ "The layout's binding dimension (%s) doesn't match the "
+ "shader's binding dimension (%s).",
+ layoutInfo.storageTexture.viewDimension, bindingInfo.viewDimension);
+ } else if constexpr (std::is_same_v<T, BufferBindingInfo>) {
+ // Binding mismatch between shader and bind group is invalid. For example, a
+ // writable binding in the shader with a readonly storage buffer in the bind
+ // group layout is invalid. For internal usage with internal shaders, a storage
+ // binding in the shader with an internal storage buffer in the bind group
+ // layout is also valid.
+ bool validBindingConversion =
+ (layoutInfo.buffer.type == kInternalStorageBufferBinding &&
+ bindingInfo.type == wgpu::BufferBindingType::Storage);
+
+ DAWN_INVALID_IF(
+ layoutInfo.buffer.type != bindingInfo.type && !validBindingConversion,
+ "The buffer type in the shader (%s) is not compatible with the type in the "
+ "layout (%s).",
+ bindingInfo.type, layoutInfo.buffer.type);
+
+ DAWN_INVALID_IF(layoutInfo.buffer.minBindingSize != 0 &&
+ bindingInfo.minBindingSize > layoutInfo.buffer.minBindingSize,
+ "The shader uses more bytes of the buffer (%u) than the layout's "
+ "minBindingSize (%u).",
+ bindingInfo.minBindingSize, layoutInfo.buffer.minBindingSize);
+ } else if constexpr (std::is_same_v<T, SamplerBindingInfo>) {
+ DAWN_INVALID_IF(
+ (layoutInfo.sampler.type == wgpu::SamplerBindingType::Comparison) !=
+ bindingInfo.isComparison,
+ "The sampler type in the shader (comparison: %u) doesn't match the type in "
+ "the layout (comparison: %u).",
+ bindingInfo.isComparison,
+ layoutInfo.sampler.type == wgpu::SamplerBindingType::Comparison);
+ } else if constexpr (std::is_same_v<T, ExternalTextureBindingInfo>) {
+ DAWN_UNREACHABLE();
}
- DAWN_INVALID_IF(!(shaderInfo.texture.compatibleSampleTypes & requiredType),
- "The sample type in the shader is not compatible with the "
- "sample type of the layout.");
-
- DAWN_INVALID_IF(
- layoutInfo.texture.viewDimension != shaderInfo.texture.viewDimension,
- "The shader's binding dimension (%s) doesn't match the shader's binding "
- "dimension (%s).",
- layoutInfo.texture.viewDimension, shaderInfo.texture.viewDimension);
- break;
- }
-
- case BindingInfoType::StorageTexture: {
- DAWN_ASSERT(layoutInfo.storageTexture.format != wgpu::TextureFormat::Undefined);
- DAWN_ASSERT(shaderInfo.storageTexture.format != wgpu::TextureFormat::Undefined);
-
- DAWN_INVALID_IF(
- !IsShaderCompatibleWithPipelineLayoutOnStorageTextureAccess(layoutInfo, shaderInfo),
- "The layout's binding access (%s) isn't compatible with the shader's "
- "binding access (%s).",
- layoutInfo.storageTexture.access, shaderInfo.storageTexture.access);
-
- DAWN_INVALID_IF(layoutInfo.storageTexture.format != shaderInfo.storageTexture.format,
- "The layout's binding format (%s) doesn't match the shader's binding "
- "format (%s).",
- layoutInfo.storageTexture.format, shaderInfo.storageTexture.format);
-
- DAWN_INVALID_IF(
- layoutInfo.storageTexture.viewDimension != shaderInfo.storageTexture.viewDimension,
- "The layout's binding dimension (%s) doesn't match the "
- "shader's binding dimension (%s).",
- layoutInfo.storageTexture.viewDimension, shaderInfo.storageTexture.viewDimension);
- break;
- }
-
- case BindingInfoType::Buffer: {
- // Binding mismatch between shader and bind group is invalid. For example, a
- // writable binding in the shader with a readonly storage buffer in the bind
- // group layout is invalid. For internal usage with internal shaders, a storage
- // binding in the shader with an internal storage buffer in the bind group
- // layout is also valid.
- bool validBindingConversion =
- (layoutInfo.buffer.type == kInternalStorageBufferBinding &&
- shaderInfo.buffer.type == wgpu::BufferBindingType::Storage);
-
- DAWN_INVALID_IF(
- layoutInfo.buffer.type != shaderInfo.buffer.type && !validBindingConversion,
- "The buffer type in the shader (%s) is not compatible with the type in the "
- "layout (%s).",
- shaderInfo.buffer.type, layoutInfo.buffer.type);
-
- DAWN_INVALID_IF(layoutInfo.buffer.minBindingSize != 0 &&
- shaderInfo.buffer.minBindingSize > layoutInfo.buffer.minBindingSize,
- "The shader uses more bytes of the buffer (%u) than the layout's "
- "minBindingSize (%u).",
- shaderInfo.buffer.minBindingSize, layoutInfo.buffer.minBindingSize);
- break;
- }
-
- case BindingInfoType::Sampler:
- DAWN_INVALID_IF(
- (layoutInfo.sampler.type == wgpu::SamplerBindingType::Comparison) !=
- shaderInfo.sampler.isComparison,
- "The sampler type in the shader (comparison: %u) doesn't match the type in "
- "the layout (comparison: %u).",
- shaderInfo.sampler.isComparison,
- layoutInfo.sampler.type == wgpu::SamplerBindingType::Comparison);
- break;
-
- case BindingInfoType::ExternalTexture: {
- DAWN_UNREACHABLE();
- break;
- }
- }
-
- return {};
+ return {};
+ },
+ shaderInfo.bindingInfo);
}
MaybeError ValidateCompatibilityWithBindGroupLayout(DeviceBase* device,
BindGroupIndex group,
@@ -813,60 +842,77 @@
inspector->GetResourceBindings(entryPoint.name)) {
ShaderBindingInfo info;
- info.bindingType = TintResourceTypeToBindingInfoType(resource.resource_type);
info.name = resource.variable_name;
- switch (info.bindingType) {
- case BindingInfoType::Buffer:
- info.buffer.minBindingSize = resource.size;
- DAWN_TRY_ASSIGN(info.buffer.type,
+ switch (TintResourceTypeToBindingInfoType(resource.resource_type)) {
+ case BindingInfoType::Buffer: {
+ BufferBindingInfo bindingInfo = {};
+ bindingInfo.minBindingSize = resource.size;
+ DAWN_TRY_ASSIGN(bindingInfo.type,
TintResourceTypeToBufferBindingType(resource.resource_type));
+ info.bindingInfo = bindingInfo;
break;
- case BindingInfoType::Sampler:
+ }
+
+ case BindingInfoType::Sampler: {
+ SamplerBindingInfo bindingInfo = {};
switch (resource.resource_type) {
case tint::inspector::ResourceBinding::ResourceType::kSampler:
- info.sampler.isComparison = false;
+ bindingInfo.isComparison = false;
break;
case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
- info.sampler.isComparison = true;
+ bindingInfo.isComparison = true;
break;
default:
DAWN_UNREACHABLE();
}
+ info.bindingInfo = bindingInfo;
break;
- case BindingInfoType::Texture:
- info.texture.viewDimension =
+ }
+
+ case BindingInfoType::Texture: {
+ SampledTextureBindingInfo bindingInfo = {};
+ bindingInfo.viewDimension =
TintTextureDimensionToTextureViewDimension(resource.dim);
if (resource.resource_type ==
tint::inspector::ResourceBinding::ResourceType::kDepthTexture ||
resource.resource_type ==
tint::inspector::ResourceBinding::ResourceType::kDepthMultisampledTexture) {
- info.texture.compatibleSampleTypes = SampleTypeBit::Depth;
+ bindingInfo.compatibleSampleTypes = SampleTypeBit::Depth;
} else {
- info.texture.compatibleSampleTypes =
+ bindingInfo.compatibleSampleTypes =
TintSampledKindToSampleTypeBit(resource.sampled_kind);
}
- info.texture.multisampled =
+ bindingInfo.multisampled =
resource.resource_type ==
tint::inspector::ResourceBinding::ResourceType::kMultisampledTexture ||
resource.resource_type ==
tint::inspector::ResourceBinding::ResourceType::kDepthMultisampledTexture;
-
+ info.bindingInfo = bindingInfo;
break;
- case BindingInfoType::StorageTexture:
- DAWN_TRY_ASSIGN(info.storageTexture.access,
+ }
+
+ case BindingInfoType::StorageTexture: {
+ StorageTextureBindingInfo bindingInfo = {};
+ DAWN_TRY_ASSIGN(bindingInfo.access,
TintResourceTypeToStorageTextureAccess(resource.resource_type));
- info.storageTexture.format = TintImageFormatToTextureFormat(resource.image_format);
- info.storageTexture.viewDimension =
+ bindingInfo.format = TintImageFormatToTextureFormat(resource.image_format);
+ bindingInfo.viewDimension =
TintTextureDimensionToTextureViewDimension(resource.dim);
- DAWN_INVALID_IF(info.storageTexture.format == wgpu::TextureFormat::BGRA8Unorm &&
+ DAWN_INVALID_IF(bindingInfo.format == wgpu::TextureFormat::BGRA8Unorm &&
!device->HasFeature(Feature::BGRA8UnormStorage),
"BGRA8Unorm storage textures are not supported if optional feature "
"bgra8unorm-storage is not supported.");
+
+ info.bindingInfo = bindingInfo;
break;
- case BindingInfoType::ExternalTexture:
+ }
+
+ case BindingInfoType::ExternalTexture: {
+ info.bindingInfo.emplace<ExternalTextureBindingInfo>();
break;
+ }
default:
return DAWN_VALIDATION_ERROR("Unknown binding type in Shader");
}
diff --git a/src/dawn/native/ShaderModule.h b/src/dawn/native/ShaderModule.h
index 5847e98..c31a16c 100644
--- a/src/dawn/native/ShaderModule.h
+++ b/src/dawn/native/ShaderModule.h
@@ -33,6 +33,7 @@
#include <memory>
#include <string>
#include <utility>
+#include <variant>
#include <vector>
#include "absl/container/flat_hash_map.h"
@@ -156,18 +157,34 @@
// Mirrors wgpu::SamplerBindingLayout but instead stores a single boolean
// for isComparison instead of a wgpu::SamplerBindingType enum.
-struct ShaderSamplerBindingInfo {
+struct SamplerBindingInfo {
bool isComparison;
};
// Mirrors wgpu::TextureBindingLayout but instead has a set of compatible sampleTypes
// instead of a single enum.
-struct ShaderTextureBindingInfo {
+struct SampledTextureBindingInfo {
SampleTypeBit compatibleSampleTypes;
wgpu::TextureViewDimension viewDimension;
bool multisampled;
};
+// Mirrors wgpu::ExternalTextureBindingLayout
+struct ExternalTextureBindingInfo {};
+
+// Mirrors wgpu::BufferBindingLayout
+struct BufferBindingInfo {
+ wgpu::BufferBindingType type;
+ uint64_t minBindingSize;
+};
+
+// Mirrors wgpu::StorageTextureBindingLayout
+struct StorageTextureBindingInfo {
+ wgpu::TextureFormat format;
+ wgpu::TextureViewDimension viewDimension;
+ wgpu::StorageTextureAccess access;
+};
+
// Per-binding shader metadata contains some SPIRV specific information in addition to
// most of the frontend per-binding information.
struct ShaderBindingInfo {
@@ -176,15 +193,16 @@
uint32_t base_type_id;
BindingNumber binding;
- BindingInfoType bindingType;
// The variable name of the binding resource.
std::string name;
- BufferBindingLayout buffer;
- ShaderSamplerBindingInfo sampler;
- ShaderTextureBindingInfo texture;
- StorageTextureBindingLayout storageTexture;
+ std::variant<BufferBindingInfo,
+ SamplerBindingInfo,
+ SampledTextureBindingInfo,
+ StorageTextureBindingInfo,
+ ExternalTextureBindingInfo>
+ bindingInfo;
};
using BindingGroupInfoMap = std::map<BindingNumber, ShaderBindingInfo>;
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index 408a45b..6bf7ba7 100644
--- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -195,7 +195,7 @@
// the Tint AST to make the "bindings" decoration match the offset chosen by
// d3d12::BindGroupLayout so that Tint produces HLSL with the correct registers
// assigned to each interface variable.
- for (const auto& [binding, bindingInfo] : moduleGroupBindingInfo) {
+ for (const auto& [binding, shaderBindingInfo] : moduleGroupBindingInfo) {
BindingIndex bindingIndex = bgl->GetBindingIndex(binding);
BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
static_cast<uint32_t>(binding)};
@@ -205,12 +205,18 @@
bindingRemapper.binding_points.emplace(srcBindingPoint, dstBindingPoint);
}
+ const auto* bufferBindingInfo =
+ std::get_if<BufferBindingInfo>(&shaderBindingInfo.bindingInfo);
+ if (bufferBindingInfo == nullptr) {
+ continue;
+ }
+
// 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 =
- (bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage &&
+ (bufferBindingInfo->type == wgpu::BufferBindingType::ReadOnlyStorage &&
(bgl->GetBindingInfo(bindingIndex).buffer.type ==
wgpu::BufferBindingType::Storage ||
bgl->GetBindingInfo(bindingIndex).buffer.type == kInternalStorageBufferBinding));
@@ -242,8 +248,8 @@
// }
// return 0u;
// }
- if ((bindingInfo.buffer.type == wgpu::BufferBindingType::Storage ||
- bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage) &&
+ if ((bufferBindingInfo->type == wgpu::BufferBindingType::Storage ||
+ bufferBindingInfo->type == wgpu::BufferBindingType::ReadOnlyStorage) &&
!bgl->GetBindingInfo(bindingIndex).buffer.hasDynamicOffset) {
req.hlsl.tintOptions.binding_points_ignored_in_robustness_transform.emplace_back(
srcBindingPoint);
@@ -351,7 +357,7 @@
// outside of the compilation.
d3d::CompiledShader result = compiledShader.Acquire();
result.hlslSource = "";
- return result;
+ return std::move(result);
}
} // namespace dawn::native::d3d12
diff --git a/src/dawn/native/metal/ShaderModuleMTL.mm b/src/dawn/native/metal/ShaderModuleMTL.mm
index 7eea7d4..82b9312 100644
--- a/src/dawn/native/metal/ShaderModuleMTL.mm
+++ b/src/dawn/native/metal/ShaderModuleMTL.mm
@@ -132,7 +132,7 @@
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
- for (const auto& [binding, bindingInfo] : moduleBindingInfo[group]) {
+ for (const auto& [binding, shaderBindingInfo] : moduleBindingInfo[group]) {
tint::BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
static_cast<uint32_t>(binding)};
@@ -142,68 +142,65 @@
tint::BindingPoint dstBindingPoint{0, shaderIndex};
- // Use the ShaderIndex as the indices for the buffer size lookups in the array length
- // uniform transform. This is used to compute the size of variable length arrays in
- // storage buffers.
- if (bindingInfo.buffer.type == wgpu::BufferBindingType::Storage ||
- bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage ||
- bindingInfo.buffer.type == kInternalStorageBufferBinding) {
- arrayLengthFromUniform.bindpoint_to_size_index.emplace(dstBindingPoint,
- dstBindingPoint.binding);
- }
+ // TODO(dawn:2370): implement a helper in dawn/utils to simplify the call of std::visit.
+ std::visit(
+ [&](const auto& bindingInfo) {
+ using T = std::decay_t<decltype(bindingInfo)>;
- switch (bindingInfo.bindingType) {
- case BindingInfoType::Buffer:
- switch (bindingInfo.buffer.type) {
- case wgpu::BufferBindingType::Uniform:
- bindings.uniform.emplace(
- srcBindingPoint,
- tint::msl::writer::binding::Uniform{dstBindingPoint.binding});
- break;
- case kInternalStorageBufferBinding:
- case wgpu::BufferBindingType::Storage:
- case wgpu::BufferBindingType::ReadOnlyStorage:
- bindings.storage.emplace(
- srcBindingPoint,
- tint::msl::writer::binding::Storage{dstBindingPoint.binding});
- break;
- case wgpu::BufferBindingType::Undefined:
- DAWN_UNREACHABLE();
- break;
+ if constexpr (std::is_same_v<T, BufferBindingInfo>) {
+ switch (bindingInfo.type) {
+ case wgpu::BufferBindingType::Uniform:
+ bindings.uniform.emplace(
+ srcBindingPoint,
+ tint::msl::writer::binding::Uniform{dstBindingPoint.binding});
+ break;
+ case kInternalStorageBufferBinding:
+ case wgpu::BufferBindingType::Storage:
+ case wgpu::BufferBindingType::ReadOnlyStorage:
+ bindings.storage.emplace(
+ srcBindingPoint,
+ tint::msl::writer::binding::Storage{dstBindingPoint.binding});
+ // Use the ShaderIndex as the indices for the buffer size lookups in
+ // the array length uniform transform. This is used to compute the
+ // size of variable length arrays in storage buffers.
+ arrayLengthFromUniform.bindpoint_to_size_index.emplace(
+ dstBindingPoint, dstBindingPoint.binding);
+ break;
+ case wgpu::BufferBindingType::Undefined:
+ DAWN_UNREACHABLE();
+ break;
+ }
+ } else if constexpr (std::is_same_v<T, SamplerBindingInfo>) {
+ bindings.sampler.emplace(
+ srcBindingPoint,
+ tint::msl::writer::binding::Sampler{dstBindingPoint.binding});
+ } else if constexpr (std::is_same_v<T, SampledTextureBindingInfo>) {
+ bindings.texture.emplace(
+ srcBindingPoint,
+ tint::msl::writer::binding::Texture{dstBindingPoint.binding});
+ } else if constexpr (std::is_same_v<T, StorageTextureBindingInfo>) {
+ bindings.storage_texture.emplace(
+ srcBindingPoint,
+ tint::msl::writer::binding::StorageTexture{dstBindingPoint.binding});
+ } else if constexpr (std::is_same_v<T, ExternalTextureBindingInfo>) {
+ const auto& etBindingMap = bgl->GetExternalTextureBindingExpansionMap();
+ const auto& expansion = etBindingMap.find(binding);
+ DAWN_ASSERT(expansion != etBindingMap.end());
+
+ const auto& bindingExpansion = expansion->second;
+ tint::msl::writer::binding::BindingInfo plane0{
+ static_cast<uint32_t>(shaderIndex)};
+ tint::msl::writer::binding::BindingInfo plane1{
+ bindingIndexInfo[bgl->GetBindingIndex(bindingExpansion.plane1)]};
+ tint::msl::writer::binding::BindingInfo metadata{
+ bindingIndexInfo[bgl->GetBindingIndex(bindingExpansion.params)]};
+
+ bindings.external_texture.emplace(
+ srcBindingPoint,
+ tint::msl::writer::binding::ExternalTexture{metadata, plane0, plane1});
}
- break;
- case BindingInfoType::Sampler:
- bindings.sampler.emplace(srcBindingPoint, tint::msl::writer::binding::Sampler{
- dstBindingPoint.binding});
- break;
- case BindingInfoType::Texture:
- bindings.texture.emplace(srcBindingPoint, tint::msl::writer::binding::Texture{
- dstBindingPoint.binding});
- break;
- case BindingInfoType::StorageTexture:
- bindings.storage_texture.emplace(
- srcBindingPoint,
- tint::msl::writer::binding::StorageTexture{dstBindingPoint.binding});
- break;
- case BindingInfoType::ExternalTexture: {
- const auto& etBindingMap = bgl->GetExternalTextureBindingExpansionMap();
- const auto& expansion = etBindingMap.find(binding);
- DAWN_ASSERT(expansion != etBindingMap.end());
-
- const auto& bindingExpansion = expansion->second;
- tint::msl::writer::binding::BindingInfo plane0{
- static_cast<uint32_t>(shaderIndex)};
- tint::msl::writer::binding::BindingInfo plane1{
- bindingIndexInfo[bgl->GetBindingIndex(bindingExpansion.plane1)]};
- tint::msl::writer::binding::BindingInfo metadata{
- bindingIndexInfo[bgl->GetBindingIndex(bindingExpansion.params)]};
-
- bindings.external_texture.emplace(
- srcBindingPoint,
- tint::msl::writer::binding::ExternalTexture{metadata, plane0, plane1});
- break;
- }
- }
+ },
+ shaderBindingInfo.bindingInfo);
}
}
diff --git a/src/dawn/native/opengl/ShaderModuleGL.cpp b/src/dawn/native/opengl/ShaderModuleGL.cpp
index 821a350..9c39077 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -206,7 +206,7 @@
// For buffer bindings that can be sharable across stages, we need to rename them to
// avoid GL program link failures due to block naming issues.
- if (bindingInfo.bindingType == BindingInfoType::Buffer &&
+ if (std::holds_alternative<BufferBindingInfo>(bindingInfo.bindingInfo) &&
stage != SingleShaderStage::Compute) {
req.bufferBindingVariables.emplace_back(bindingInfo.name);
}
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index ba70051..02530fa 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -238,72 +238,76 @@
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
const BindGroupLayout* bgl = ToBackend(layout->GetBindGroupLayout(group));
- for (const auto& [binding, bindingInfo] : moduleBindingInfo[group]) {
+ for (const auto& currentModuleBindingInfo : moduleBindingInfo[group]) {
+ // We cannot use structured binding here because lambda expressions can only capture
+ // variables, while structured binding doesn't introduce variables.
+ const auto& binding = currentModuleBindingInfo.first;
+ const auto& shaderBindingInfo = currentModuleBindingInfo.second;
tint::BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
static_cast<uint32_t>(binding)};
tint::BindingPoint dstBindingPoint{
static_cast<uint32_t>(group), static_cast<uint32_t>(bgl->GetBindingIndex(binding))};
- switch (bindingInfo.bindingType) {
- case BindingInfoType::Buffer:
- switch (bindingInfo.buffer.type) {
- case wgpu::BufferBindingType::Uniform:
- bindings.uniform.emplace(
- srcBindingPoint,
- tint::spirv::writer::binding::Uniform{dstBindingPoint.group,
- dstBindingPoint.binding});
- break;
- case kInternalStorageBufferBinding:
- case wgpu::BufferBindingType::Storage:
- case wgpu::BufferBindingType::ReadOnlyStorage:
- bindings.storage.emplace(
- srcBindingPoint,
- tint::spirv::writer::binding::Storage{dstBindingPoint.group,
- dstBindingPoint.binding});
- break;
- case wgpu::BufferBindingType::Undefined:
- DAWN_UNREACHABLE();
- break;
+ // TODO(dawn:2370): implement a helper in dawn/utils to simplify the call of std::visit.
+ std::visit(
+ [&](const auto& bindingInfo) {
+ using T = std::decay_t<decltype(bindingInfo)>;
+
+ if constexpr (std::is_same_v<T, BufferBindingInfo>) {
+ switch (bindingInfo.type) {
+ case wgpu::BufferBindingType::Uniform:
+ bindings.uniform.emplace(
+ srcBindingPoint,
+ tint::spirv::writer::binding::Uniform{dstBindingPoint.group,
+ dstBindingPoint.binding});
+ break;
+ case kInternalStorageBufferBinding:
+ case wgpu::BufferBindingType::Storage:
+ case wgpu::BufferBindingType::ReadOnlyStorage:
+ bindings.storage.emplace(
+ srcBindingPoint,
+ tint::spirv::writer::binding::Storage{dstBindingPoint.group,
+ dstBindingPoint.binding});
+ break;
+ case wgpu::BufferBindingType::Undefined:
+ DAWN_UNREACHABLE();
+ break;
+ }
+ } else if constexpr (std::is_same_v<T, SamplerBindingInfo>) {
+ bindings.sampler.emplace(
+ srcBindingPoint, tint::spirv::writer::binding::Sampler{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ } else if constexpr (std::is_same_v<T, SampledTextureBindingInfo>) {
+ bindings.texture.emplace(
+ srcBindingPoint, tint::spirv::writer::binding::Texture{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ } else if constexpr (std::is_same_v<T, StorageTextureBindingInfo>) {
+ bindings.storage_texture.emplace(
+ srcBindingPoint, tint::spirv::writer::binding::StorageTexture{
+ dstBindingPoint.group, dstBindingPoint.binding});
+ } else if constexpr (std::is_same_v<T, ExternalTextureBindingInfo>) {
+ const auto& bindingMap = bgl->GetExternalTextureBindingExpansionMap();
+ const auto& expansion = bindingMap.find(binding);
+ DAWN_ASSERT(expansion != bindingMap.end());
+
+ const auto& bindingExpansion = expansion->second;
+ tint::spirv::writer::binding::BindingInfo plane0{
+ static_cast<uint32_t>(group),
+ static_cast<uint32_t>(bgl->GetBindingIndex(bindingExpansion.plane0))};
+ tint::spirv::writer::binding::BindingInfo plane1{
+ static_cast<uint32_t>(group),
+ static_cast<uint32_t>(bgl->GetBindingIndex(bindingExpansion.plane1))};
+ tint::spirv::writer::binding::BindingInfo metadata{
+ static_cast<uint32_t>(group),
+ static_cast<uint32_t>(bgl->GetBindingIndex(bindingExpansion.params))};
+
+ bindings.external_texture.emplace(
+ srcBindingPoint, tint::spirv::writer::binding::ExternalTexture{
+ metadata, plane0, plane1});
}
- break;
- case BindingInfoType::Sampler:
- bindings.sampler.emplace(srcBindingPoint,
- tint::spirv::writer::binding::Sampler{
- dstBindingPoint.group, dstBindingPoint.binding});
- break;
- case BindingInfoType::Texture:
- bindings.texture.emplace(srcBindingPoint,
- tint::spirv::writer::binding::Texture{
- dstBindingPoint.group, dstBindingPoint.binding});
- break;
- case BindingInfoType::StorageTexture:
- bindings.storage_texture.emplace(
- srcBindingPoint, tint::spirv::writer::binding::StorageTexture{
- dstBindingPoint.group, dstBindingPoint.binding});
- break;
- case BindingInfoType::ExternalTexture: {
- const auto& bindingMap = bgl->GetExternalTextureBindingExpansionMap();
- const auto& expansion = bindingMap.find(binding);
- DAWN_ASSERT(expansion != bindingMap.end());
-
- const auto& bindingExpansion = expansion->second;
- tint::spirv::writer::binding::BindingInfo plane0{
- static_cast<uint32_t>(group),
- static_cast<uint32_t>(bgl->GetBindingIndex(bindingExpansion.plane0))};
- tint::spirv::writer::binding::BindingInfo plane1{
- static_cast<uint32_t>(group),
- static_cast<uint32_t>(bgl->GetBindingIndex(bindingExpansion.plane1))};
- tint::spirv::writer::binding::BindingInfo metadata{
- static_cast<uint32_t>(group),
- static_cast<uint32_t>(bgl->GetBindingIndex(bindingExpansion.params))};
-
- bindings.external_texture.emplace(
- srcBindingPoint,
- tint::spirv::writer::binding::ExternalTexture{metadata, plane0, plane1});
- break;
- }
- }
+ },
+ shaderBindingInfo.bindingInfo);
}
}