1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//! Utilities that allow updating of large POD structures from multiple threads.
//!
//! In a select few cases, for performance reasons, we want to update "plain
//! old data"—data without any pointers—from helper threads, without having to
//! send the new data over a channel first. These utilities allow code that
//! needs to perform this operation to do so without dropping down to unsafe
//! code.
//!
//! Note that, while this operation is always *memory* safe, it isn't free of
//! potential data races. Updating large amounts of POD atomically, word by
//! word, amplifies the consequences of data races, because write hazards can
//! result in data "slicing". That is, one thread can see the results of a copy
//! operation in progress, a situation which ordinary atomics prevent. So you
//! should use the functionality in here sparingly and only when measured
//! performance concerns justify it.
use Pod;
/// Data that can be converted to an array of [`std::sync::atomic::AtomicU32`]
/// values.
///
/// That array is known as the *blob* ([`Self::Blob`]). The trait provides
/// methods to copy data into and out of the blob type.
///
/// Note that, while implementing this trait isn't unsafe, it can be tedious,
/// and in any case implementing [`AtomicPodBlob`] *is* unsafe. Therefore, you
/// should almost always use the `impl_atomic_pod!` macro to produce
/// implementations of this trait.
/// Describes a type that has the same bit pattern as another type, but is made
/// up entirely of an array of [`std::sync::atomic::AtomicU32`] values.
///
/// This trait enables values of whatever type this mirrors to be written from
/// multiple threads. It's memory-safe because the type must be POD. However,
/// this doesn't protect against data races; it's possible for safe code to see
/// partially-updated values, which might be incorrect. Therefore, use this type
/// with caution.
///
/// The [`crate::impl_atomic_pod`] macro that generates an implementation of
/// [`AtomicPod`] automatically generates a blob type that implements
/// [`AtomicPodBlob`]. This is the preferred way to implement this trait and
/// doesn't require any unsafe code.
///
/// # Safety
///
/// This trait must only be implemented by types that are `#[repr(transparent)]`
/// wrappers around `[AtomicU32; N]` for some N (where N may legally be 0).
/// That's because values implementing this trait are read as a `&[u8]` when
/// uploading to the GPU.
pub unsafe
/// A macro that generates a *blob* type that allows a POD type to be updated in
/// shared memory.
///
/// An example of use of this macro:
///
/// ```
/// # use bevy_render::impl_atomic_pod;
/// # use bevy_render::render_resource::AtomicPod;
/// # use bytemuck::{Pod, Zeroable};
/// # use std::mem::offset_of;
/// #[derive(Clone, Copy, Default, Pod, Zeroable)]
/// #[repr(C)]
/// struct Foo {
/// a: u32,
/// b: u32,
/// }
/// impl_atomic_pod!(
/// Foo,
/// FooBlob,
/// field(a: u32, a, set_a),
/// field(b: u32, b, set_b),
/// );
/// ```
///
/// The first argument to this macro is the name of the type that you wish to be
/// updatable in shared memory. The second argument is the name of a "blob"
/// type: conventionally, it matches the name of the type with `Blob` appended.
///
/// Afterward follow optional *field getter and setter* declarations. These
/// declarations direct the [`crate::impl_atomic_pod`] macro to create
/// convenience accessor and mutation methods that allow fields of the blob
/// value to be accessed and mutated. The first argument of `field` is the name
/// of the field, a `:`, and the type of the field. The second argument is the
/// name that this macro should assign the accessor method, and the third,
/// optional, argument is the name that this macro should give the mutator
/// method.
///
/// This macro generates (1) the `struct` corresponding to the blob type; (2)
/// the implementation of `AtomicPod` for the POD type; (3) the unsafe
/// implementation of `AtomicPodBlob`; (4) an inherent implementation of
/// `AtomicPodBlob` that contains accessor and mutator methods as directed.
///
/// The POD type must have a size that's a multiple of 4 bytes, as must the
/// types of any fields that are named in `field` declarations.
);
must_cast
}
}
// SAFETY: Atomic POD blobs must be bit-castable to a flat list of
// `AtomicU32`s, which we ensured above.
unsafe
};
}
impl_atomic_pod!;