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 thiserror::Error;
13use wgpu::{BindingResource, BufferAddress, BufferUsages};
14
15use super::GpuArrayBufferable;
16
17/// A structure for storing raw bytes that have already been properly formatted
18/// for use by the GPU.
19///
20/// "Properly formatted" means that item data already meets the alignment and padding
21/// requirements for how it will be used on the GPU. The item type must implement [`NoUninit`]
22/// for its data representation to be directly copyable.
23///
24/// Index, vertex, and instance-rate vertex buffers have no alignment nor padding requirements and
25/// so this helper type is a good choice for them.
26///
27/// The contained data is stored in system RAM. Calling [`reserve`](RawBufferVec::reserve)
28/// allocates VRAM from the [`RenderDevice`].
29/// [`write_buffer`](RawBufferVec::write_buffer) queues copying of the data
30/// from system RAM to VRAM.
31///
32/// Other options for storing GPU-accessible data are:
33/// * [`BufferVec`]
34/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
35/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
36/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)
37/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
38/// * [`Texture`](crate::render_resource::Texture)
39/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
40pub struct RawBufferVec<T: NoUninit> {
41    values: Vec<T>,
42    buffer: Option<Buffer>,
43    capacity: usize,
44    item_size: usize,
45    buffer_usage: BufferUsages,
46    label: Option<String>,
47    changed: bool,
48}
49
50impl<T: NoUninit> RawBufferVec<T> {
51    /// Creates a new [`RawBufferVec`] with the given [`BufferUsages`].
52    pub const fn new(buffer_usage: BufferUsages) -> Self {
53        Self {
54            values: Vec::new(),
55            buffer: None,
56            capacity: 0,
57            item_size: size_of::<T>(),
58            buffer_usage,
59            label: None,
60            changed: false,
61        }
62    }
63
64    /// Returns a handle to the buffer, if the data has been uploaded.
65    #[inline]
66    pub fn buffer(&self) -> Option<&Buffer> {
67        self.buffer.as_ref()
68    }
69
70    /// Returns the binding for the buffer if the data has been uploaded.
71    #[inline]
72    pub fn binding(&self) -> Option<BindingResource<'_>> {
73        Some(BindingResource::Buffer(
74            self.buffer()?.as_entire_buffer_binding(),
75        ))
76    }
77
78    /// Returns the amount of space that the GPU will use before reallocating.
79    #[inline]
80    pub fn capacity(&self) -> usize {
81        self.capacity
82    }
83
84    /// Returns the number of items that have been pushed to this buffer.
85    #[inline]
86    pub fn len(&self) -> usize {
87        self.values.len()
88    }
89
90    /// Returns true if the buffer is empty.
91    #[inline]
92    pub fn is_empty(&self) -> bool {
93        self.values.is_empty()
94    }
95
96    /// Adds a new value and returns its index.
97    pub fn push(&mut self, value: T) -> usize {
98        let index = self.values.len();
99        self.values.push(value);
100        index
101    }
102
103    pub fn append(&mut self, other: &mut RawBufferVec<T>) {
104        self.values.append(&mut other.values);
105    }
106
107    /// Returns the value at the given index.
108    pub fn get(&self, index: u32) -> Option<&T> {
109        self.values.get(index as usize)
110    }
111
112    /// Sets the value at the given index.
113    ///
114    /// The index must be less than [`RawBufferVec::len`].
115    pub fn set(&mut self, index: u32, value: T) {
116        self.values[index as usize] = value;
117    }
118
119    /// Preallocates space for `count` elements in the internal CPU-side buffer.
120    ///
121    /// Unlike [`RawBufferVec::reserve`], this doesn't have any effect on the GPU buffer.
122    pub fn reserve_internal(&mut self, count: usize) {
123        self.values.reserve(count);
124    }
125
126    /// Changes the debugging label of the buffer.
127    ///
128    /// The next time the buffer is updated (via [`reserve`](Self::reserve)), Bevy will inform
129    /// the driver of the new label.
130    pub fn set_label(&mut self, label: Option<&str>) {
131        let label = label.map(str::to_string);
132
133        if label != self.label {
134            self.changed = true;
135        }
136
137        self.label = label;
138    }
139
140    /// Returns the label
141    pub fn get_label(&self) -> Option<&str> {
142        self.label.as_deref()
143    }
144
145    /// Creates a [`Buffer`] on the [`RenderDevice`] with size
146    /// at least `size_of::<T>() * capacity`, unless a such a buffer already exists.
147    ///
148    /// If a [`Buffer`] exists, but is too small, references to it will be discarded,
149    /// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s
150    /// that are no longer referenced will be deleted by the [`RenderDevice`]
151    /// once it is done using them (typically 1-2 frames).
152    ///
153    /// In addition to any [`BufferUsages`] provided when
154    /// the `RawBufferVec` was created, the buffer on the [`RenderDevice`]
155    /// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
156    pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
157        let size = self.item_size * capacity;
158        if capacity > self.capacity || (self.changed && size > 0) {
159            self.capacity = capacity;
160            self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
161                label: self.label.as_deref(),
162                size: size as BufferAddress,
163                usage: BufferUsages::COPY_DST | self.buffer_usage,
164                mapped_at_creation: false,
165            }));
166            self.changed = false;
167        }
168    }
169
170    /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
171    /// and the provided [`RenderQueue`].
172    ///
173    /// Before queuing the write, a [`reserve`](RawBufferVec::reserve) operation
174    /// is executed.
175    pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
176        if self.values.is_empty() {
177            return;
178        }
179        self.reserve(self.values.len(), device);
180        if let Some(buffer) = &self.buffer {
181            let range = 0..self.item_size * self.values.len();
182            let bytes: &[u8] = must_cast_slice(&self.values);
183            queue.write_buffer(buffer, 0, &bytes[range]);
184        }
185    }
186
187    /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
188    /// and the provided [`RenderQueue`].
189    ///
190    /// If the buffer is not initialized on the GPU or the range is bigger than the capacity it will
191    /// return an error. You'll need to either reserve a new buffer which will lose data on the GPU
192    /// or create a new buffer and copy the old data to it.
193    ///
194    /// This will only write the data contained in the given range. It is useful if you only want
195    /// to update a part of the buffer.
196    pub fn write_buffer_range(
197        &mut self,
198        render_queue: &RenderQueue,
199        range: core::ops::Range<usize>,
200    ) -> Result<(), WriteBufferRangeError> {
201        if self.values.is_empty() {
202            return Err(WriteBufferRangeError::NoValuesToUpload);
203        }
204        if range.end > self.item_size * self.capacity {
205            return Err(WriteBufferRangeError::RangeBiggerThanBuffer);
206        }
207        if let Some(buffer) = &self.buffer {
208            // Cast only the bytes we need to write
209            let bytes: &[u8] = must_cast_slice(&self.values[range.start..range.end]);
210            render_queue.write_buffer(buffer, (range.start * self.item_size) as u64, bytes);
211            Ok(())
212        } else {
213            Err(WriteBufferRangeError::BufferNotInitialized)
214        }
215    }
216
217    /// Reduces the length of the buffer.
218    pub fn truncate(&mut self, len: usize) {
219        self.values.truncate(len);
220    }
221
222    /// Removes all elements from the buffer.
223    pub fn clear(&mut self) {
224        self.values.clear();
225    }
226
227    /// Removes and returns the last element in the buffer.
228    pub fn pop(&mut self) -> Option<T> {
229        self.values.pop()
230    }
231
232    pub fn values(&self) -> &Vec<T> {
233        &self.values
234    }
235
236    pub fn values_mut(&mut self) -> &mut Vec<T> {
237        &mut self.values
238    }
239}
240
241impl<T> RawBufferVec<T>
242where
243    T: NoUninit + Default,
244{
245    pub fn grow_set(&mut self, index: u32, value: T) {
246        while index as usize + 1 > self.len() {
247            self.values.push(T::default());
248        }
249        self.values[index as usize] = value;
250    }
251}
252
253impl<T: NoUninit> Extend<T> for RawBufferVec<T> {
254    #[inline]
255    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
256        self.values.extend(iter);
257    }
258}
259
260/// Like [`RawBufferVec`], but doesn't require that the data type `T` be
261/// [`NoUninit`].
262///
263/// This is a high-performance data structure that you should use whenever
264/// possible if your data is more complex than is suitable for [`RawBufferVec`].
265/// The [`ShaderType`] trait from the `encase` library is used to ensure that
266/// the data is correctly aligned for use by the GPU.
267///
268/// For performance reasons, unlike [`RawBufferVec`], this type doesn't allow
269/// CPU access to the data after it's been added via [`BufferVec::push`]. If you
270/// need CPU access to the data, consider another type, such as
271/// [`StorageBuffer`][super::StorageBuffer].
272///
273/// Other options for storing GPU-accessible data are:
274/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
275/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
276/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)
277/// * [`RawBufferVec`]
278/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
279/// * [`Texture`](crate::render_resource::Texture)
280/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
281pub struct BufferVec<T>
282where
283    T: ShaderType + WriteInto,
284{
285    data: Vec<u8>,
286    buffer: Option<Buffer>,
287    capacity: usize,
288    buffer_usage: BufferUsages,
289    label: Option<String>,
290    label_changed: bool,
291    phantom: PhantomData<T>,
292}
293
294impl<T> BufferVec<T>
295where
296    T: ShaderType + WriteInto,
297{
298    /// Creates a new [`BufferVec`] with the given [`BufferUsages`].
299    pub const fn new(buffer_usage: BufferUsages) -> Self {
300        Self {
301            data: vec![],
302            buffer: None,
303            capacity: 0,
304            buffer_usage,
305            label: None,
306            label_changed: false,
307            phantom: PhantomData,
308        }
309    }
310
311    /// Returns a handle to the buffer, if the data has been uploaded.
312    #[inline]
313    pub fn buffer(&self) -> Option<&Buffer> {
314        self.buffer.as_ref()
315    }
316
317    /// Returns the binding for the buffer if the data has been uploaded.
318    #[inline]
319    pub fn binding(&self) -> Option<BindingResource<'_>> {
320        Some(BindingResource::Buffer(
321            self.buffer()?.as_entire_buffer_binding(),
322        ))
323    }
324
325    /// Returns the amount of space that the GPU will use before reallocating.
326    #[inline]
327    pub fn capacity(&self) -> usize {
328        self.capacity
329    }
330
331    /// Returns the number of items that have been pushed to this buffer.
332    #[inline]
333    pub fn len(&self) -> usize {
334        self.data.len() / u64::from(T::min_size()) as usize
335    }
336
337    /// Returns true if the buffer is empty.
338    #[inline]
339    pub fn is_empty(&self) -> bool {
340        self.data.is_empty()
341    }
342
343    /// Adds a new value and returns its index.
344    pub fn push(&mut self, value: T) -> usize {
345        let element_size = u64::from(T::min_size()) as usize;
346        let offset = self.data.len();
347
348        // TODO: Consider using unsafe code to push uninitialized, to prevent
349        // the zeroing. It shows up in profiles.
350        self.data.extend(iter::repeat_n(0, element_size));
351
352        // Take a slice of the new data for `write_into` to use. This is
353        // important: it hoists the bounds check up here so that the compiler
354        // can eliminate all the bounds checks that `write_into` will emit.
355        let mut dest = &mut self.data[offset..(offset + element_size)];
356        value.write_into(&mut Writer::new(&value, &mut dest, 0).unwrap());
357
358        offset / u64::from(T::min_size()) as usize
359    }
360
361    /// Changes the debugging label of the buffer.
362    ///
363    /// The next time the buffer is updated (via [`Self::reserve`]), Bevy will inform
364    /// the driver of the new label.
365    pub fn set_label(&mut self, label: Option<&str>) {
366        let label = label.map(str::to_string);
367
368        if label != self.label {
369            self.label_changed = true;
370        }
371
372        self.label = label;
373    }
374
375    /// Returns the label
376    pub fn get_label(&self) -> Option<&str> {
377        self.label.as_deref()
378    }
379
380    /// Creates a [`Buffer`] on the [`RenderDevice`] with size
381    /// at least `size_of::<T>() * capacity`, unless such a buffer already exists.
382    ///
383    /// If a [`Buffer`] exists, but is too small, references to it will be discarded,
384    /// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s
385    /// that are no longer referenced will be deleted by the [`RenderDevice`]
386    /// once it is done using them (typically 1-2 frames).
387    ///
388    /// In addition to any [`BufferUsages`] provided when
389    /// the `BufferVec` was created, the buffer on the [`RenderDevice`]
390    /// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
391    pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
392        if capacity <= self.capacity && !self.label_changed {
393            return;
394        }
395
396        self.capacity = capacity;
397        let size = u64::from(T::min_size()) as usize * capacity;
398        self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
399            label: self.label.as_deref(),
400            size: size as BufferAddress,
401            usage: BufferUsages::COPY_DST | self.buffer_usage,
402            mapped_at_creation: false,
403        }));
404        self.label_changed = false;
405    }
406
407    /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
408    /// and the provided [`RenderQueue`].
409    ///
410    /// Before queuing the write, a [`reserve`](BufferVec::reserve) operation is
411    /// executed.
412    pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
413        if self.data.is_empty() {
414            return;
415        }
416
417        self.reserve(self.data.len() / u64::from(T::min_size()) as usize, device);
418
419        let Some(buffer) = &self.buffer else { return };
420        queue.write_buffer(buffer, 0, &self.data);
421    }
422
423    /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
424    /// and the provided [`RenderQueue`].
425    ///
426    /// If the buffer is not initialized on the GPU or the range is bigger than the capacity it will
427    /// return an error. You'll need to either reserve a new buffer which will lose data on the GPU
428    /// or create a new buffer and copy the old data to it.
429    ///
430    /// This will only write the data contained in the given range. It is useful if you only want
431    /// to update a part of the buffer.
432    pub fn write_buffer_range(
433        &mut self,
434        render_queue: &RenderQueue,
435        range: core::ops::Range<usize>,
436    ) -> Result<(), WriteBufferRangeError> {
437        if self.data.is_empty() {
438            return Err(WriteBufferRangeError::NoValuesToUpload);
439        }
440        let item_size = u64::from(T::min_size()) as usize;
441        if range.end > item_size * self.capacity {
442            return Err(WriteBufferRangeError::RangeBiggerThanBuffer);
443        }
444        if let Some(buffer) = &self.buffer {
445            let bytes = &self.data[range.start..range.end];
446            render_queue.write_buffer(buffer, (range.start * item_size) as u64, bytes);
447            Ok(())
448        } else {
449            Err(WriteBufferRangeError::BufferNotInitialized)
450        }
451    }
452
453    /// Reduces the length of the buffer.
454    pub fn truncate(&mut self, len: usize) {
455        self.data.truncate(u64::from(T::min_size()) as usize * len);
456    }
457
458    /// Removes all elements from the buffer.
459    pub fn clear(&mut self) {
460        self.data.clear();
461    }
462}
463
464/// Like a [`BufferVec`], but only reserves space on the GPU for elements
465/// instead of initializing them CPU-side.
466///
467/// This type is useful when you're accumulating "output slots" for a GPU
468/// compute shader to write into.
469///
470/// The type `T` need not be [`NoUninit`], unlike [`RawBufferVec`]; it only has to
471/// be [`GpuArrayBufferable`].
472pub struct UninitBufferVec<T>
473where
474    T: GpuArrayBufferable,
475{
476    buffer: Option<Buffer>,
477    len: usize,
478    capacity: usize,
479    item_size: usize,
480    buffer_usage: BufferUsages,
481    label: Option<String>,
482    label_changed: bool,
483    phantom: PhantomData<T>,
484}
485
486impl<T> UninitBufferVec<T>
487where
488    T: GpuArrayBufferable,
489{
490    /// Creates a new [`UninitBufferVec`] with the given [`BufferUsages`].
491    pub const fn new(buffer_usage: BufferUsages) -> Self {
492        Self {
493            len: 0,
494            buffer: None,
495            capacity: 0,
496            item_size: size_of::<T>(),
497            buffer_usage,
498            label: None,
499            label_changed: false,
500            phantom: PhantomData,
501        }
502    }
503
504    /// Returns the buffer, if allocated.
505    #[inline]
506    pub fn buffer(&self) -> Option<&Buffer> {
507        self.buffer.as_ref()
508    }
509
510    /// Returns the binding for the buffer if the data has been uploaded.
511    #[inline]
512    pub fn binding(&self) -> Option<BindingResource<'_>> {
513        Some(BindingResource::Buffer(
514            self.buffer()?.as_entire_buffer_binding(),
515        ))
516    }
517
518    /// Reserves space for one more element in the buffer and returns its index.
519    pub fn add(&mut self) -> usize {
520        self.add_multiple(1)
521    }
522
523    /// Reserves space for the given number of elements in the buffer and
524    /// returns the index of the first one.
525    pub fn add_multiple(&mut self, count: usize) -> usize {
526        let index = self.len;
527        self.len += count;
528        index
529    }
530
531    /// Returns true if no elements have been added to this [`UninitBufferVec`].
532    pub fn is_empty(&self) -> bool {
533        self.len == 0
534    }
535
536    /// Removes all elements from the buffer.
537    pub fn clear(&mut self) {
538        self.len = 0;
539    }
540
541    /// Returns the length of the buffer.
542    pub fn len(&self) -> usize {
543        self.len
544    }
545
546    /// Materializes the buffer on the GPU with space for `capacity` elements.
547    ///
548    /// If the buffer is already big enough, this function doesn't reallocate
549    /// the buffer.
550    pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
551        if capacity <= self.capacity && !self.label_changed {
552            return;
553        }
554
555        self.capacity = capacity;
556        let size = self.item_size * capacity;
557        self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
558            label: self.label.as_deref(),
559            size: size as BufferAddress,
560            usage: BufferUsages::COPY_DST | self.buffer_usage,
561            mapped_at_creation: false,
562        }));
563
564        self.label_changed = false;
565    }
566
567    /// Materializes the buffer on the GPU, with an appropriate size for the
568    /// elements that have been pushed so far.
569    pub fn write_buffer(&mut self, device: &RenderDevice) {
570        if !self.is_empty() {
571            self.reserve(self.len, device);
572        }
573    }
574}
575
576/// Error returned when `write_buffer_range` fails
577///
578/// See [`RawBufferVec::write_buffer_range`] [`BufferVec::write_buffer_range`]
579#[derive(Debug, Eq, PartialEq, Copy, Clone, Error)]
580pub enum WriteBufferRangeError {
581    #[error("the range is bigger than the capacity of the buffer")]
582    RangeBiggerThanBuffer,
583    #[error("the gpu buffer is not initialized")]
584    BufferNotInitialized,
585    #[error("there are no values to upload")]
586    NoValuesToUpload,
587}