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}