tint: Add TINT_REFLECT() & ForeachField()

This uses template and macro magic to reflect the fields of a class.

Dawn:
* Reflect the fields of the types that are used by Dawn's stream::Stream<T> specializations, and use tint::ForeachField() to call StreamIn().

Fuzzers:
* Replace tint::fuzzers::DataBuilder::BuildImpl<T> specializations with the new reflection system.
* static_assert that the type is either POD or reflected. Add a specialization for std::optional which was missing.

Move tint::transform::BindingPoints into MultiplanarExternalTexture, as this is only used by MultiplanarExternalTexture.

All this reduces fragility of the struct declarations slipping out of sync with the uses.

Bug: tint:1640
Change-Id: I08729c1c356f1b427e85983efe3c2678fc2ce717
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/101001
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
Ben Clayton 2022-09-02 11:40:19 +00:00 committed by Dawn LUCI CQ
parent bd6bcf1e0c
commit 648bd7b4be
16 changed files with 359 additions and 135 deletions

View File

@ -19,6 +19,15 @@
namespace dawn::native {
namespace {
template <typename OBJECT>
void StreamInTintObject(const OBJECT& object, stream::Sink* sink) {
tint::ForeachField(object, [&](auto& field) { StreamIn(sink, field); });
}
} // namespace
// static
template <>
void stream::Stream<tint::Program>::Write(stream::Sink* sink, const tint::Program& p) {
@ -36,82 +45,48 @@ void stream::Stream<tint::Program>::Write(stream::Sink* sink, const tint::Progra
// static
template <>
void stream::Stream<tint::sem::BindingPoint>::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<tint::transform::BindingPoints>::Write(
void stream::Stream<tint::transform::MultiplanarExternalTexture::BindingPoints>::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<tint::transform::VertexPulling::Config>::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<tint::transform::VertexBufferLayoutDescriptor>::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<tint::transform::VertexAttributeDescriptor>::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<tint::writer::ArrayLengthFromUniformOptions>::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

View File

@ -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},
};

View File

@ -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",

View File

@ -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

View File

@ -17,6 +17,7 @@
#include <cassert>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
@ -128,11 +129,26 @@ class DataBuilder {
/// @returns a variable of type T filled with pseudo-random data
static T impl(DataBuilder* b) {
T out{};
if constexpr (tint::HasReflection<T>) {
ForeachField(out, [&](auto& field) { b->build(field); });
} else if constexpr (std::is_pod_v<T>) {
b->build(&out, sizeof(T));
} else {
static_assert(sizeof(T) == 0, "cannot build type");
}
return out;
}
};
/// Specialization for bool
template <>
struct BuildImpl<bool> {
/// 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<std::string> {
@ -150,74 +166,17 @@ class DataBuilder {
}
};
/// Specialization for bool
template <>
struct BuildImpl<bool> {
/// Generate a pseudo-random bool
/// Specialization for std::optional
template <typename T>
struct BuildImpl<std::optional<T>> {
/// Generate a pseudo-random optional<T>
/// @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<writer::msl::Options> {
/// 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;
/// @returns a either a nullopt, or a randomly filled T
static std::optional<T> impl(DataBuilder* b) {
if (b->build<bool>()) {
return b->build<T>();
}
};
/// Specialization for writer::hlsl::Options
template <>
struct BuildImpl<writer::hlsl::Options> {
/// 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<writer::spirv::Options> {
/// 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<writer::ArrayLengthFromUniformOptions> {
/// 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;
return std::nullopt;
}
};

67
src/tint/reflection.h Normal file
View File

@ -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 <typename T, typename ENABLE = void>
struct HasReflection : std::false_type {};
/// Specialization for types that have a nested Reflection class.
template <typename T>
struct HasReflection<T, std::void_t<typename T::Reflection>> : std::true_type {};
} // namespace detail
/// Is true if the class T has reflected its fields with TINT_REFLECT()
template <typename T>
static constexpr bool HasReflection = detail::HasReflection<T>::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 <typename OBJECT, typename CB>
void ForeachField(OBJECT&& object, CB&& callback) {
using T = std::decay_t<OBJECT>;
static_assert(HasReflection<T>, "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 <typename OBJECT, typename CB> \
static void Fields(OBJECT&& object, CB&& callback) { \
TINT_FOREACH(TINT_REFLECT_CALLBACK_FIELD, __VA_ARGS__) \
} \
}
} // namespace tint
#endif // SRC_TINT_REFLECTION_H_

View File

@ -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<int>);
static_assert(HasReflection<S>);
TEST(ReflectionTest, ForeachFieldConst) {
const S s{1, 2, true};
size_t field_idx = 0;
ForeachField(s, [&](auto& field) {
using T = std::decay_t<decltype(field)>;
switch (field_idx) {
case 0:
EXPECT_TRUE((std::is_same_v<T, int>));
EXPECT_EQ(field, static_cast<T>(1));
break;
case 1:
EXPECT_TRUE((std::is_same_v<T, unsigned>));
EXPECT_EQ(field, static_cast<T>(2));
break;
case 2:
EXPECT_TRUE((std::is_same_v<T, bool>));
EXPECT_EQ(field, static_cast<T>(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<decltype(field)>;
switch (field_idx) {
case 0:
EXPECT_TRUE((std::is_same_v<T, int>));
EXPECT_EQ(field, static_cast<T>(1));
field = static_cast<T>(10);
break;
case 1:
EXPECT_TRUE((std::is_same_v<T, unsigned>));
EXPECT_EQ(field, static_cast<T>(2));
field = static_cast<T>(20);
break;
case 2:
EXPECT_TRUE((std::is_same_v<T, bool>));
EXPECT_EQ(field, static_cast<T>(true));
field = static_cast<T>(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

View File

@ -19,6 +19,7 @@
#include <functional>
#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`

View File

@ -28,6 +28,19 @@ namespace tint::transform {
/// BindingPoint is an alias to sem::BindingPoint
using BindingPoint = sem::BindingPoint;
/// Within the MultiplanarExternalTexture transform, each instance of a
/// texture_external binding is unpacked into two texture_2d<f32> 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 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<MultiplanarExternalTexture, Transform> {
public:
/// This struct identifies the binding groups and locations for new bindings to
/// use when transforming a texture_external instance.
struct BindingPoints {
@ -37,21 +50,11 @@ struct BindingPoints {
/// 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);
};
/// Within the MultiplanarExternalTexture transform, each instance of a
/// texture_external binding is unpacked into two texture_2d<f32> 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
/// 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<MultiplanarExternalTexture, Transform> {
public:
/// 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.

View File

@ -20,6 +20,7 @@
#include <unordered_map>
#include <vector>
#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<VertexAttributeDescriptor> 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<VertexPulling, Transform> {
/// 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

View File

@ -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_

View File

@ -43,8 +43,8 @@ struct ArrayLengthFromUniformOptions {
/// uniform buffer where the length of the buffer is stored.
std::unordered_map<sem::BindingPoint, uint32_t> 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

View File

@ -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;

View File

@ -23,6 +23,7 @@
#include <vector>
#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.

View File

@ -21,6 +21,7 @@
#include <unordered_set>
#include <vector>
#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.

View File

@ -19,6 +19,7 @@
#include <string>
#include <vector>
#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.