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/// * [`BufferVec`]
33/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
34/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
35/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)
36/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
37/// * [`Texture`](crate::render_resource::Texture)
38/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
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    /// Returns the value at the given index.
107    pub fn get(&self, index: u32) -> Option<&T> {
108        self.values.get(index as usize)
109    }
110
111    /// Sets the value at the given index.
112    ///
113    /// The index must be less than [`RawBufferVec::len`].
114    pub fn set(&mut self, index: u32, value: T) {
115        self.values[index as usize] = value;
116    }
117
118    /// Preallocates space for `count` elements in the internal CPU-side buffer.
119    ///
120    /// Unlike [`RawBufferVec::reserve`], this doesn't have any effect on the GPU buffer.
121    pub fn reserve_internal(&mut self, count: usize) {
122        self.values.reserve(count);
123    }
124
125    /// Changes the debugging label of the buffer.
126    ///
127    /// The next time the buffer is updated (via [`reserve`](Self::reserve)), Bevy will inform
128    /// the driver of the new label.
129    pub fn set_label(&mut self, label: Option<&str>) {
130        let label = label.map(str::to_string);
131
132        if label != self.label {
133            self.changed = true;
134        }
135
136        self.label = label;
137    }
138
139    /// Returns the label
140    pub fn get_label(&self) -> Option<&str> {
141        self.label.as_deref()
142    }
143
144    /// Creates a [`Buffer`] on the [`RenderDevice`] with size
145    /// at least `size_of::<T>() * capacity`, unless a such a buffer already exists.
146    ///
147    /// If a [`Buffer`] exists, but is too small, references to it will be discarded,
148    /// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s
149    /// that are no longer referenced will be deleted by the [`RenderDevice`]
150    /// once it is done using them (typically 1-2 frames).
151    ///
152    /// In addition to any [`BufferUsages`] provided when
153    /// the `RawBufferVec` was created, the buffer on the [`RenderDevice`]
154    /// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
155    pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
156        let size = self.item_size * capacity;
157        if capacity > self.capacity || (self.changed && size > 0) {
158            self.capacity = capacity;
159            self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
160                label: self.label.as_deref(),
161                size: size as BufferAddress,
162                usage: BufferUsages::COPY_DST | self.buffer_usage,
163                mapped_at_creation: false,
164            }));
165            self.changed = false;
166        }
167    }
168
169    /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
170    /// and the provided [`RenderQueue`].
171    ///
172    /// Before queuing the write, a [`reserve`](RawBufferVec::reserve) operation
173    /// is executed.
174    pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
175        if self.values.is_empty() {
176            return;
177        }
178        self.reserve(self.values.len(), device);
179        if let Some(buffer) = &self.buffer {
180            let range = 0..self.item_size * self.values.len();
181            let bytes: &[u8] = must_cast_slice(&self.values);
182            queue.write_buffer(buffer, 0, &bytes[range]);
183        }
184    }
185
186    /// Reduces the length of the buffer.
187    pub fn truncate(&mut self, len: usize) {
188        self.values.truncate(len);
189    }
190
191    /// Removes all elements from the buffer.
192    pub fn clear(&mut self) {
193        self.values.clear();
194    }
195
196    /// Removes and returns the last element in the buffer.
197    pub fn pop(&mut self) -> Option<T> {
198        self.values.pop()
199    }
200
201    pub fn values(&self) -> &Vec<T> {
202        &self.values
203    }
204
205    pub fn values_mut(&mut self) -> &mut Vec<T> {
206        &mut self.values
207    }
208}
209
210impl<T> RawBufferVec<T>
211where
212    T: NoUninit + Default,
213{
214    pub fn grow_set(&mut self, index: u32, value: T) {
215        while index as usize + 1 > self.len() {
216            self.values.push(T::default());
217        }
218        self.values[index as usize] = value;
219    }
220}
221
222impl<T: NoUninit> Extend<T> for RawBufferVec<T> {
223    #[inline]
224    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
225        self.values.extend(iter);
226    }
227}
228
229/// Like [`RawBufferVec`], but doesn't require that the data type `T` be
230/// [`NoUninit`].
231///
232/// This is a high-performance data structure that you should use whenever
233/// possible if your data is more complex than is suitable for [`RawBufferVec`].
234/// The [`ShaderType`] trait from the `encase` library is used to ensure that
235/// the data is correctly aligned for use by the GPU.
236///
237/// For performance reasons, unlike [`RawBufferVec`], this type doesn't allow
238/// CPU access to the data after it's been added via [`BufferVec::push`]. If you
239/// need CPU access to the data, consider another type, such as
240/// [`StorageBuffer`][super::StorageBuffer].
241///
242/// Other options for storing GPU-accessible data are:
243/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
244/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
245/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)
246/// * [`RawBufferVec`]
247/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
248/// * [`Texture`](crate::render_resource::Texture)
249/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
250pub struct BufferVec<T>
251where
252    T: ShaderType + WriteInto,
253{
254    data: Vec<u8>,
255    buffer: Option<Buffer>,
256    capacity: usize,
257    buffer_usage: BufferUsages,
258    label: Option<String>,
259    label_changed: bool,
260    phantom: PhantomData<T>,
261}
262
263impl<T> BufferVec<T>
264where
265    T: ShaderType + WriteInto,
266{
267    /// Creates a new [`BufferVec`] with the given [`BufferUsages`].
268    pub const fn new(buffer_usage: BufferUsages) -> Self {
269        Self {
270            data: vec![],
271            buffer: None,
272            capacity: 0,
273            buffer_usage,
274            label: None,
275            label_changed: false,
276            phantom: PhantomData,
277        }
278    }
279
280    /// Returns a handle to the buffer, if the data has been uploaded.
281    #[inline]
282    pub fn buffer(&self) -> Option<&Buffer> {
283        self.buffer.as_ref()
284    }
285
286    /// Returns the binding for the buffer if the data has been uploaded.
287    #[inline]
288    pub fn binding(&self) -> Option<BindingResource> {
289        Some(BindingResource::Buffer(
290            self.buffer()?.as_entire_buffer_binding(),
291        ))
292    }
293
294    /// Returns the amount of space that the GPU will use before reallocating.
295    #[inline]
296    pub fn capacity(&self) -> usize {
297        self.capacity
298    }
299
300    /// Returns the number of items that have been pushed to this buffer.
301    #[inline]
302    pub fn len(&self) -> usize {
303        self.data.len() / u64::from(T::min_size()) as usize
304    }
305
306    /// Returns true if the buffer is empty.
307    #[inline]
308    pub fn is_empty(&self) -> bool {
309        self.data.is_empty()
310    }
311
312    /// Adds a new value and returns its index.
313    pub fn push(&mut self, value: T) -> usize {
314        let element_size = u64::from(T::min_size()) as usize;
315        let offset = self.data.len();
316
317        // TODO: Consider using unsafe code to push uninitialized, to prevent
318        // the zeroing. It shows up in profiles.
319        self.data.extend(iter::repeat_n(0, element_size));
320
321        // Take a slice of the new data for `write_into` to use. This is
322        // important: it hoists the bounds check up here so that the compiler
323        // can eliminate all the bounds checks that `write_into` will emit.
324        let mut dest = &mut self.data[offset..(offset + element_size)];
325        value.write_into(&mut Writer::new(&value, &mut dest, 0).unwrap());
326
327        offset / u64::from(T::min_size()) as usize
328    }
329
330    /// Changes the debugging label of the buffer.
331    ///
332    /// The next time the buffer is updated (via [`Self::reserve`]), Bevy will inform
333    /// the driver of the new label.
334    pub fn set_label(&mut self, label: Option<&str>) {
335        let label = label.map(str::to_string);
336
337        if label != self.label {
338            self.label_changed = true;
339        }
340
341        self.label = label;
342    }
343
344    /// Returns the label
345    pub fn get_label(&self) -> Option<&str> {
346        self.label.as_deref()
347    }
348
349    /// Creates a [`Buffer`] on the [`RenderDevice`] with size
350    /// at least `size_of::<T>() * capacity`, unless such a buffer already exists.
351    ///
352    /// If a [`Buffer`] exists, but is too small, references to it will be discarded,
353    /// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s
354    /// that are no longer referenced will be deleted by the [`RenderDevice`]
355    /// once it is done using them (typically 1-2 frames).
356    ///
357    /// In addition to any [`BufferUsages`] provided when
358    /// the `BufferVec` was created, the buffer on the [`RenderDevice`]
359    /// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
360    pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
361        if capacity <= self.capacity && !self.label_changed {
362            return;
363        }
364
365        self.capacity = capacity;
366        let size = u64::from(T::min_size()) as usize * capacity;
367        self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
368            label: self.label.as_deref(),
369            size: size as BufferAddress,
370            usage: BufferUsages::COPY_DST | self.buffer_usage,
371            mapped_at_creation: false,
372        }));
373        self.label_changed = false;
374    }
375
376    /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
377    /// and the provided [`RenderQueue`].
378    ///
379    /// Before queuing the write, a [`reserve`](BufferVec::reserve) operation is
380    /// executed.
381    pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
382        if self.data.is_empty() {
383            return;
384        }
385
386        self.reserve(self.data.len() / u64::from(T::min_size()) as usize, device);
387
388        let Some(buffer) = &self.buffer else { return };
389        queue.write_buffer(buffer, 0, &self.data);
390    }
391
392    /// Reduces the length of the buffer.
393    pub fn truncate(&mut self, len: usize) {
394        self.data.truncate(u64::from(T::min_size()) as usize * len);
395    }
396
397    /// Removes all elements from the buffer.
398    pub fn clear(&mut self) {
399        self.data.clear();
400    }
401}
402
403/// Like a [`BufferVec`], but only reserves space on the GPU for elements
404/// instead of initializing them CPU-side.
405///
406/// This type is useful when you're accumulating "output slots" for a GPU
407/// compute shader to write into.
408///
409/// The type `T` need not be [`NoUninit`], unlike [`RawBufferVec`]; it only has to
410/// be [`GpuArrayBufferable`].
411pub struct UninitBufferVec<T>
412where
413    T: GpuArrayBufferable,
414{
415    buffer: Option<Buffer>,
416    len: usize,
417    capacity: usize,
418    item_size: usize,
419    buffer_usage: BufferUsages,
420    label: Option<String>,
421    label_changed: bool,
422    phantom: PhantomData<T>,
423}
424
425impl<T> UninitBufferVec<T>
426where
427    T: GpuArrayBufferable,
428{
429    /// Creates a new [`UninitBufferVec`] with the given [`BufferUsages`].
430    pub const fn new(buffer_usage: BufferUsages) -> Self {
431        Self {
432            len: 0,
433            buffer: None,
434            capacity: 0,
435            item_size: size_of::<T>(),
436            buffer_usage,
437            label: None,
438            label_changed: false,
439            phantom: PhantomData,
440        }
441    }
442
443    /// Returns the buffer, if allocated.
444    #[inline]
445    pub fn buffer(&self) -> Option<&Buffer> {
446        self.buffer.as_ref()
447    }
448
449    /// Returns the binding for the buffer if the data has been uploaded.
450    #[inline]
451    pub fn binding(&self) -> Option<BindingResource> {
452        Some(BindingResource::Buffer(
453            self.buffer()?.as_entire_buffer_binding(),
454        ))
455    }
456
457    /// Reserves space for one more element in the buffer and returns its index.
458    pub fn add(&mut self) -> usize {
459        self.add_multiple(1)
460    }
461
462    /// Reserves space for the given number of elements in the buffer and
463    /// returns the index of the first one.
464    pub fn add_multiple(&mut self, count: usize) -> usize {
465        let index = self.len;
466        self.len += count;
467        index
468    }
469
470    /// Returns true if no elements have been added to this [`UninitBufferVec`].
471    pub fn is_empty(&self) -> bool {
472        self.len == 0
473    }
474
475    /// Removes all elements from the buffer.
476    pub fn clear(&mut self) {
477        self.len = 0;
478    }
479
480    /// Returns the length of the buffer.
481    pub fn len(&self) -> usize {
482        self.len
483    }
484
485    /// Materializes the buffer on the GPU with space for `capacity` elements.
486    ///
487    /// If the buffer is already big enough, this function doesn't reallocate
488    /// the buffer.
489    pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
490        if capacity <= self.capacity && !self.label_changed {
491            return;
492        }
493
494        self.capacity = capacity;
495        let size = self.item_size * capacity;
496        self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
497            label: self.label.as_deref(),
498            size: size as BufferAddress,
499            usage: BufferUsages::COPY_DST | self.buffer_usage,
500            mapped_at_creation: false,
501        }));
502
503        self.label_changed = false;
504    }
505
506    /// Materializes the buffer on the GPU, with an appropriate size for the
507    /// elements that have been pushed so far.
508    pub fn write_buffer(&mut self, device: &RenderDevice) {
509        if !self.is_empty() {
510            self.reserve(self.len, device);
511        }
512    }
513}