Skip to content

Commit a7e4c2d

Browse files
committed
bevy_pbr: Always write length to StorageVec
1 parent 2e814f7 commit a7e4c2d

File tree

2 files changed

+29
-13
lines changed

2 files changed

+29
-13
lines changed

crates/bevy_pbr/src/render/mesh_view_bind_group.wgsl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,15 @@ struct ClusterOffsetsAndCounts {
7272
};
7373
#else
7474
struct PointLights {
75+
length: u32;
7576
data: array<PointLight>;
7677
};
7778
struct ClusterLightIndexLists {
79+
length: u32;
7880
data: array<u32>;
7981
};
8082
struct ClusterOffsetsAndCounts {
83+
length: u32;
8184
data: array<vec2<u32>>;
8285
};
8386
#endif

crates/bevy_render/src/render_resource/storage_vec.rs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,29 @@ use crate::renderer::{RenderDevice, RenderQueue};
88

99
use super::Buffer;
1010

11-
pub struct StorageVec<T: AsStd430 + Default> {
11+
/// A helper for a storage buffer binding with a variable-sized array
12+
/// Use a struct with length: u32, data: array<T> in the shader.
13+
pub struct StorageVec<T: AsStd430> {
1214
values: Vec<T>,
1315
scratch: Vec<u8>,
1416
storage_buffer: Option<Buffer>,
1517
capacity: usize,
1618
item_size: usize,
1719
}
1820

19-
impl<T: AsStd430 + Default> Default for StorageVec<T> {
21+
impl<T: AsStd430> Default for StorageVec<T> {
2022
fn default() -> Self {
2123
Self {
2224
values: Vec::new(),
2325
scratch: Vec::new(),
2426
storage_buffer: None,
2527
capacity: 0,
26-
// FIXME: Is this correct or even necessary? Maybe only need T::std430_size_static()?
27-
item_size: (T::std430_size_static() + <T as AsStd430>::Output::ALIGNMENT - 1)
28-
& !(<T as AsStd430>::Output::ALIGNMENT - 1),
28+
item_size: T::std430_size_static(),
2929
}
3030
}
3131
}
3232

33-
impl<T: AsStd430 + Default> StorageVec<T> {
33+
impl<T: AsStd430> StorageVec<T> {
3434
#[inline]
3535
pub fn storage_buffer(&self) -> Option<&Buffer> {
3636
self.storage_buffer.as_ref()
@@ -41,7 +41,7 @@ impl<T: AsStd430 + Default> StorageVec<T> {
4141
Some(BindingResource::Buffer(BufferBinding {
4242
buffer: self.storage_buffer()?,
4343
offset: 0,
44-
size: Some(NonZeroU64::new((self.item_size * self.values.len()) as u64).unwrap()),
44+
size: Some(NonZeroU64::new((self.size()) as u64).unwrap()),
4545
}))
4646
}
4747

@@ -71,9 +71,9 @@ impl<T: AsStd430 + Default> StorageVec<T> {
7171
}
7272

7373
pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) -> bool {
74-
if capacity > self.capacity {
74+
if self.storage_buffer.is_none() || capacity > self.capacity {
7575
self.capacity = capacity;
76-
let size = self.item_size * capacity;
76+
let size = self.size();
7777
self.scratch.resize(size, 0);
7878
self.storage_buffer = Some(device.create_buffer(&BufferDescriptor {
7979
label: None,
@@ -87,16 +87,29 @@ impl<T: AsStd430 + Default> StorageVec<T> {
8787
}
8888
}
8989

90+
pub fn size(&self) -> usize {
91+
// 4 bytes for a u32 array length plus the necessary padding according to T's alignment
92+
((4 + <T as AsStd430>::Output::ALIGNMENT - 1) & !(<T as AsStd430>::Output::ALIGNMENT - 1))
93+
// Variable size arrays must have at least 1 element
94+
+ self.item_size * self.capacity.max(1)
95+
}
96+
9097
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
91-
if self.values.is_empty() {
92-
self.values.push(T::default());
93-
}
9498
self.reserve(self.values.len(), device);
9599
if let Some(storage_buffer) = &self.storage_buffer {
96-
let range = 0..self.item_size * self.values.len();
100+
let range = 0..self.size();
97101
let mut writer = std430::Writer::new(&mut self.scratch[range.clone()]);
102+
// NOTE: Can only represent up to u32::MAX values
103+
debug_assert!(self.values.len() <= u32::MAX as usize);
98104
// NOTE: Failing to write should be non-fatal. It would likely cause visual
99105
// artifacts but a warning message should suffice.
106+
// First write the length of the array
107+
writer
108+
.write(&(self.values.len() as u32))
109+
.map_err(|e| warn!("{:?}", e))
110+
.ok();
111+
// Then write the array. Note that padding bytes may be added between the array length
112+
// and the array in order to align the array to the alignment requirements of T
100113
writer
101114
.write(self.values.as_slice())
102115
.map_err(|e| warn!("{:?}", e))

0 commit comments

Comments
 (0)