bevy_render/render_resource/buffer_vec.rs
1use core::{iter, marker::PhantomData};
2
3use crate::{
4 render_resource::Buffer,
5 renderer::{RenderDevice, RenderQueue},
6};
7use bytemuck::{must_cast_slice, NoUninit};
8use encase::{
9 internal::{WriteInto, Writer},
10 ShaderType,
11};
12use wgpu::{BindingResource, BufferAddress, BufferUsages};
13
14use super::GpuArrayBufferable;
15
16/// A structure for storing raw bytes that have already been properly formatted
17/// for use by the GPU.
18///
19/// "Properly formatted" means that item data already meets the alignment and padding
20/// requirements for how it will be used on the GPU. The item type must implement [`NoUninit`]
21/// for its data representation to be directly copyable.
22///
23/// Index, vertex, and instance-rate vertex buffers have no alignment nor padding requirements and
24/// so this helper type is a good choice for them.
25///
26/// The contained data is stored in system RAM. Calling [`reserve`](RawBufferVec::reserve)
27/// allocates VRAM from the [`RenderDevice`].
28/// [`write_buffer`](RawBufferVec::write_buffer) queues copying of the data
29/// from system RAM to VRAM.
30///
31/// Other options for storing GPU-accessible data are:
32/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
33/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
34/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
35/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
36/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)
37/// * [`BufferVec`]
38/// * [`Texture`](crate::render_resource::Texture)
39pub struct RawBufferVec<T: NoUninit> {
40 values: Vec<T>,
41 buffer: Option<Buffer>,
42 capacity: usize,
43 item_size: usize,
44 buffer_usage: BufferUsages,
45 label: Option<String>,
46 changed: bool,
47}
48
49impl<T: NoUninit> RawBufferVec<T> {
50 /// Creates a new [`RawBufferVec`] with the given [`BufferUsages`].
51 pub const fn new(buffer_usage: BufferUsages) -> Self {
52 Self {
53 values: Vec::new(),
54 buffer: None,
55 capacity: 0,
56 item_size: size_of::<T>(),
57 buffer_usage,
58 label: None,
59 changed: false,
60 }
61 }
62
63 /// Returns a handle to the buffer, if the data has been uploaded.
64 #[inline]
65 pub fn buffer(&self) -> Option<&Buffer> {
66 self.buffer.as_ref()
67 }
68
69 /// Returns the binding for the buffer if the data has been uploaded.
70 #[inline]
71 pub fn binding(&self) -> Option<BindingResource> {
72 Some(BindingResource::Buffer(
73 self.buffer()?.as_entire_buffer_binding(),
74 ))
75 }
76
77 /// Returns the amount of space that the GPU will use before reallocating.
78 #[inline]
79 pub fn capacity(&self) -> usize {
80 self.capacity
81 }
82
83 /// Returns the number of items that have been pushed to this buffer.
84 #[inline]
85 pub fn len(&self) -> usize {
86 self.values.len()
87 }
88
89 /// Returns true if the buffer is empty.
90 #[inline]
91 pub fn is_empty(&self) -> bool {
92 self.values.is_empty()
93 }
94
95 /// Adds a new value and returns its index.
96 pub fn push(&mut self, value: T) -> usize {
97 let index = self.values.len();
98 self.values.push(value);
99 index
100 }
101
102 pub fn append(&mut self, other: &mut RawBufferVec<T>) {
103 self.values.append(&mut other.values);
104 }
105
106 /// Changes the debugging label of the buffer.
107 ///
108 /// The next time the buffer is updated (via [`reserve`](Self::reserve)), Bevy will inform
109 /// the driver of the new label.
110 pub fn set_label(&mut self, label: Option<&str>) {
111 let label = label.map(str::to_string);
112
113 if label != self.label {
114 self.changed = true;
115 }
116
117 self.label = label;
118 }
119
120 /// Returns the label
121 pub fn get_label(&self) -> Option<&str> {
122 self.label.as_deref()
123 }
124
125 /// Creates a [`Buffer`] on the [`RenderDevice`] with size
126 /// at least `size_of::<T>() * capacity`, unless a such a buffer already exists.
127 ///
128 /// If a [`Buffer`] exists, but is too small, references to it will be discarded,
129 /// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s
130 /// that are no longer referenced will be deleted by the [`RenderDevice`]
131 /// once it is done using them (typically 1-2 frames).
132 ///
133 /// In addition to any [`BufferUsages`] provided when
134 /// the `RawBufferVec` was created, the buffer on the [`RenderDevice`]
135 /// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
136 pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
137 let size = self.item_size * capacity;
138 if capacity > self.capacity || (self.changed && size > 0) {
139 self.capacity = capacity;
140 self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
141 label: self.label.as_deref(),
142 size: size as BufferAddress,
143 usage: BufferUsages::COPY_DST | self.buffer_usage,
144 mapped_at_creation: false,
145 }));
146 self.changed = false;
147 }
148 }
149
150 /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
151 /// and the provided [`RenderQueue`].
152 ///
153 /// Before queuing the write, a [`reserve`](RawBufferVec::reserve) operation
154 /// is executed.
155 pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
156 if self.values.is_empty() {
157 return;
158 }
159 self.reserve(self.values.len(), device);
160 if let Some(buffer) = &self.buffer {
161 let range = 0..self.item_size * self.values.len();
162 let bytes: &[u8] = must_cast_slice(&self.values);
163 queue.write_buffer(buffer, 0, &bytes[range]);
164 }
165 }
166
167 /// Reduces the length of the buffer.
168 pub fn truncate(&mut self, len: usize) {
169 self.values.truncate(len);
170 }
171
172 /// Removes all elements from the buffer.
173 pub fn clear(&mut self) {
174 self.values.clear();
175 }
176
177 pub fn values(&self) -> &Vec<T> {
178 &self.values
179 }
180
181 pub fn values_mut(&mut self) -> &mut Vec<T> {
182 &mut self.values
183 }
184}
185
186impl<T: NoUninit> Extend<T> for RawBufferVec<T> {
187 #[inline]
188 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
189 self.values.extend(iter);
190 }
191}
192
193/// Like [`RawBufferVec`], but doesn't require that the data type `T` be
194/// [`NoUninit`].
195///
196/// This is a high-performance data structure that you should use whenever
197/// possible if your data is more complex than is suitable for [`RawBufferVec`].
198/// The [`ShaderType`] trait from the `encase` library is used to ensure that
199/// the data is correctly aligned for use by the GPU.
200///
201/// For performance reasons, unlike [`RawBufferVec`], this type doesn't allow
202/// CPU access to the data after it's been added via [`BufferVec::push`]. If you
203/// need CPU access to the data, consider another type, such as
204/// [`StorageBuffer`][super::StorageBuffer].
205pub struct BufferVec<T>
206where
207 T: ShaderType + WriteInto,
208{
209 data: Vec<u8>,
210 buffer: Option<Buffer>,
211 capacity: usize,
212 buffer_usage: BufferUsages,
213 label: Option<String>,
214 label_changed: bool,
215 phantom: PhantomData<T>,
216}
217
218impl<T> BufferVec<T>
219where
220 T: ShaderType + WriteInto,
221{
222 /// Creates a new [`BufferVec`] with the given [`BufferUsages`].
223 pub const fn new(buffer_usage: BufferUsages) -> Self {
224 Self {
225 data: vec![],
226 buffer: None,
227 capacity: 0,
228 buffer_usage,
229 label: None,
230 label_changed: false,
231 phantom: PhantomData,
232 }
233 }
234
235 /// Returns a handle to the buffer, if the data has been uploaded.
236 #[inline]
237 pub fn buffer(&self) -> Option<&Buffer> {
238 self.buffer.as_ref()
239 }
240
241 /// Returns the binding for the buffer if the data has been uploaded.
242 #[inline]
243 pub fn binding(&self) -> Option<BindingResource> {
244 Some(BindingResource::Buffer(
245 self.buffer()?.as_entire_buffer_binding(),
246 ))
247 }
248
249 /// Returns the amount of space that the GPU will use before reallocating.
250 #[inline]
251 pub fn capacity(&self) -> usize {
252 self.capacity
253 }
254
255 /// Returns the number of items that have been pushed to this buffer.
256 #[inline]
257 pub fn len(&self) -> usize {
258 self.data.len() / u64::from(T::min_size()) as usize
259 }
260
261 /// Returns true if the buffer is empty.
262 #[inline]
263 pub fn is_empty(&self) -> bool {
264 self.data.is_empty()
265 }
266
267 /// Adds a new value and returns its index.
268 pub fn push(&mut self, value: T) -> usize {
269 let element_size = u64::from(T::min_size()) as usize;
270 let offset = self.data.len();
271
272 // TODO: Consider using unsafe code to push uninitialized, to prevent
273 // the zeroing. It shows up in profiles.
274 self.data.extend(iter::repeat(0).take(element_size));
275
276 // Take a slice of the new data for `write_into` to use. This is
277 // important: it hoists the bounds check up here so that the compiler
278 // can eliminate all the bounds checks that `write_into` will emit.
279 let mut dest = &mut self.data[offset..(offset + element_size)];
280 value.write_into(&mut Writer::new(&value, &mut dest, 0).unwrap());
281
282 offset / u64::from(T::min_size()) as usize
283 }
284
285 /// Changes the debugging label of the buffer.
286 ///
287 /// The next time the buffer is updated (via [`Self::reserve`]), Bevy will inform
288 /// the driver of the new label.
289 pub fn set_label(&mut self, label: Option<&str>) {
290 let label = label.map(str::to_string);
291
292 if label != self.label {
293 self.label_changed = true;
294 }
295
296 self.label = label;
297 }
298
299 /// Returns the label
300 pub fn get_label(&self) -> Option<&str> {
301 self.label.as_deref()
302 }
303
304 /// Creates a [`Buffer`] on the [`RenderDevice`] with size
305 /// at least `size_of::<T>() * capacity`, unless such a buffer already exists.
306 ///
307 /// If a [`Buffer`] exists, but is too small, references to it will be discarded,
308 /// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s
309 /// that are no longer referenced will be deleted by the [`RenderDevice`]
310 /// once it is done using them (typically 1-2 frames).
311 ///
312 /// In addition to any [`BufferUsages`] provided when
313 /// the `BufferVec` was created, the buffer on the [`RenderDevice`]
314 /// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
315 pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
316 if capacity <= self.capacity && !self.label_changed {
317 return;
318 }
319
320 self.capacity = capacity;
321 let size = u64::from(T::min_size()) as usize * capacity;
322 self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
323 label: self.label.as_deref(),
324 size: size as BufferAddress,
325 usage: BufferUsages::COPY_DST | self.buffer_usage,
326 mapped_at_creation: false,
327 }));
328 self.label_changed = false;
329 }
330
331 /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
332 /// and the provided [`RenderQueue`].
333 ///
334 /// Before queuing the write, a [`reserve`](BufferVec::reserve) operation is
335 /// executed.
336 pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
337 if self.data.is_empty() {
338 return;
339 }
340
341 self.reserve(self.data.len() / u64::from(T::min_size()) as usize, device);
342
343 let Some(buffer) = &self.buffer else { return };
344 queue.write_buffer(buffer, 0, &self.data);
345 }
346
347 /// Reduces the length of the buffer.
348 pub fn truncate(&mut self, len: usize) {
349 self.data.truncate(u64::from(T::min_size()) as usize * len);
350 }
351
352 /// Removes all elements from the buffer.
353 pub fn clear(&mut self) {
354 self.data.clear();
355 }
356}
357
358/// Like a [`BufferVec`], but only reserves space on the GPU for elements
359/// instead of initializing them CPU-side.
360///
361/// This type is useful when you're accumulating "output slots" for a GPU
362/// compute shader to write into.
363///
364/// The type `T` need not be [`NoUninit`], unlike [`RawBufferVec`]; it only has to
365/// be [`GpuArrayBufferable`].
366pub struct UninitBufferVec<T>
367where
368 T: GpuArrayBufferable,
369{
370 buffer: Option<Buffer>,
371 len: usize,
372 capacity: usize,
373 item_size: usize,
374 buffer_usage: BufferUsages,
375 label: Option<String>,
376 label_changed: bool,
377 phantom: PhantomData<T>,
378}
379
380impl<T> UninitBufferVec<T>
381where
382 T: GpuArrayBufferable,
383{
384 /// Creates a new [`UninitBufferVec`] with the given [`BufferUsages`].
385 pub const fn new(buffer_usage: BufferUsages) -> Self {
386 Self {
387 len: 0,
388 buffer: None,
389 capacity: 0,
390 item_size: size_of::<T>(),
391 buffer_usage,
392 label: None,
393 label_changed: false,
394 phantom: PhantomData,
395 }
396 }
397
398 /// Returns the buffer, if allocated.
399 #[inline]
400 pub fn buffer(&self) -> Option<&Buffer> {
401 self.buffer.as_ref()
402 }
403
404 /// Returns the binding for the buffer if the data has been uploaded.
405 #[inline]
406 pub fn binding(&self) -> Option<BindingResource> {
407 Some(BindingResource::Buffer(
408 self.buffer()?.as_entire_buffer_binding(),
409 ))
410 }
411
412 /// Reserves space for one more element in the buffer and returns its index.
413 pub fn add(&mut self) -> usize {
414 let index = self.len;
415 self.len += 1;
416 index
417 }
418
419 /// Returns true if no elements have been added to this [`UninitBufferVec`].
420 pub fn is_empty(&self) -> bool {
421 self.len == 0
422 }
423
424 /// Removes all elements from the buffer.
425 pub fn clear(&mut self) {
426 self.len = 0;
427 }
428
429 /// Returns the length of the buffer.
430 pub fn len(&self) -> usize {
431 self.len
432 }
433
434 /// Materializes the buffer on the GPU with space for `capacity` elements.
435 ///
436 /// If the buffer is already big enough, this function doesn't reallocate
437 /// the buffer.
438 pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
439 if capacity <= self.capacity && !self.label_changed {
440 return;
441 }
442
443 self.capacity = capacity;
444 let size = self.item_size * capacity;
445 self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
446 label: self.label.as_deref(),
447 size: size as BufferAddress,
448 usage: BufferUsages::COPY_DST | self.buffer_usage,
449 mapped_at_creation: false,
450 }));
451
452 self.label_changed = false;
453 }
454
455 /// Materializes the buffer on the GPU, with an appropriate size for the
456 /// elements that have been pushed so far.
457 pub fn write_buffer(&mut self, device: &RenderDevice) {
458 if !self.is_empty() {
459 self.reserve(self.len, device);
460 }
461 }
462}