Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/render_resource/buffer_vec.rs
9328 views
1
use core::{iter, marker::PhantomData};
2
3
use crate::{
4
render_resource::Buffer,
5
renderer::{RenderDevice, RenderQueue},
6
};
7
use bytemuck::{must_cast_slice, NoUninit};
8
use encase::{
9
internal::{WriteInto, Writer},
10
ShaderType,
11
};
12
use thiserror::Error;
13
use wgpu::{BindingResource, BufferAddress, BufferUsages};
14
15
use 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)
40
pub 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
50
impl<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: make_buffer_label::<Self>(&self.label),
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
241
impl<T> RawBufferVec<T>
242
where
243
T: NoUninit + Default,
244
{
245
pub fn grow_set(&mut self, index: u32, value: T) {
246
self.values.reserve(index as usize + 1);
247
while index as usize + 1 > self.len() {
248
self.values.push(T::default());
249
}
250
self.values[index as usize] = value;
251
}
252
}
253
254
impl<T: NoUninit> Extend<T> for RawBufferVec<T> {
255
#[inline]
256
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
257
self.values.extend(iter);
258
}
259
}
260
261
/// Like [`RawBufferVec`], but doesn't require that the data type `T` be
262
/// [`NoUninit`].
263
///
264
/// This is a high-performance data structure that you should use whenever
265
/// possible if your data is more complex than is suitable for [`RawBufferVec`].
266
/// The [`ShaderType`] trait from the `encase` library is used to ensure that
267
/// the data is correctly aligned for use by the GPU.
268
///
269
/// For performance reasons, unlike [`RawBufferVec`], this type doesn't allow
270
/// CPU access to the data after it's been added via [`BufferVec::push`]. If you
271
/// need CPU access to the data, consider another type, such as
272
/// [`StorageBuffer`][super::StorageBuffer].
273
///
274
/// Other options for storing GPU-accessible data are:
275
/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
276
/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
277
/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)
278
/// * [`RawBufferVec`]
279
/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
280
/// * [`Texture`](crate::render_resource::Texture)
281
/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
282
pub struct BufferVec<T>
283
where
284
T: ShaderType + WriteInto,
285
{
286
data: Vec<u8>,
287
buffer: Option<Buffer>,
288
capacity: usize,
289
buffer_usage: BufferUsages,
290
label: Option<String>,
291
label_changed: bool,
292
phantom: PhantomData<T>,
293
}
294
295
impl<T> BufferVec<T>
296
where
297
T: ShaderType + WriteInto,
298
{
299
/// Creates a new [`BufferVec`] with the given [`BufferUsages`].
300
pub const fn new(buffer_usage: BufferUsages) -> Self {
301
Self {
302
data: vec![],
303
buffer: None,
304
capacity: 0,
305
buffer_usage,
306
label: None,
307
label_changed: false,
308
phantom: PhantomData,
309
}
310
}
311
312
/// Returns a handle to the buffer, if the data has been uploaded.
313
#[inline]
314
pub fn buffer(&self) -> Option<&Buffer> {
315
self.buffer.as_ref()
316
}
317
318
/// Returns the binding for the buffer if the data has been uploaded.
319
#[inline]
320
pub fn binding(&self) -> Option<BindingResource<'_>> {
321
Some(BindingResource::Buffer(
322
self.buffer()?.as_entire_buffer_binding(),
323
))
324
}
325
326
/// Returns the amount of space that the GPU will use before reallocating.
327
#[inline]
328
pub fn capacity(&self) -> usize {
329
self.capacity
330
}
331
332
/// Returns the number of items that have been pushed to this buffer.
333
#[inline]
334
pub fn len(&self) -> usize {
335
self.data.len() / u64::from(T::min_size()) as usize
336
}
337
338
/// Returns true if the buffer is empty.
339
#[inline]
340
pub fn is_empty(&self) -> bool {
341
self.data.is_empty()
342
}
343
344
/// Adds a new value and returns its index.
345
pub fn push(&mut self, value: T) -> usize {
346
let element_size = u64::from(T::min_size()) as usize;
347
let offset = self.data.len();
348
349
// `extend` does not optimize for reallocation. Related `trusted_len` feature is unstable.
350
self.data.reserve(self.data.len() + element_size);
351
// We can't optimize and push uninitialized data here (using e.g. spare_capacity_mut())
352
// because write_into() does not initialize inner padding bytes in T's expansion
353
self.data.extend(iter::repeat_n(0, element_size));
354
355
// Take a slice of the new data for `write_into` to use. This is
356
// important: it hoists the bounds check up here so that the compiler
357
// can eliminate all the bounds checks that `write_into` will emit.
358
let mut dest = &mut self.data[offset..(offset + element_size)];
359
value.write_into(&mut Writer::new(&value, &mut dest, 0).unwrap());
360
361
offset / u64::from(T::min_size()) as usize
362
}
363
364
/// Changes the debugging label of the buffer.
365
///
366
/// The next time the buffer is updated (via [`Self::reserve`]), Bevy will inform
367
/// the driver of the new label.
368
pub fn set_label(&mut self, label: Option<&str>) {
369
let label = label.map(str::to_string);
370
371
if label != self.label {
372
self.label_changed = true;
373
}
374
375
self.label = label;
376
}
377
378
/// Returns the label
379
pub fn get_label(&self) -> Option<&str> {
380
self.label.as_deref()
381
}
382
383
/// Preallocates space for `count` elements in the internal CPU-side buffer.
384
///
385
/// Unlike [`Self::reserve`], this doesn't have any effect on the GPU buffer.
386
pub fn reserve_internal(&mut self, count: usize) {
387
self.data.reserve(count * u64::from(T::min_size()) as usize);
388
}
389
390
/// Creates a [`Buffer`] on the [`RenderDevice`] with size
391
/// at least `size_of::<T>() * capacity`, unless such a buffer already exists.
392
///
393
/// If a [`Buffer`] exists, but is too small, references to it will be discarded,
394
/// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s
395
/// that are no longer referenced will be deleted by the [`RenderDevice`]
396
/// once it is done using them (typically 1-2 frames).
397
///
398
/// In addition to any [`BufferUsages`] provided when
399
/// the `BufferVec` was created, the buffer on the [`RenderDevice`]
400
/// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
401
pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
402
if capacity <= self.capacity && !self.label_changed {
403
return;
404
}
405
406
self.capacity = capacity;
407
let size = u64::from(T::min_size()) as usize * capacity;
408
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
409
label: make_buffer_label::<Self>(&self.label),
410
size: size as BufferAddress,
411
usage: BufferUsages::COPY_DST | self.buffer_usage,
412
mapped_at_creation: false,
413
}));
414
self.label_changed = false;
415
}
416
417
/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
418
/// and the provided [`RenderQueue`].
419
///
420
/// Before queuing the write, a [`reserve`](BufferVec::reserve) operation is
421
/// executed.
422
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
423
if self.data.is_empty() {
424
return;
425
}
426
427
self.reserve(self.data.len() / u64::from(T::min_size()) as usize, device);
428
429
let Some(buffer) = &self.buffer else { return };
430
queue.write_buffer(buffer, 0, &self.data);
431
}
432
433
/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
434
/// and the provided [`RenderQueue`].
435
///
436
/// If the buffer is not initialized on the GPU or the range is bigger than the capacity it will
437
/// return an error. You'll need to either reserve a new buffer which will lose data on the GPU
438
/// or create a new buffer and copy the old data to it.
439
///
440
/// This will only write the data contained in the given range. It is useful if you only want
441
/// to update a part of the buffer.
442
pub fn write_buffer_range(
443
&mut self,
444
render_queue: &RenderQueue,
445
range: core::ops::Range<usize>,
446
) -> Result<(), WriteBufferRangeError> {
447
if self.data.is_empty() {
448
return Err(WriteBufferRangeError::NoValuesToUpload);
449
}
450
let item_size = u64::from(T::min_size()) as usize;
451
if range.end > item_size * self.capacity {
452
return Err(WriteBufferRangeError::RangeBiggerThanBuffer);
453
}
454
if let Some(buffer) = &self.buffer {
455
let bytes = &self.data[range.start..range.end];
456
render_queue.write_buffer(buffer, (range.start * item_size) as u64, bytes);
457
Ok(())
458
} else {
459
Err(WriteBufferRangeError::BufferNotInitialized)
460
}
461
}
462
463
/// Reduces the length of the buffer.
464
pub fn truncate(&mut self, len: usize) {
465
self.data.truncate(u64::from(T::min_size()) as usize * len);
466
}
467
468
/// Removes all elements from the buffer.
469
pub fn clear(&mut self) {
470
self.data.clear();
471
}
472
}
473
474
/// Like a [`BufferVec`], but only reserves space on the GPU for elements
475
/// instead of initializing them CPU-side.
476
///
477
/// This type is useful when you're accumulating "output slots" for a GPU
478
/// compute shader to write into.
479
///
480
/// The type `T` need not be [`NoUninit`], unlike [`RawBufferVec`]; it only has to
481
/// be [`GpuArrayBufferable`].
482
pub struct UninitBufferVec<T>
483
where
484
T: GpuArrayBufferable,
485
{
486
buffer: Option<Buffer>,
487
len: usize,
488
capacity: usize,
489
item_size: usize,
490
buffer_usage: BufferUsages,
491
label: Option<String>,
492
label_changed: bool,
493
phantom: PhantomData<T>,
494
}
495
496
impl<T> UninitBufferVec<T>
497
where
498
T: GpuArrayBufferable,
499
{
500
/// Creates a new [`UninitBufferVec`] with the given [`BufferUsages`].
501
pub const fn new(buffer_usage: BufferUsages) -> Self {
502
Self {
503
len: 0,
504
buffer: None,
505
capacity: 0,
506
item_size: size_of::<T>(),
507
buffer_usage,
508
label: None,
509
label_changed: false,
510
phantom: PhantomData,
511
}
512
}
513
514
/// Returns the buffer, if allocated.
515
#[inline]
516
pub fn buffer(&self) -> Option<&Buffer> {
517
self.buffer.as_ref()
518
}
519
520
/// Returns the binding for the buffer if the data has been uploaded.
521
#[inline]
522
pub fn binding(&self) -> Option<BindingResource<'_>> {
523
Some(BindingResource::Buffer(
524
self.buffer()?.as_entire_buffer_binding(),
525
))
526
}
527
528
/// Reserves space for one more element in the buffer and returns its index.
529
pub fn add(&mut self) -> usize {
530
self.add_multiple(1)
531
}
532
533
/// Reserves space for the given number of elements in the buffer and
534
/// returns the index of the first one.
535
pub fn add_multiple(&mut self, count: usize) -> usize {
536
let index = self.len;
537
self.len += count;
538
index
539
}
540
541
/// Returns true if no elements have been added to this [`UninitBufferVec`].
542
pub fn is_empty(&self) -> bool {
543
self.len == 0
544
}
545
546
/// Removes all elements from the buffer.
547
pub fn clear(&mut self) {
548
self.len = 0;
549
}
550
551
/// Returns the length of the buffer.
552
pub fn len(&self) -> usize {
553
self.len
554
}
555
556
/// Returns the amount of space that the GPU will use before reallocating.
557
#[inline]
558
pub fn capacity(&self) -> usize {
559
self.capacity
560
}
561
562
/// Changes the debugging label of the buffer.
563
///
564
/// The next time the buffer is updated (via [`Self::reserve`]), Bevy will inform
565
/// the driver of the new label.
566
pub fn set_label(&mut self, label: Option<&str>) {
567
let label = label.map(str::to_string);
568
569
if label != self.label {
570
self.label_changed = true;
571
}
572
573
self.label = label;
574
}
575
576
/// Returns the label
577
pub fn get_label(&self) -> Option<&str> {
578
self.label.as_deref()
579
}
580
581
/// Materializes the buffer on the GPU with space for `capacity` elements.
582
///
583
/// If the buffer is already big enough, this function doesn't reallocate
584
/// the buffer.
585
pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
586
if capacity <= self.capacity && !self.label_changed {
587
return;
588
}
589
590
self.capacity = capacity;
591
let size = self.item_size * capacity;
592
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
593
label: make_buffer_label::<Self>(&self.label),
594
size: size as BufferAddress,
595
usage: BufferUsages::COPY_DST | self.buffer_usage,
596
mapped_at_creation: false,
597
}));
598
599
self.label_changed = false;
600
}
601
602
/// Materializes the buffer on the GPU, with an appropriate size for the
603
/// elements that have been pushed so far.
604
pub fn write_buffer(&mut self, device: &RenderDevice) {
605
if !self.is_empty() {
606
self.reserve(self.len, device);
607
}
608
}
609
}
610
611
/// Error returned when `write_buffer_range` fails
612
///
613
/// See [`RawBufferVec::write_buffer_range`] [`BufferVec::write_buffer_range`]
614
#[derive(Debug, Eq, PartialEq, Copy, Clone, Error)]
615
pub enum WriteBufferRangeError {
616
#[error("the range is bigger than the capacity of the buffer")]
617
RangeBiggerThanBuffer,
618
#[error("the gpu buffer is not initialized")]
619
BufferNotInitialized,
620
#[error("there are no values to upload")]
621
NoValuesToUpload,
622
}
623
624
#[inline]
625
pub(crate) fn make_buffer_label<'a, T>(label: &'a Option<String>) -> Option<&'a str> {
626
#[cfg(feature = "type_label_buffers")]
627
if label.is_none() {
628
return Some(core::any::type_name::<T>());
629
}
630
label.as_deref()
631
}
632
633