Dawn: Make shader module reflection serializable
This CL make shader module reflection data, i.e. EntryPointMetadataTable
serializable, so we can cache it into on-disk blob cache. With this CL
it is possible to create a shader module with reflection data but
without calling Tint at all.
This CL also make macro DAWN_SERIALIZABLE to generate default equality
comparison for the serializable struct, and also add default equality
comparison operator in necessary structs to achieve that.
Bug: 402772740, 42240459
Change-Id: Icf7b2d3d2e1fa427f2bd9e1db4f6410ff842c08c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/241494
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@microsoft.com>
diff --git a/src/dawn/native/BindGroupLayoutInternal.cpp b/src/dawn/native/BindGroupLayoutInternal.cpp
index 22b5f88..0c1b299 100644
--- a/src/dawn/native/BindGroupLayoutInternal.cpp
+++ b/src/dawn/native/BindGroupLayoutInternal.cpp
@@ -379,12 +379,11 @@
return {
.binding = binding,
.visibility = visibility,
- .bindingLayout =
- TextureBindingInfo{
- .sampleType = wgpu::TextureSampleType::Float,
- .viewDimension = wgpu::TextureViewDimension::e2D,
- .multisampled = false,
- },
+ .bindingLayout = TextureBindingInfo{{
+ .sampleType = wgpu::TextureSampleType::Float,
+ .viewDimension = wgpu::TextureViewDimension::e2D,
+ .multisampled = false,
+ }},
};
}
@@ -393,12 +392,11 @@
return {
.binding = binding,
.visibility = visibility,
- .bindingLayout =
- BufferBindingInfo{
- .type = wgpu::BufferBindingType::Uniform,
- .minBindingSize = 0,
- .hasDynamicOffset = false,
- },
+ .bindingLayout = BufferBindingInfo{{
+ .type = wgpu::BufferBindingType::Uniform,
+ .minBindingSize = 0,
+ .hasDynamicOffset = false,
+ }},
};
}
@@ -414,7 +412,7 @@
} else if (binding->texture.sampleType != wgpu::TextureSampleType::BindingNotUsed) {
auto textureBindingInfo = TextureBindingInfo::From(binding->texture);
if (binding->texture.viewDimension == kInternalInputAttachmentDim) {
- bindingInfo.bindingLayout = InputAttachmentBindingInfo{textureBindingInfo.sampleType};
+ bindingInfo.bindingLayout = InputAttachmentBindingInfo{{textureBindingInfo.sampleType}};
} else {
bindingInfo.bindingLayout = textureBindingInfo;
}
diff --git a/src/dawn/native/BindingInfo.cpp b/src/dawn/native/BindingInfo.cpp
index 099d9f7..ee52c714 100644
--- a/src/dawn/native/BindingInfo.cpp
+++ b/src/dawn/native/BindingInfo.cpp
@@ -302,11 +302,11 @@
// static
BufferBindingInfo BufferBindingInfo::From(const BufferBindingLayout& layout) {
BufferBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
- return {
+ return {{
.type = defaultedLayout.type,
.minBindingSize = defaultedLayout.minBindingSize,
.hasDynamicOffset = defaultedLayout.hasDynamicOffset,
- };
+ }};
}
// TextureBindingInfo
@@ -314,11 +314,11 @@
// static
TextureBindingInfo TextureBindingInfo::From(const TextureBindingLayout& layout) {
TextureBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
- return {
+ return {{
.sampleType = defaultedLayout.sampleType,
.viewDimension = defaultedLayout.viewDimension,
.multisampled = defaultedLayout.multisampled,
- };
+ }};
}
// StorageTextureBindingInfo
@@ -327,11 +327,11 @@
StorageTextureBindingInfo StorageTextureBindingInfo::From(
const StorageTextureBindingLayout& layout) {
StorageTextureBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
- return {
+ return {{
.format = defaultedLayout.format,
.viewDimension = defaultedLayout.viewDimension,
.access = defaultedLayout.access,
- };
+ }};
}
// SamplerBindingInfo
@@ -339,9 +339,9 @@
// static
SamplerBindingInfo SamplerBindingInfo::From(const SamplerBindingLayout& layout) {
SamplerBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
- return {
+ return {{
.type = defaultedLayout.type,
- };
+ }};
}
// SamplerBindingInfo
diff --git a/src/dawn/native/BindingInfo.h b/src/dawn/native/BindingInfo.h
index 292c256..c171f22 100644
--- a/src/dawn/native/BindingInfo.h
+++ b/src/dawn/native/BindingInfo.h
@@ -39,6 +39,7 @@
#include "dawn/native/Format.h"
#include "dawn/native/IntegerTypes.h"
#include "dawn/native/PerStage.h"
+#include "dawn/native/Serializable.h"
#include "dawn/native/dawn_platform.h"
@@ -69,51 +70,57 @@
};
// A mirror of wgpu::BufferBindingLayout for use inside dawn::native.
-struct BufferBindingInfo {
+#define BUFFER_BINDING_INFO_MEMBER(X) \
+ X(wgpu::BufferBindingType, type) \
+ X(uint64_t, minBindingSize) \
+ /* hasDynamicOffset is always false in shader reflection */ \
+ X(bool, hasDynamicOffset)
+DAWN_SERIALIZABLE(struct, BufferBindingInfo, BUFFER_BINDING_INFO_MEMBER) {
static BufferBindingInfo From(const BufferBindingLayout& layout);
-
- wgpu::BufferBindingType type;
- uint64_t minBindingSize;
-
- // Always false in shader reflection.
- bool hasDynamicOffset = false;
-
- bool operator==(const BufferBindingInfo& other) const = default;
};
+#undef BUFFER_BINDING_INFO_MEMBER
// A mirror of wgpu::TextureBindingLayout for use inside dawn::native.
-struct TextureBindingInfo {
+#define TEXTURE_BINDING_INFO_MEMBER(X) \
+ /* For shader reflection UnfilterableFloat is never used and the sample type is Float */ \
+ /* for any texture_Nd<f32>. */ \
+ X(wgpu::TextureSampleType, sampleType) \
+ X(wgpu::TextureViewDimension, viewDimension) \
+ X(bool, multisampled)
+DAWN_SERIALIZABLE(struct, TextureBindingInfo, TEXTURE_BINDING_INFO_MEMBER) {
static TextureBindingInfo From(const TextureBindingLayout& layout);
-
- // For shader reflection UnfilterableFloat is never used and the sample type is Float for any
- // texture_Nd<f32>.
- wgpu::TextureSampleType sampleType;
- wgpu::TextureViewDimension viewDimension;
- bool multisampled;
-
- bool operator==(const TextureBindingInfo& other) const = default;
};
+#undef TEXTURE_BINDING_INFO_MEMBER
// A mirror of wgpu::StorageTextureBindingLayout for use inside dawn::native.
-struct StorageTextureBindingInfo {
+#define STORAGE_TEXTURE_BINDING_INFO_MEMBER(X) \
+ X(wgpu::TextureFormat, format) \
+ X(wgpu::TextureViewDimension, viewDimension) \
+ X(wgpu::StorageTextureAccess, access)
+DAWN_SERIALIZABLE(struct, StorageTextureBindingInfo, STORAGE_TEXTURE_BINDING_INFO_MEMBER) {
static StorageTextureBindingInfo From(const StorageTextureBindingLayout& layout);
-
- wgpu::TextureFormat format;
- wgpu::TextureViewDimension viewDimension;
- wgpu::StorageTextureAccess access;
-
- bool operator==(const StorageTextureBindingInfo& other) const = default;
};
+#undef STORAGE_TEXTURE_BINDING_INFO_MEMBER
// A mirror of wgpu::SamplerBindingLayout for use inside dawn::native.
-struct SamplerBindingInfo {
+#define SAMPLER_BINDING_INFO_MEMBER(X) \
+ /* For shader reflection NonFiltering is never used and Filtering is used for */ \
+ /* any `sampler`. */ \
+ X(wgpu::SamplerBindingType, type)
+DAWN_SERIALIZABLE(struct, SamplerBindingInfo, SAMPLER_BINDING_INFO_MEMBER) {
static SamplerBindingInfo From(const SamplerBindingLayout& layout);
-
- // For shader reflection NonFiltering is never used and Filtering is used for any `sampler`.
- wgpu::SamplerBindingType type;
-
- bool operator==(const SamplerBindingInfo& other) const = default;
};
+#undef SAMPLER_BINDING_INFO_MEMBER
+
+// A mirror of wgpu::ExternalTextureBindingLayout for use inside dawn::native.
+#define EXTERNAL_TEXTURE_BINDING_INFO_MEMBER(X) // ExternalTextureBindingInfo has no member
+DAWN_SERIALIZABLE(struct, ExternalTextureBindingInfo, EXTERNAL_TEXTURE_BINDING_INFO_MEMBER){};
+#undef EXTERNAL_TEXTURE_BINDING_INFO_MEMBER
+
+// Internal to vulkan only.
+#define INPUT_ATTACHMENT_BINDING_INFO_MEMBER(X) X(wgpu::TextureSampleType, sampleType)
+DAWN_SERIALIZABLE(struct, InputAttachmentBindingInfo, INPUT_ATTACHMENT_BINDING_INFO_MEMBER){};
+#undef INPUT_ATTACHMENT_BINDING_INFO_MEMBER
// A mirror of wgpu::StaticSamplerBindingLayout for use inside dawn::native.
struct StaticSamplerBindingInfo {
@@ -130,18 +137,6 @@
bool operator==(const StaticSamplerBindingInfo& other) const = default;
};
-// A mirror of wgpu::ExternalTextureBindingLayout for use inside dawn::native.
-struct ExternalTextureBindingInfo {
- bool operator==(const ExternalTextureBindingInfo& other) const = default;
-};
-
-// Internal to vulkan only.
-struct InputAttachmentBindingInfo {
- wgpu::TextureSampleType sampleType;
-
- bool operator==(const InputAttachmentBindingInfo& other) const = default;
-};
-
struct BindingInfo {
BindingNumber binding;
wgpu::ShaderStage visibility;
@@ -165,12 +160,11 @@
BindingInfoType GetBindingInfoType(const BindingInfo& bindingInfo);
// Match tint::BindingPoint, can convert to/from tint::BindingPoint using ToTint and FromTint.
-struct BindingSlot {
- BindGroupIndex group;
- BindingNumber binding;
-
- constexpr bool operator==(const BindingSlot& rhs) const = default;
-};
+#define BINDING_SLOT_MEMBER(X) \
+ X(BindGroupIndex, group) \
+ X(BindingNumber, binding)
+DAWN_SERIALIZABLE(struct, BindingSlot, BINDING_SLOT_MEMBER){};
+#undef BINDING_SLOT_MEMBER
struct PerStageBindingCounts {
uint32_t sampledTextureCount;
diff --git a/src/dawn/native/Blob.cpp b/src/dawn/native/Blob.cpp
index d68b1aa..7fb1fcc 100644
--- a/src/dawn/native/Blob.cpp
+++ b/src/dawn/native/Blob.cpp
@@ -97,6 +97,13 @@
return mSize;
}
+bool Blob::operator==(const Blob& other) const {
+ if (other.Size() != Size()) {
+ return false;
+ }
+ return 0 == memcmp(Data(), other.Data(), Size());
+}
+
template <>
void stream::Stream<Blob>::Write(stream::Sink* s, const Blob& b) {
size_t size = b.Size();
diff --git a/src/dawn/native/Blob.h b/src/dawn/native/Blob.h
index 30f8901..52cf536 100644
--- a/src/dawn/native/Blob.h
+++ b/src/dawn/native/Blob.h
@@ -61,6 +61,8 @@
uint8_t* Data();
size_t Size() const;
+ bool operator==(const Blob& other) const;
+
private:
// The constructor should be responsible to take ownership of |data| and releases ownership by
// calling |deleter|. The deleter function is called at ~Blob() and during std::move.
diff --git a/src/dawn/native/CacheKey.h b/src/dawn/native/CacheKey.h
index a65ea9a..b5e32db 100644
--- a/src/dawn/native/CacheKey.h
+++ b/src/dawn/native/CacheKey.h
@@ -54,6 +54,10 @@
// stream::StreamIn<T>.
friend constexpr void StreamIn(stream::Sink*, const UnsafeUnkeyedValue&) {}
+ // Enabling DAWN_SERIALIZABLE classes with UnsafeUnkeyedValue member to use default equality
+ // operator. Equality comparison always returns true for the same type UnsafeUnkeyedValues.
+ bool operator==(const UnsafeUnkeyedValue<T>& other) const { return true; }
+
private:
T mValue;
};
diff --git a/src/dawn/native/Limits.h b/src/dawn/native/Limits.h
index 825c40e..094d47a 100644
--- a/src/dawn/native/Limits.h
+++ b/src/dawn/native/Limits.h
@@ -85,6 +85,7 @@
struct LimitsForCompilationRequest {
static LimitsForCompilationRequest Create(const Limits& limits);
DAWN_VISITABLE_MEMBERS(LIMITS_FOR_COMPILATION_REQUEST_MEMBERS)
+ bool operator==(const LimitsForCompilationRequest& other) const = default;
};
// Enforce restriction for limit values, including:
diff --git a/src/dawn/native/Serializable.h b/src/dawn/native/Serializable.h
index ea4b79d..72dafb2 100644
--- a/src/dawn/native/Serializable.h
+++ b/src/dawn/native/Serializable.h
@@ -67,8 +67,8 @@
// Helper macro to define a struct or class along with VisitAll methods to call
// a functor on all members. Derives from Visitable which provides
-// implementations of StreamIn/StreamOut/FromBlob/ToBlob.
-// Example usage:
+// implementations of StreamIn/StreamOut/FromBlob/ToBlob, and provides a default equality
+// comparison. Example usage:
// #define MEMBERS(X) \
// X(int, a) \
// X(float, b) \
@@ -78,10 +78,11 @@
// void SomeAdditionalMethod();
// };
// #undef MEMBERS
-#define DAWN_SERIALIZABLE(qualifier, Name, MEMBERS) \
- struct Name##__Contents { \
- DAWN_VISITABLE_MEMBERS(MEMBERS) \
- }; \
+#define DAWN_SERIALIZABLE(qualifier, Name, MEMBERS) \
+ struct Name##__Contents { \
+ DAWN_VISITABLE_MEMBERS(MEMBERS) \
+ bool operator==(const Name##__Contents& other) const = default; \
+ }; \
qualifier Name : Name##__Contents, public ::dawn::native::Serializable<Name>
#endif // SRC_DAWN_NATIVE_SERIALIZABLE_H_
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 9f96028..34ef542 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -320,6 +320,10 @@
DAWN_UNREACHABLE();
}
+EntryPointMetadata::OverrideId FromTintOverrideId(tint::OverrideId id) {
+ return EntryPointMetadata::OverrideId{{id.value}};
+}
+
EntryPointMetadata::Override::Type FromTintOverrideType(tint::inspector::Override::Type type) {
switch (type) {
case tint::inspector::Override::Type::kBool:
@@ -677,8 +681,8 @@
if (!entryPoint.overrides.empty()) {
for (auto& c : entryPoint.overrides) {
auto id = name2Id.at(c.name);
- EntryPointMetadata::Override override = {id, FromTintOverrideType(c.type),
- c.is_initialized};
+ EntryPointMetadata::Override override = {
+ {FromTintOverrideId(id), FromTintOverrideType(c.type), c.is_initialized}};
std::string identifier = c.is_id_specified ? std::to_string(override.id.value) : c.name;
metadata->overrides[identifier] = override;
@@ -705,8 +709,9 @@
}
auto id = name2Id.at(o.name);
- EntryPointMetadata::Override override = {id, FromTintOverrideType(o.type), o.is_initialized,
- /* isUsed */ false};
+ EntryPointMetadata::Override override = {{FromTintOverrideId(id),
+ FromTintOverrideType(o.type), o.is_initialized,
+ /* isUsed */ false}};
metadata->overrides[identifier] = override;
}
diff --git a/src/dawn/native/ShaderModule.h b/src/dawn/native/ShaderModule.h
index 868d212..8b49bd3 100644
--- a/src/dawn/native/ShaderModule.h
+++ b/src/dawn/native/ShaderModule.h
@@ -56,6 +56,7 @@
#include "dawn/native/Limits.h"
#include "dawn/native/ObjectBase.h"
#include "dawn/native/PerStage.h"
+#include "dawn/native/Serializable.h"
#include "dawn/native/dawn_platform.h"
#include "tint/tint.h"
@@ -166,25 +167,159 @@
const PipelineLayoutBase* layout);
// Shader metadata for a binding, very similar to information contained in a pipeline layout.
-struct ShaderBindingInfo {
- BindingNumber binding;
- BindingIndex arraySize;
-
- // The variable name of the binding resource.
- std::string name;
-
- std::variant<BufferBindingInfo,
- SamplerBindingInfo,
- TextureBindingInfo,
- StorageTextureBindingInfo,
- ExternalTextureBindingInfo,
- InputAttachmentBindingInfo>
- bindingInfo;
-};
+using ShaderBindingInfoVariant = std::variant<BufferBindingInfo,
+ SamplerBindingInfo,
+ TextureBindingInfo,
+ StorageTextureBindingInfo,
+ ExternalTextureBindingInfo,
+ InputAttachmentBindingInfo>;
+#define SHADER_BINDING_INFO_MEMBER(X) \
+ X(BindingNumber, binding) \
+ X(BindingIndex, arraySize) \
+ /*The variable name of the binding resource.*/ \
+ X(std::string, name) \
+ X(ShaderBindingInfoVariant, bindingInfo)
+DAWN_SERIALIZABLE(struct, ShaderBindingInfo, SHADER_BINDING_INFO_MEMBER){};
+#undef SHADER_BINDING_INFO_MEMBER
using BindingGroupInfoMap = absl::flat_hash_map<BindingNumber, ShaderBindingInfo>;
using BindingInfoArray = ityp::array<BindGroupIndex, BindingGroupInfoMap, kMaxBindGroups>;
+// Define types for the shader reflection data structures in detail namespaces to prevent messing
+// up dawn::native namespace. These types can be exposed within EntryPointMetadata if needed.
+namespace detail {
+#define SAMPLER_TEXTURE_PAIR_MEMBER(X) \
+ X(BindingSlot, sampler) \
+ X(BindingSlot, texture)
+DAWN_SERIALIZABLE(struct, SamplerTexturePair, SAMPLER_TEXTURE_PAIR_MEMBER){};
+#undef SAMPLER_TEXTURE_PAIR_MEMBER
+
+/// Match tint::inspector::Inspector::LevelSampleInfo
+enum class TextureQueryType : uint8_t { TextureNumLevels, TextureNumSamples };
+
+#define TEXTURE_METADATE_QUERY_MEMBER(X) \
+ X(TextureQueryType, type) \
+ X(uint32_t, group) \
+ X(uint32_t, binding)
+DAWN_SERIALIZABLE(struct, TextureMetadataQuery, TEXTURE_METADATE_QUERY_MEMBER) {
+ using TextureQueryType = TextureQueryType;
+};
+#undef TEXTURE_METADATE_QUERY_MEMBER
+
+// Structure to record the basic types (float, int and uint) of the fragment shader framebuffer
+// input/outputs (inputs being "framebuffer fetch").
+#define FRAGMENT_RENDER_ATTACHMENT_INFO_MEMBER(X) \
+ X(TextureComponentType, baseType) \
+ X(uint8_t, componentCount) \
+ X(uint8_t, blendSrc)
+DAWN_SERIALIZABLE(struct, FragmentRenderAttachmentInfo, FRAGMENT_RENDER_ATTACHMENT_INFO_MEMBER){};
+#undef FRAGMENT_RENDER_ATTACHMENT_INFO_MEMBER
+
+#define INTER_STAGE_VARIABLE_INFO_MEMBER(X) \
+ X(std::string, name) \
+ X(InterStageComponentType, baseType) \
+ X(uint32_t, componentCount) \
+ X(InterpolationType, interpolationType) \
+ X(InterpolationSampling, interpolationSampling)
+DAWN_SERIALIZABLE(struct, InterStageVariableInfo, INTER_STAGE_VARIABLE_INFO_MEMBER){};
+#undef INTER_STAGE_VARIABLE_INFO_MEMBER
+
+// Match tint::OverrideId
+#define OVERRIDE_ID_MEMBER(X) X(uint16_t, value)
+DAWN_SERIALIZABLE(struct, OverrideId, OVERRIDE_ID_MEMBER){};
+#undef OVERRIDE_ID_MEMBER
+
+enum class OverrideType { Boolean, Float32, Uint32, Int32, Float16 };
+
+#define OVERRIDE_MEMBER(X) \
+ X(OverrideId, id) \
+ X(OverrideType, type) \
+ X(bool, isInitialized) \
+ X(bool, isUsed)
+DAWN_SERIALIZABLE(struct, Override, OVERRIDE_MEMBER) {
+ using Type = OverrideType;
+};
+#undef OVERRIDE_MEMBER
+
+using OverridesMap = absl::flat_hash_map<std::string, Override>;
+} // namespace detail
+
+// Contains all the reflection data for a valid (ShaderModule, entryPoint, stage). This structure is
+// serializable and doesn't depend on the shader program, thus it can outlive the shader program and
+// get cached on disk. They are stored in the ShaderModuleBase so pointers to EntryPointMetadata are
+// safe to store as long as you also keep a Ref to the ShaderModuleBase.
+#define ENTRY_POINT_METADATA_MEMBER(X) \
+ /* It is valid for a shader to contain entry points that go over limits. To keep this */ \
+ /* structure with packed arrays and bitsets, we still validate against limits when doing */ \
+ /* reflection, but store the errors in this vector, for later use if the application tries */ \
+ /* to use the entry point. */ \
+ X(std::vector<std::string>, infringedLimitErrors) \
+ /* bindings[G][B] is the reflection data for the binding defined with @group(G) @binding(B)*/ \
+ X(BindingInfoArray, bindings) \
+ /* Contains the reflection information of all sampler and non-sampler texture (storage */ \
+ /* texture not included) usage in the entry point. For non-sampler usage, */ \
+ /* nonSamplerBindingPoint is used for sampler slot. */ \
+ X(std::vector<detail::SamplerTexturePair>, samplerAndNonSamplerTexturePairs) \
+ X(std::vector<detail::TextureMetadataQuery>, textureQueries) \
+ /* The set of vertex attributes this entryPoint uses.*/ \
+ X(PerVertexAttribute<VertexFormatBaseType>, vertexInputBaseTypes) \
+ X(VertexAttributeMask, usedVertexInputs) \
+ /* An array to record the basic types of the fragment shader framebuffer input/outputs.*/ \
+ X(PerColorAttachment<detail::FragmentRenderAttachmentInfo>, fragmentOutputVariables) \
+ X(ColorAttachmentMask, fragmentOutputMask) \
+ X(PerColorAttachment<detail::FragmentRenderAttachmentInfo>, fragmentInputVariables) \
+ X(ColorAttachmentMask, fragmentInputMask) \
+ /* Now that we only support vertex and fragment stages, there can't be both inter-stage */ \
+ /* inputs and outputs in one shader stage. */ \
+ X(std::vector<bool>, usedInterStageVariables) \
+ X(std::vector<detail::InterStageVariableInfo>, interStageVariables) \
+ X(uint32_t, totalInterStageShaderVariables) \
+ /* The shader stage for this entry point.*/ \
+ X(SingleShaderStage, stage) \
+ /* Map identifier to override variable. */ \
+ /* Identifier is unique: either the variable name or the numeric ID if specified */ \
+ X(detail::OverridesMap, overrides) \
+ /* Override variables that are not initialized in shaders. They need value initialization */ \
+ /* from pipeline stage or it is a validation error */ \
+ X(absl::flat_hash_set<std::string>, uninitializedOverrides) \
+ /* Store constants with shader initialized values as well. */ \
+ /* This is used by metal backend to set values with default initializers that are not */ \
+ /* overridden. */ \
+ X(absl::flat_hash_set<std::string>, initializedOverrides) \
+ /* Reflection information about potential `pixel_local` variable use. */ \
+ X(bool, usesPixelLocal) \
+ X(size_t, pixelLocalBlockSize) \
+ X(std::vector<PixelLocalMemberType>, pixelLocalMembers) \
+ X(bool, usesFragDepth) \
+ X(bool, usesInstanceIndex) \
+ X(bool, usesNumWorkgroups) \
+ X(bool, usesSampleMaskOutput) \
+ X(bool, usesSampleIndex) \
+ X(bool, usesVertexIndex) \
+ X(bool, usesTextureLoadWithDepthTexture) \
+ X(bool, usesDepthTextureWithNonComparisonSampler) \
+ X(bool, usesSubgroupMatrix) \
+ /* Immediate Data block byte size */ \
+ X(uint32_t, immediateDataRangeByteSize) \
+ /* Number of texture+sampler combinations, computed as 1 for every texture+sampler */ \
+ /* combination + 1 for every texture used without a sampler that wasn't previously counted.*/ \
+ /* Note: this is only set in compatibility mode. */ \
+ X(uint32_t, numTextureSamplerCombinations)
+DAWN_SERIALIZABLE(struct, EntryPointMetadata, ENTRY_POINT_METADATA_MEMBER) {
+ using SamplerTexturePair = detail::SamplerTexturePair;
+ // TODO(crbug.com/409438000): Remove the hack of sampler placeholders for non-sampler texture.
+ static constexpr const BindingSlot nonSamplerBindingPoint{
+ {BindGroupIndex{std::numeric_limits<uint32_t>::max()},
+ BindingNumber{std::numeric_limits<uint32_t>::max()}}};
+
+ using TextureMetadataQuery = detail::TextureMetadataQuery;
+ using FragmentRenderAttachmentInfo = detail::FragmentRenderAttachmentInfo;
+ using InterStageVariableInfo = detail::InterStageVariableInfo;
+ using OverrideId = detail::OverrideId;
+ using Override = detail::Override;
+};
+#undef ENTRY_POINT_METADATA_MEMBER
+
// The WebGPU override variables only support these scalar types
union OverrideScalar {
// Use int32_t for boolean to initialize the full 32bit
@@ -194,140 +329,6 @@
uint32_t u32;
};
-// Contains all the reflection data for a valid (ShaderModule, entryPoint, stage). They are
-// stored in the ShaderModuleBase and destroyed only when the shader program is destroyed so
-// pointers to EntryPointMetadata are safe to store as long as you also keep a Ref to the
-// ShaderModuleBase.
-struct EntryPointMetadata {
- // It is valid for a shader to contain entry points that go over limits. To keep this
- // structure with packed arrays and bitsets, we still validate against limits when
- // doing reflection, but store the errors in this vector, for later use if the application
- // tries to use the entry point.
- std::vector<std::string> infringedLimitErrors;
-
- // bindings[G][B] is the reflection data for the binding defined with @group(G) @binding(B)
- BindingInfoArray bindings;
-
- struct SamplerTexturePair {
- BindingSlot sampler;
- BindingSlot texture;
- };
- // TODO(crbug.com/409438000): Remove the hack of sampler placeholders for non-sampler texture.
- static constexpr const BindingSlot nonSamplerBindingPoint = {
- BindGroupIndex(std::numeric_limits<uint32_t>::max()),
- BindingNumber(std::numeric_limits<uint32_t>::max())};
- // Contains the reflection information of all sampler and non-sampler texture (storage texture
- // not included) usage in the entry point. For non-sampler usage, nonSamplerBindingPoint is used
- // for sampler slot.
- std::vector<SamplerTexturePair> samplerAndNonSamplerTexturePairs;
-
- /// Match tint::inspector::Inspector::LevelSampleInfo
- struct TextureMetadataQuery {
- /// The information needed to be supplied.
- enum class TextureQueryType : uint8_t {
- /// Texture Num Levels
- TextureNumLevels,
- /// Texture Num Samples
- TextureNumSamples,
- };
- /// The type of function
- TextureQueryType type = TextureQueryType::TextureNumLevels;
- /// The group number
- uint32_t group = 0;
- /// The binding number
- uint32_t binding = 0;
- };
- std::vector<TextureMetadataQuery> textureQueries;
-
- // The set of vertex attributes this entryPoint uses.
- PerVertexAttribute<VertexFormatBaseType> vertexInputBaseTypes;
- VertexAttributeMask usedVertexInputs;
-
- // An array to record the basic types (float, int and uint) of the fragment shader framebuffer
- // input/outputs (inputs being "framebuffer fetch").
- struct FragmentRenderAttachmentInfo {
- TextureComponentType baseType;
- uint8_t componentCount;
- uint8_t blendSrc;
- };
- PerColorAttachment<FragmentRenderAttachmentInfo> fragmentOutputVariables;
- ColorAttachmentMask fragmentOutputMask;
-
- PerColorAttachment<FragmentRenderAttachmentInfo> fragmentInputVariables;
- ColorAttachmentMask fragmentInputMask;
-
- struct InterStageVariableInfo {
- std::string name;
- InterStageComponentType baseType;
- uint32_t componentCount;
- InterpolationType interpolationType;
- InterpolationSampling interpolationSampling;
- };
- // Now that we only support vertex and fragment stages, there can't be both inter-stage
- // inputs and outputs in one shader stage.
- std::vector<bool> usedInterStageVariables;
- std::vector<InterStageVariableInfo> interStageVariables;
- uint32_t totalInterStageShaderVariables;
-
- // The shader stage for this entry point.
- SingleShaderStage stage;
-
- struct Override {
- tint::OverrideId id;
-
- // Match tint::inspector::Override::Type
- // Bool is defined as a macro on linux X11 and cannot compile
- enum class Type { Boolean, Float32, Uint32, Int32, Float16 } type;
-
- // If the constant doesn't not have an initializer in the shader
- // Then it is required for the pipeline stage to have a constant record to initialize a
- // value
- bool isInitialized;
-
- // Set to true if the override is used in the entry point
- bool isUsed = true;
- };
-
- using OverridesMap = absl::flat_hash_map<std::string, Override>;
-
- // Map identifier to override variable
- // Identifier is unique: either the variable name or the numeric ID if specified
- OverridesMap overrides;
-
- // Override variables that are not initialized in shaders
- // They need value initialization from pipeline stage or it is a validation error
- absl::flat_hash_set<std::string> uninitializedOverrides;
-
- // Store constants with shader initialized values as well
- // This is used by metal backend to set values with default initializers that are not
- // overridden
- absl::flat_hash_set<std::string> initializedOverrides;
-
- // Reflection information about potential `pixel_local` variable use.
- bool usesPixelLocal = false;
- size_t pixelLocalBlockSize = 0;
- std::vector<PixelLocalMemberType> pixelLocalMembers;
-
- bool usesFragDepth = false;
- bool usesInstanceIndex = false;
- bool usesNumWorkgroups = false;
- bool usesSampleMaskOutput = false;
- bool usesSampleIndex = false;
- bool usesVertexIndex = false;
- bool usesTextureLoadWithDepthTexture = false;
- bool usesDepthTextureWithNonComparisonSampler = false;
- bool usesSubgroupMatrix = false;
-
- // Immediate Data block byte size
- uint32_t immediateDataRangeByteSize = 0;
-
- // Number of texture+sampler combinations, computed as
- // 1 for every texture+sampler combination + 1 for every texture used
- // without a sampler that wasn't previously counted.
- // Note: this is only set in compatibility mode.
- uint32_t numTextureSamplerCombinations = 0;
-};
-
class ShaderModuleBase : public RefCountedWithExternalCount<ApiObjectBase>,
public CachedObject,
public ContentLessObjectCacheable<ShaderModuleBase> {
diff --git a/src/dawn/native/TintUtils.cpp b/src/dawn/native/TintUtils.cpp
index c2b8d3d..2ab9fe1 100644
--- a/src/dawn/native/TintUtils.cpp
+++ b/src/dawn/native/TintUtils.cpp
@@ -180,7 +180,7 @@
for (const auto& [key, value] : constants) {
const auto& o = metadata.overrides.at(key);
- map.insert({o.id, value});
+ map.insert({{o.id.value}, value});
}
return map;
}
diff --git a/src/dawn/native/TintUtils.h b/src/dawn/native/TintUtils.h
index 5c3b1dc..d8f83e1 100644
--- a/src/dawn/native/TintUtils.h
+++ b/src/dawn/native/TintUtils.h
@@ -76,7 +76,7 @@
}
constexpr BindingSlot FromTint(const tint::BindingPoint& tintBindingPoint) {
- return {BindGroupIndex(tintBindingPoint.group), BindingNumber(tintBindingPoint.binding)};
+ return {{BindGroupIndex(tintBindingPoint.group), BindingNumber(tintBindingPoint.binding)}};
}
} // namespace dawn::native
diff --git a/src/dawn/native/stream/Stream.cpp b/src/dawn/native/stream/Stream.cpp
index 1682b63..b3a5cb0 100644
--- a/src/dawn/native/stream/Stream.cpp
+++ b/src/dawn/native/stream/Stream.cpp
@@ -33,6 +33,12 @@
namespace dawn::native::stream {
+constexpr void StreamIn(Sink* s) {}
+
+MaybeError StreamOut(Source* s) {
+ return {};
+}
+
template <>
void Stream<std::string>::Write(Sink* s, const std::string& t) {
StreamIn(s, t.length());
diff --git a/src/dawn/native/stream/Stream.h b/src/dawn/native/stream/Stream.h
index d501925..3ffd37d 100644
--- a/src/dawn/native/stream/Stream.h
+++ b/src/dawn/native/stream/Stream.h
@@ -104,6 +104,14 @@
return StreamOut(s, vs...);
}
+// Helper to call StreamIn on an empty parameter pack, e.g. for a DAWN_SERIALIZABLE struct with no
+// member. Do nothing.
+constexpr void StreamIn(Sink* s);
+
+// Helper to call StreamOut on an empty parameter pack, e.g. for a DAWN_SERIALIZABLE struct with no
+// member. Do nothing and return success.
+MaybeError StreamOut(Source* s);
+
// Stream specialization for fundamental types.
template <typename T>
class Stream<T, std::enable_if_t<std::is_fundamental_v<T>>> {
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index 12b04df..f080142 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -121,6 +121,8 @@
/// The binding points that will be ignored by the rebustness transform.
std::vector<BindingPoint> ignored_by_robustness_transform;
+ bool operator==(const Bindings& other) const = default;
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(Bindings,
uniform,
@@ -146,6 +148,8 @@
/// into the uniform buffer where the length of the buffer is stored.
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_size_index;
+ bool operator==(const ArrayLengthFromUniformOptions& other) const = default;
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(ArrayLengthFromUniformOptions, ubo_binding, bindpoint_to_size_index);
};
@@ -178,6 +182,8 @@
/// The bind group index of all pixel local storage attachments
uint32_t group_index = 0;
+ bool operator==(const PixelLocalOptions& other) const = default;
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(PixelLocalOptions, attachments, group_index);
};
@@ -260,6 +266,8 @@
/// Pixel local configuration
PixelLocalOptions pixel_local;
+ bool operator==(const Options& other) const = default;
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(Options,
remapped_entry_point_name,