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}