| 1 |
--- |
| 2 |
title: "`ShaderBuffer` stores typed data in an `AlignedVec` with an explicit buffer size" |
| 3 |
pull_requests: [24938, 25426] |
| 4 |
--- |
| 5 |
|
| 6 |
`ShaderBuffer` CPU data is now stored in an `AlignedVec` whose alignment can be |
| 7 |
configured at runtime. The allocation is guaranteed to be aligned to the element |
| 8 |
type used to fill it, which allows typed reads and writes through |
| 9 |
`bytemuck::cast_slice` / `cast_slice_mut` without extra copies or unaligned |
| 10 |
access. |
| 11 |
|
| 12 |
The GPU buffer size is now explicit and decoupled from the CPU data length: |
| 13 |
`ShaderBufferData::Initialized` carries a `buffer_size` that can differ from the |
| 14 |
length of `data`, so a larger GPU allocation can be kept while CPU data is |
| 15 |
cleared or resized, avoiding reallocations. |
| 16 |
|
| 17 |
When creating the GPU buffer, `buffer_size` always wins over the data length: |
| 18 |
the data is truncated when it is longer than `buffer_size`, and the buffer is |
| 19 |
zero-filled when it is shorter. |
| 20 |
|
| 21 |
The public fields of `ShaderBuffer` have changed: |
| 22 |
|
| 23 |
- `data: Option<Vec<u8>>` is now `data: ShaderBufferData` |
| 24 |
(`Initialized { data, buffer_size }` or `Uninitialized(size)`). |
| 25 |
- `buffer_description: wgpu::BufferDescriptor<'static>` has been replaced by the |
| 26 |
`label: Cow<'static, str>` and `buffer_usage: BufferUsages` fields. |
| 27 |
|
| 28 |
The following methods changed: |
| 29 |
|
| 30 |
- `ShaderBuffer::new` now takes a `Vec<T>` of `bytemuck::NoUninit` elements |
| 31 |
instead of a byte slice: |
| 32 |
|
| 33 |
```rust |
| 34 |
// Bevy 0.19 |
| 35 |
let buffer = ShaderBuffer::new(&bytes, RenderAssetUsages::default()); |
| 36 |
|
| 37 |
// Bevy 0.20 |
| 38 |
let buffer = ShaderBuffer::new(bytes, RenderAssetUsages::default()); |
| 39 |
``` |
| 40 |
|
| 41 |
- `ShaderBuffer::set_data` which uses `encase::ShaderType`, has been removed. Build the buffer with `new` or fill |
| 42 |
an existing one with `extend` / `extend_from_slice` instead: |
| 43 |
|
| 44 |
```rust |
| 45 |
// Bevy 0.19 |
| 46 |
let mut buffer = ShaderBuffer::default(); |
| 47 |
buffer.set_data(my_struct); |
| 48 |
|
| 49 |
// Bevy 0.20 |
| 50 |
let mut buffer = ShaderBuffer::default(); |
| 51 |
buffer.extend([my_struct]); |
| 52 |
``` |
| 53 |
|
| 54 |
- `From<T>` which uses `encase::ShaderType`, is replaced by `From<Vec<T>>` which reuses the memory: |
| 55 |
|
| 56 |
```rust |
| 57 |
// Bevy 0.19 |
| 58 |
let buffer = ShaderBuffer::from(my_struct); |
| 59 |
|
| 60 |
// Bevy 0.20 |
| 61 |
let buffer = ShaderBuffer::from(vec![my_struct]); |
| 62 |
``` |
| 63 |
|
| 64 |
- `ShaderBuffer::with_size` now takes a `u64` instead of a `usize`. |
| 65 |
- `ShaderBuffer::resize_in_place` has been removed. Use `ShaderBuffer::resize_buffer` |
| 66 |
to resize the GPU buffer without touching the CPU data, or `resize` for both. |
| 67 |
- `ShaderBuffer::cast_slice` / `cast_slice_mut` provide typed access to the data |
| 68 |
(new in 0.20). In 0.19 the data was only reachable as raw bytes through the |
| 69 |
`data` field; casting that `Vec<u8>` was not guaranteed to be aligned. |
| 70 |
- `ShaderBuffer::buffer_size()` returns the GPU buffer size; use |
| 71 |
`buffer_size() == 0` to check for a zero-sized buffer. |