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
6596 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: 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
241
impl<T> RawBufferVec<T>
242
where
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
253
impl<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)
281
pub struct BufferVec<T>
282
where
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
294
impl<T> BufferVec<T>
295
where
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`].
472
pub struct UninitBufferVec<T>
473
where
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
486
impl<T> UninitBufferVec<T>
487
where
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)]
580
pub 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
}
588
589