diff --git a/src/dawn/native/StreamImplTint.cpp b/src/dawn/native/StreamImplTint.cpp index 13a70cabb5..deeaa0f11a 100644 --- a/src/dawn/native/StreamImplTint.cpp +++ b/src/dawn/native/StreamImplTint.cpp @@ -19,6 +19,15 @@ namespace dawn::native { +namespace { + +template +void StreamInTintObject(const OBJECT& object, stream::Sink* sink) { + tint::ForeachField(object, [&](auto& field) { StreamIn(sink, field); }); +} + +} // namespace + // static template <> void stream::Stream::Write(stream::Sink* sink, const tint::Program& p) { @@ -36,82 +45,48 @@ void stream::Stream::Write(stream::Sink* sink, const tint::Progra // static template <> void stream::Stream::Write(stream::Sink* sink, - const tint::sem::BindingPoint& p) { - static_assert(offsetof(tint::sem::BindingPoint, group) == 0, - "Please update serialization for tint::sem::BindingPoint"); - static_assert(offsetof(tint::sem::BindingPoint, binding) == 4, - "Please update serialization for tint::sem::BindingPoint"); - static_assert(sizeof(tint::sem::BindingPoint) == 8, - "Please update serialization for tint::sem::BindingPoint"); - StreamIn(sink, p.group, p.binding); + const tint::sem::BindingPoint& point) { + StreamInTintObject(point, sink); } // static template <> -void stream::Stream::Write( +void stream::Stream::Write( stream::Sink* sink, - const tint::transform::BindingPoints& points) { - static_assert(offsetof(tint::transform::BindingPoints, plane_1) == 0, - "Please update serialization for tint::transform::BindingPoints"); - static_assert(offsetof(tint::transform::BindingPoints, params) == 8, - "Please update serialization for tint::transform::BindingPoints"); - static_assert(sizeof(tint::transform::BindingPoints) == 16, - "Please update serialization for tint::transform::BindingPoints"); - StreamIn(sink, points.plane_1, points.params); + const tint::transform::MultiplanarExternalTexture::BindingPoints& points) { + StreamInTintObject(points, sink); } +// static template <> void stream::Stream::Write( stream::Sink* sink, const tint::transform::VertexPulling::Config& cfg) { - StreamIn(sink, cfg.entry_point_name, cfg.vertex_state, cfg.pulling_group); + StreamInTintObject(cfg, sink); } +// static template <> void stream::Stream::Write( stream::Sink* sink, const tint::transform::VertexBufferLayoutDescriptor& layout) { - using Layout = tint::transform::VertexBufferLayoutDescriptor; - static_assert(offsetof(Layout, array_stride) == 0, - "Please update serialization for tint::transform::VertexBufferLayoutDescriptor"); - static_assert(offsetof(Layout, step_mode) == 4, - "Please update serialization for tint::transform::VertexBufferLayoutDescriptor"); - static_assert(offsetof(Layout, attributes) == 8, - "Please update serialization for tint::transform::VertexBufferLayoutDescriptor"); - StreamIn(sink, layout.array_stride, layout.step_mode, layout.attributes); + StreamInTintObject(layout, sink); } +// static template <> void stream::Stream::Write( stream::Sink* sink, const tint::transform::VertexAttributeDescriptor& attrib) { - using Attrib = tint::transform::VertexAttributeDescriptor; - static_assert(offsetof(Attrib, format) == 0, - "Please update serialization for tint::transform::VertexAttributeDescriptor"); - static_assert(offsetof(Attrib, offset) == 4, - "Please update serialization for tint::transform::VertexAttributeDescriptor"); - static_assert(offsetof(Attrib, shader_location) == 8, - "Please update serialization for tint::transform::VertexAttributeDescriptor"); - static_assert(sizeof(Attrib) == 12, - "Please update serialization for tint::transform::VertexAttributeDescriptor"); - StreamIn(sink, attrib.format, attrib.offset, attrib.shader_location); + StreamInTintObject(attrib, sink); } // static template <> void stream::Stream::Write( stream::Sink* sink, - const tint::writer::ArrayLengthFromUniformOptions& o) { - static_assert(offsetof(tint::writer::ArrayLengthFromUniformOptions, ubo_binding) == 0, - "Please update serialization for tint::writer::ArrayLengthFromUniformOptions"); - static_assert( - offsetof(tint::writer::ArrayLengthFromUniformOptions, bindpoint_to_size_index) == 8, - "Please update serialization for tint::writer::ArrayLengthFromUniformOptions"); - static_assert( - sizeof(tint::writer::ArrayLengthFromUniformOptions) == - 8 + sizeof(tint::writer::ArrayLengthFromUniformOptions::bindpoint_to_size_index), - "Please update serialization for tint::writer::ArrayLengthFromUniformOptions"); - StreamIn(sink, o.ubo_binding, o.bindpoint_to_size_index); + const tint::writer::ArrayLengthFromUniformOptions& options) { + StreamInTintObject(options, sink); } } // namespace dawn::native diff --git a/src/dawn/tests/unittests/native/StreamTests.cpp b/src/dawn/tests/unittests/native/StreamTests.cpp index 2246fb3bba..2819cc3e43 100644 --- a/src/dawn/tests/unittests/native/StreamTests.cpp +++ b/src/dawn/tests/unittests/native/StreamTests.cpp @@ -265,7 +265,7 @@ TEST(SerializeTests, TintSemBindingPoint) { // Test that ByteVectorSink serializes tint::transform::BindingPoints as expected. TEST(SerializeTests, TintTransformBindingPoints) { - tint::transform::BindingPoints points{ + tint::transform::MultiplanarExternalTexture::BindingPoints points{ tint::sem::BindingPoint{1, 4}, tint::sem::BindingPoint{3, 7}, }; diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index c1e84d18ec..f53b52019b 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -390,6 +390,7 @@ libtint_source_set("libtint_core_all_src") { "program_builder.h", "program_id.cc", "program_id.h", + "reflection.h", "reader/reader.cc", "reader/reader.h", "resolver/const_eval.cc", @@ -568,6 +569,7 @@ libtint_source_set("libtint_core_all_src") { "utils/debugger.cc", "utils/debugger.h", "utils/enum_set.h", + "utils/foreach_macro.h", "utils/hash.h", "utils/hashmap.h", "utils/hashset.h", @@ -1609,6 +1611,7 @@ if (tint_build_unittests) { "number_test.cc", "program_builder_test.cc", "program_test.cc", + "reflection_test.cc", "scope_stack_test.cc", "source_test.cc", "symbol_table_test.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index e8f875b4a6..3e0c5d1b26 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -252,6 +252,7 @@ set(TINT_LIB_SRCS program_id.h program.cc program.h + reflection.h reader/reader.cc reader/reader.h resolver/const_eval.cc @@ -478,6 +479,7 @@ set(TINT_LIB_SRCS utils/concat.h utils/crc32.h utils/enum_set.h + utils/foreach_macro.h utils/hash.h utils/hashmap.h utils/hashset.h @@ -777,6 +779,7 @@ if(TINT_BUILD_TESTS) number_test.cc program_builder_test.cc program_test.cc + reflection_test.cc resolver/array_accessor_test.cc resolver/assignment_validation_test.cc resolver/atomics_test.cc diff --git a/src/tint/fuzzers/data_builder.h b/src/tint/fuzzers/data_builder.h index 92a565f82f..2aaecf701f 100644 --- a/src/tint/fuzzers/data_builder.h +++ b/src/tint/fuzzers/data_builder.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -128,11 +129,26 @@ class DataBuilder { /// @returns a variable of type T filled with pseudo-random data static T impl(DataBuilder* b) { T out{}; - b->build(&out, sizeof(T)); + if constexpr (tint::HasReflection) { + ForeachField(out, [&](auto& field) { b->build(field); }); + } else if constexpr (std::is_pod_v) { + b->build(&out, sizeof(T)); + } else { + static_assert(sizeof(T) == 0, "cannot build type"); + } return out; } }; + /// Specialization for bool + template <> + struct BuildImpl { + /// Generate a pseudo-random bool + /// @param b - data builder to use + /// @returns a boolean with even odds of being true or false + static bool impl(DataBuilder* b) { return b->generator_.GetBool(); } + }; + /// Specialization for std::string template <> struct BuildImpl { @@ -150,74 +166,17 @@ class DataBuilder { } }; - /// Specialization for bool - template <> - struct BuildImpl { - /// Generate a pseudo-random bool + /// Specialization for std::optional + template + struct BuildImpl> { + /// Generate a pseudo-random optional /// @param b - data builder to use - /// @returns a boolean with even odds of being true or false - static bool impl(DataBuilder* b) { return b->generator_.GetBool(); } - }; - - /// Specialization for writer::msl::Options - template <> - struct BuildImpl { - /// Generate a pseudo-random writer::msl::Options struct - /// @param b - data builder to use - /// @returns writer::msl::Options filled with pseudo-random data - static writer::msl::Options impl(DataBuilder* b) { - writer::msl::Options out{}; - b->build(out.buffer_size_ubo_index); - b->build(out.fixed_sample_mask); - b->build(out.emit_vertex_point_size); - b->build(out.disable_workgroup_init); - b->build(out.generate_external_texture_bindings); - b->build(out.array_length_from_uniform); - return out; - } - }; - - /// Specialization for writer::hlsl::Options - template <> - struct BuildImpl { - /// Generate a pseudo-random writer::hlsl::Options struct - /// @param b - data builder to use - /// @returns writer::hlsl::Options filled with pseudo-random data - static writer::hlsl::Options impl(DataBuilder* b) { - writer::hlsl::Options out{}; - b->build(out.root_constant_binding_point); - b->build(out.disable_workgroup_init); - b->build(out.array_length_from_uniform); - return out; - } - }; - - /// Specialization for writer::spirv::Options - template <> - struct BuildImpl { - /// Generate a pseudo-random writer::spirv::Options struct - /// @param b - data builder to use - /// @returns writer::spirv::Options filled with pseudo-random data - static writer::spirv::Options impl(DataBuilder* b) { - writer::spirv::Options out{}; - b->build(out.emit_vertex_point_size); - b->build(out.disable_workgroup_init); - return out; - } - }; - - /// Specialization for writer::ArrayLengthFromUniformOptions - template <> - struct BuildImpl { - /// Generate a pseudo-random writer::ArrayLengthFromUniformOptions struct - /// @param b - data builder to use - /// @returns writer::ArrayLengthFromUniformOptions filled with pseudo-random - /// data - static writer::ArrayLengthFromUniformOptions impl(DataBuilder* b) { - writer::ArrayLengthFromUniformOptions out{}; - b->build(out.ubo_binding); - b->build(out.bindpoint_to_size_index); - return out; + /// @returns a either a nullopt, or a randomly filled T + static std::optional impl(DataBuilder* b) { + if (b->build()) { + return b->build(); + } + return std::nullopt; } }; diff --git a/src/tint/reflection.h b/src/tint/reflection.h new file mode 100644 index 0000000000..05918381ba --- /dev/null +++ b/src/tint/reflection.h @@ -0,0 +1,67 @@ +// Copyright 2022 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_TINT_REFLECTION_H_ +#define SRC_TINT_REFLECTION_H_ + +#include "src/tint/traits.h" +#include "src/tint/utils/concat.h" +#include "src/tint/utils/foreach_macro.h" + +namespace tint { + +namespace detail { + +/// Helper for detecting whether the type T contains a nested Reflection class. +template +struct HasReflection : std::false_type {}; + +/// Specialization for types that have a nested Reflection class. +template +struct HasReflection> : std::true_type {}; + +} // namespace detail + +/// Is true if the class T has reflected its fields with TINT_REFLECT() +template +static constexpr bool HasReflection = detail::HasReflection::value; + +/// Calls @p callback with each field of @p object +/// @param object the object +/// @param callback a function that is called for each field of @p object. +/// @tparam CB a function with the signature `void(FIELD)` +template +void ForeachField(OBJECT&& object, CB&& callback) { + using T = std::decay_t; + static_assert(HasReflection, "object type requires a tint::Reflect<> specialization"); + T::Reflection::Fields(object, callback); +} + +/// Macro used by TINT_FOREACH() in TINT_REFLECT() to call the callback function with each field in +/// the variadic. +#define TINT_REFLECT_CALLBACK_FIELD(field) callback(object.field); + +// TINT_REFLECT(...) reflects each of the fields arguments so that the types can be used with +// tint::ForeachField(). +#define TINT_REFLECT(...) \ + struct Reflection { \ + template \ + static void Fields(OBJECT&& object, CB&& callback) { \ + TINT_FOREACH(TINT_REFLECT_CALLBACK_FIELD, __VA_ARGS__) \ + } \ + } + +} // namespace tint + +#endif // SRC_TINT_REFLECTION_H_ diff --git a/src/tint/reflection_test.cc b/src/tint/reflection_test.cc new file mode 100644 index 0000000000..3c88b8dbd7 --- /dev/null +++ b/src/tint/reflection_test.cc @@ -0,0 +1,91 @@ +// Copyright 2022 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/tint/reflection.h" +#include "gtest/gtest.h" + +namespace tint { +namespace { + +struct S { + int i; + unsigned u; + bool b; + TINT_REFLECT(i, u, b); +}; + +static_assert(!HasReflection); +static_assert(HasReflection); + +TEST(ReflectionTest, ForeachFieldConst) { + const S s{1, 2, true}; + size_t field_idx = 0; + ForeachField(s, [&](auto& field) { + using T = std::decay_t; + switch (field_idx) { + case 0: + EXPECT_TRUE((std::is_same_v)); + EXPECT_EQ(field, static_cast(1)); + break; + case 1: + EXPECT_TRUE((std::is_same_v)); + EXPECT_EQ(field, static_cast(2)); + break; + case 2: + EXPECT_TRUE((std::is_same_v)); + EXPECT_EQ(field, static_cast(true)); + break; + default: + FAIL() << "unexpected field"; + break; + } + field_idx++; + }); +} + +TEST(ReflectionTest, ForeachFieldNonConst) { + S s{1, 2, true}; + size_t field_idx = 0; + ForeachField(s, [&](auto& field) { + using T = std::decay_t; + switch (field_idx) { + case 0: + EXPECT_TRUE((std::is_same_v)); + EXPECT_EQ(field, static_cast(1)); + field = static_cast(10); + break; + case 1: + EXPECT_TRUE((std::is_same_v)); + EXPECT_EQ(field, static_cast(2)); + field = static_cast(20); + break; + case 2: + EXPECT_TRUE((std::is_same_v)); + EXPECT_EQ(field, static_cast(true)); + field = static_cast(false); + break; + default: + FAIL() << "unexpected field"; + break; + } + field_idx++; + }); + + EXPECT_EQ(s.i, 10); + EXPECT_EQ(s.u, 20u); + EXPECT_EQ(s.b, false); +} + +} // namespace +} // namespace tint diff --git a/src/tint/sem/binding_point.h b/src/tint/sem/binding_point.h index 993fb5edad..b779b73512 100644 --- a/src/tint/sem/binding_point.h +++ b/src/tint/sem/binding_point.h @@ -19,6 +19,7 @@ #include +#include "src/tint/reflection.h" #include "src/tint/utils/hash.h" namespace tint::sem { @@ -30,6 +31,9 @@ struct BindingPoint { /// The `@binding` part of the binding point uint32_t binding = 0; + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(group, binding); + /// Equality operator /// @param rhs the BindingPoint to compare against /// @returns true if this BindingPoint is equal to `rhs` diff --git a/src/tint/transform/multiplanar_external_texture.h b/src/tint/transform/multiplanar_external_texture.h index afd15a1701..a10fed4c09 100644 --- a/src/tint/transform/multiplanar_external_texture.h +++ b/src/tint/transform/multiplanar_external_texture.h @@ -28,30 +28,33 @@ namespace tint::transform { /// BindingPoint is an alias to sem::BindingPoint using BindingPoint = sem::BindingPoint; -/// This struct identifies the binding groups and locations for new bindings to -/// use when transforming a texture_external instance. -struct BindingPoints { - /// The desired binding location of the texture_2d representing plane #1 when - /// a texture_external binding is expanded. - BindingPoint plane_1; - /// The desired binding location of the ExternalTextureParams uniform when a - /// texture_external binding is expanded. - BindingPoint params; -}; - /// Within the MultiplanarExternalTexture transform, each instance of a /// texture_external binding is unpacked into two texture_2d bindings /// representing two possible planes of a texture and a uniform buffer binding /// representing a struct of parameters. Calls to textureLoad or /// textureSampleLevel that contain a texture_external parameter will be /// transformed into a newly generated version of the function, which can -/// perform the desired operation on a single RGBA plane or on seperate Y and UV +/// perform the desired operation on a single RGBA plane or on separate Y and UV /// planes, and do colorspace conversions including yuv->rgb conversion, gamma /// decoding, gamut conversion, and gamma encoding steps. Specifically // for BT.709 to SRGB conversion, it takes the fast path only doing the yuv->rgb // step and skipping all other steps. class MultiplanarExternalTexture final : public Castable { public: + /// This struct identifies the binding groups and locations for new bindings to + /// use when transforming a texture_external instance. + struct BindingPoints { + /// The desired binding location of the texture_2d representing plane #1 when + /// a texture_external binding is expanded. + BindingPoint plane_1; + /// The desired binding location of the ExternalTextureParams uniform when a + /// texture_external binding is expanded. + BindingPoint params; + + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(plane_1, params); + }; + /// BindingsMap is a map where the key is the binding location of a /// texture_external and the value is a struct containing the desired /// locations for new bindings expanded from the texture_external instance. diff --git a/src/tint/transform/vertex_pulling.h b/src/tint/transform/vertex_pulling.h index 92eb627524..255a49a639 100644 --- a/src/tint/transform/vertex_pulling.h +++ b/src/tint/transform/vertex_pulling.h @@ -20,6 +20,7 @@ #include #include +#include "src/tint/reflection.h" #include "src/tint/transform/transform.h" namespace tint::transform { @@ -72,6 +73,9 @@ struct VertexAttributeDescriptor { uint32_t offset; /// The shader location used for the attribute uint32_t shader_location; + + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(format, offset, shader_location); }; /// Describes a buffer containing multiple vertex attributes @@ -102,6 +106,9 @@ struct VertexBufferLayoutDescriptor { VertexStepMode step_mode = VertexStepMode::kVertex; /// The vertex attributes std::vector attributes; + + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(array_stride, step_mode, attributes); }; /// Describes vertex state, which consists of many buffers containing vertex @@ -154,6 +161,9 @@ class VertexPulling final : public Castable { /// The "group" we will put all our vertex buffers into (as storage buffers) /// Default to 4 as it is past the limits of user-accessible groups uint32_t pulling_group = 4u; + + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(entry_point_name, vertex_state, pulling_group); }; /// Constructor diff --git a/src/tint/utils/foreach_macro.h b/src/tint/utils/foreach_macro.h new file mode 100644 index 0000000000..c76bfb3228 --- /dev/null +++ b/src/tint/utils/foreach_macro.h @@ -0,0 +1,91 @@ +// Copyright 2022 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_TINT_UTILS_FOREACH_MACRO_H_ +#define SRC_TINT_UTILS_FOREACH_MACRO_H_ + +// Macro magic to perform macro variadic dispatch. +// See: +// https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments +// Note, this doesn't attempt to use the ##__VA_ARGS__ trick to handle 0 + +// Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler. +#define TINT_MSVC_EXPAND_BUG(X) X + +/// TINT_COUNT_ARGUMENTS_NTH_ARG is used by TINT_COUNT_ARGUMENTS to get the number of arguments in a +/// variadic macro call. +#define TINT_COUNT_ARGUMENTS_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \ + _15, _16, N, ...) \ + N + +/// TINT_COUNT_ARGUMENTS evaluates to the number of arguments passed to the macro +#define TINT_COUNT_ARGUMENTS(...) \ + TINT_MSVC_EXPAND_BUG(TINT_COUNT_ARGUMENTS_NTH_ARG(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, \ + 8, 7, 6, 5, 4, 3, 2, 1, 0)) + +// Correctness checks. +static_assert(1 == TINT_COUNT_ARGUMENTS(a), "TINT_COUNT_ARGUMENTS broken"); +static_assert(2 == TINT_COUNT_ARGUMENTS(a, b), "TINT_COUNT_ARGUMENTS broken"); +static_assert(3 == TINT_COUNT_ARGUMENTS(a, b, c), "TINT_COUNT_ARGUMENTS broken"); + +/// TINT_FOREACH calls CB with each of the variadic arguments. +#define TINT_FOREACH(CB, ...) \ + TINT_MSVC_EXPAND_BUG( \ + TINT_CONCAT(TINT_FOREACH_, TINT_COUNT_ARGUMENTS(__VA_ARGS__))(CB, __VA_ARGS__)) + +#define TINT_FOREACH_1(CB, _1) CB(_1) +#define TINT_FOREACH_2(CB, _1, _2) \ + TINT_FOREACH_1(CB, _1) \ + CB(_2) +#define TINT_FOREACH_3(CB, _1, _2, _3) \ + TINT_FOREACH_2(CB, _1, _2) \ + CB(_3) +#define TINT_FOREACH_4(CB, _1, _2, _3, _4) \ + TINT_FOREACH_3(CB, _1, _2, _3) \ + CB(_4) +#define TINT_FOREACH_5(CB, _1, _2, _3, _4, _5) \ + TINT_FOREACH_4(CB, _1, _2, _3, _4) \ + CB(_5) +#define TINT_FOREACH_6(CB, _1, _2, _3, _4, _5, _6) \ + TINT_FOREACH_5(CB, _1, _2, _3, _4, _5) \ + CB(_6) +#define TINT_FOREACH_7(CB, _1, _2, _3, _4, _5, _6, _7) \ + TINT_FOREACH_6(CB, _1, _2, _3, _4, _5, _6) \ + CB(_7) +#define TINT_FOREACH_8(CB, _1, _2, _3, _4, _5, _6, _7, _8) \ + TINT_FOREACH_7(CB, _1, _2, _3, _4, _5, _6, _7) \ + CB(_8) +#define TINT_FOREACH_9(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + TINT_FOREACH_8(CB, _1, _2, _3, _4, _5, _6, _7, _8) \ + CB(_9) +#define TINT_FOREACH_10(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ + TINT_FOREACH_9(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + CB(_10) +#define TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ + TINT_FOREACH_10(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ + CB(_11) +#define TINT_FOREACH_12(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ + TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ + CB(_12) +#define TINT_FOREACH_13(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ + TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ + CB(_13) +#define TINT_FOREACH_14(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ + TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ + CB(_14) +#define TINT_FOREACH_15(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ + TINT_FOREACH_11(CB, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ + CB(_15) + +#endif // SRC_TINT_UTILS_FOREACH_MACRO_H_ diff --git a/src/tint/writer/array_length_from_uniform_options.h b/src/tint/writer/array_length_from_uniform_options.h index cfa2fbd873..41d873eb8b 100644 --- a/src/tint/writer/array_length_from_uniform_options.h +++ b/src/tint/writer/array_length_from_uniform_options.h @@ -43,8 +43,8 @@ struct ArrayLengthFromUniformOptions { /// uniform buffer where the length of the buffer is stored. std::unordered_map bindpoint_to_size_index; - // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any - // struct members. + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(ubo_binding, bindpoint_to_size_index); }; } // namespace tint::writer diff --git a/src/tint/writer/generate_external_texture_bindings.cc b/src/tint/writer/generate_external_texture_bindings.cc index 16c33e3083..6408e0e56e 100644 --- a/src/tint/writer/generate_external_texture_bindings.cc +++ b/src/tint/writer/generate_external_texture_bindings.cc @@ -50,7 +50,8 @@ transform::MultiplanarExternalTexture::BindingsMap GenerateExternalTextureBindin for (auto bp : ext_tex_bps) { uint32_t g = bp.group; uint32_t& next_num = group_to_next_binding_number[g]; - auto new_bps = transform::BindingPoints{{g, next_num++}, {g, next_num++}}; + auto new_bps = + transform::MultiplanarExternalTexture::BindingPoints{{g, next_num++}, {g, next_num++}}; new_bindings_map[bp] = new_bps; } return new_bindings_map; diff --git a/src/tint/writer/hlsl/generator.h b/src/tint/writer/hlsl/generator.h index 233416ea99..9974cdef47 100644 --- a/src/tint/writer/hlsl/generator.h +++ b/src/tint/writer/hlsl/generator.h @@ -23,6 +23,7 @@ #include #include "src/tint/ast/pipeline_stage.h" +#include "src/tint/reflection.h" #include "src/tint/sem/binding_point.h" #include "src/tint/writer/array_length_from_uniform_options.h" #include "src/tint/writer/text.h" @@ -56,8 +57,11 @@ struct Options { /// from which to load buffer sizes. ArrayLengthFromUniformOptions array_length_from_uniform = {}; - // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any - // struct members. + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(root_constant_binding_point, + disable_workgroup_init, + generate_external_texture_bindings, + array_length_from_uniform); }; /// The result produced when generating HLSL. diff --git a/src/tint/writer/msl/generator.h b/src/tint/writer/msl/generator.h index d4208cc262..bdc2be58b7 100644 --- a/src/tint/writer/msl/generator.h +++ b/src/tint/writer/msl/generator.h @@ -21,6 +21,7 @@ #include #include +#include "src/tint/reflection.h" #include "src/tint/writer/array_length_from_uniform_options.h" #include "src/tint/writer/text.h" @@ -65,8 +66,13 @@ struct Options { /// from which to load buffer sizes. ArrayLengthFromUniformOptions array_length_from_uniform = {}; - // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any - // struct members. + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(buffer_size_ubo_index, + fixed_sample_mask, + emit_vertex_point_size, + disable_workgroup_init, + generate_external_texture_bindings, + array_length_from_uniform); }; /// The result produced when generating MSL. diff --git a/src/tint/writer/spirv/generator.h b/src/tint/writer/spirv/generator.h index ce871ffc9a..e406f6ea1e 100644 --- a/src/tint/writer/spirv/generator.h +++ b/src/tint/writer/spirv/generator.h @@ -19,6 +19,7 @@ #include #include +#include "src/tint/reflection.h" #include "src/tint/writer/writer.h" // Forward declarations @@ -47,6 +48,12 @@ struct Options { /// Set to `true` to initialize workgroup memory with OpConstantNull when /// VK_KHR_zero_initialize_workgroup_memory is enabled. bool use_zero_initialize_workgroup_memory_extension = false; + + /// Reflect the fields of this class so that it can be used by tint::ForeachField() + TINT_REFLECT(emit_vertex_point_size, + disable_workgroup_init, + generate_external_texture_bindings, + use_zero_initialize_workgroup_memory_extension); }; /// The result produced when generating SPIR-V.