Skip to content

Commit 305a3d0

Browse files
committed
bevy_pbr: Rework StorageVec to be StorageBuffer
Supports both a body and variable-size array at the end.
1 parent a7e4c2d commit 305a3d0

File tree

5 files changed

+72
-50
lines changed

5 files changed

+72
-50
lines changed

crates/bevy_crevice/src/std430/traits.rs

+8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ pub unsafe trait Std430: Copy + Zeroable + Pod {
3939
}
4040
}
4141

42+
unsafe impl Std430 for () {
43+
const ALIGNMENT: usize = 0;
44+
45+
const PAD_AT_END: bool = false;
46+
47+
type Padded = ();
48+
}
49+
4250
/// Trait specifically for Std430::Padded, implements conversions between padded type and base type.
4351
pub trait Std430Convertible<T: Std430>: Copy {
4452
/// Convert from self to Std430

crates/bevy_pbr/src/render/light.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub enum GpuPointLights {
9595
buffer: UniformVec<[GpuPointLight; MAX_POINT_LIGHTS]>,
9696
},
9797
Storage {
98-
buffer: StorageVec<GpuPointLight>,
98+
buffer: StorageBuffer<(), GpuPointLight>,
9999
},
100100
}
101101

@@ -116,7 +116,7 @@ impl GpuPointLights {
116116

117117
fn storage() -> Self {
118118
Self::Storage {
119-
buffer: StorageVec::default(),
119+
buffer: StorageBuffer::default(),
120120
}
121121
}
122122

@@ -986,8 +986,8 @@ enum ViewClusterBuffers {
986986
cluster_offsets_and_counts: UniformVec<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>,
987987
},
988988
Storage {
989-
cluster_light_index_lists: StorageVec<u32>,
990-
cluster_offsets_and_counts: StorageVec<UVec2>,
989+
cluster_light_index_lists: StorageBuffer<(), u32>,
990+
cluster_offsets_and_counts: StorageBuffer<(), UVec2>,
991991
},
992992
}
993993

@@ -1009,8 +1009,8 @@ impl ViewClusterBuffers {
10091009

10101010
fn storage() -> Self {
10111011
ViewClusterBuffers::Storage {
1012-
cluster_light_index_lists: StorageVec::default(),
1013-
cluster_offsets_and_counts: StorageVec::default(),
1012+
cluster_light_index_lists: StorageBuffer::default(),
1013+
cluster_offsets_and_counts: StorageBuffer::default(),
10141014
}
10151015
}
10161016
}
@@ -1049,6 +1049,7 @@ impl ViewClusterBindings {
10491049
ViewClusterBuffers::Storage {
10501050
cluster_light_index_lists,
10511051
cluster_offsets_and_counts,
1052+
..
10521053
} => {
10531054
cluster_light_index_lists.clear();
10541055
cluster_offsets_and_counts.clear();
@@ -1059,8 +1060,8 @@ impl ViewClusterBindings {
10591060
pub fn push_offset_and_count(&mut self, offset: usize, count: usize) {
10601061
match &mut self.buffers {
10611062
ViewClusterBuffers::Uniform {
1062-
cluster_light_index_lists: _,
10631063
cluster_offsets_and_counts,
1064+
..
10641065
} => {
10651066
let array_index = self.n_offsets >> 2; // >> 2 is equivalent to / 4
10661067
if array_index >= Self::MAX_UNIFORM_ITEMS {
@@ -1073,8 +1074,8 @@ impl ViewClusterBindings {
10731074
cluster_offsets_and_counts.get_mut(0)[array_index][component] = packed;
10741075
}
10751076
ViewClusterBuffers::Storage {
1076-
cluster_light_index_lists: _,
10771077
cluster_offsets_and_counts,
1078+
..
10781079
} => {
10791080
cluster_offsets_and_counts.push(UVec2::new(offset as u32, count as u32));
10801081
}
@@ -1091,7 +1092,7 @@ impl ViewClusterBindings {
10911092
match &mut self.buffers {
10921093
ViewClusterBuffers::Uniform {
10931094
cluster_light_index_lists,
1094-
cluster_offsets_and_counts: _,
1095+
..
10951096
} => {
10961097
let array_index = self.n_indices >> 4; // >> 4 is equivalent to / 16
10971098
let component = (self.n_indices >> 2) & ((1 << 2) - 1);
@@ -1103,7 +1104,7 @@ impl ViewClusterBindings {
11031104
}
11041105
ViewClusterBuffers::Storage {
11051106
cluster_light_index_lists,
1106-
cluster_offsets_and_counts: _,
1107+
..
11071108
} => {
11081109
cluster_light_index_lists.push(index as u32);
11091110
}
@@ -1135,24 +1136,24 @@ impl ViewClusterBindings {
11351136
match &self.buffers {
11361137
ViewClusterBuffers::Uniform {
11371138
cluster_light_index_lists,
1138-
cluster_offsets_and_counts: _,
1139+
..
11391140
} => cluster_light_index_lists.binding(),
11401141
ViewClusterBuffers::Storage {
11411142
cluster_light_index_lists,
1142-
cluster_offsets_and_counts: _,
1143+
..
11431144
} => cluster_light_index_lists.binding(),
11441145
}
11451146
}
11461147

11471148
pub fn offsets_and_counts_binding(&self) -> Option<BindingResource> {
11481149
match &self.buffers {
11491150
ViewClusterBuffers::Uniform {
1150-
cluster_light_index_lists: _,
11511151
cluster_offsets_and_counts,
1152+
..
11521153
} => cluster_offsets_and_counts.binding(),
11531154
ViewClusterBuffers::Storage {
1154-
cluster_light_index_lists: _,
11551155
cluster_offsets_and_counts,
1156+
..
11561157
} => cluster_offsets_and_counts.binding(),
11571158
}
11581159
}

crates/bevy_pbr/src/render/mesh_view_bind_group.wgsl

-3
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,12 @@ struct ClusterOffsetsAndCounts {
7272
};
7373
#else
7474
struct PointLights {
75-
length: u32;
7675
data: array<PointLight>;
7776
};
7877
struct ClusterLightIndexLists {
79-
length: u32;
8078
data: array<u32>;
8179
};
8280
struct ClusterOffsetsAndCounts {
83-
length: u32;
8481
data: array<vec2<u32>>;
8582
};
8683
#endif

crates/bevy_render/src/render_resource/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod pipeline;
66
mod pipeline_cache;
77
mod pipeline_specializer;
88
mod shader;
9-
mod storage_vec;
9+
mod storage_buffer;
1010
mod texture;
1111
mod uniform_vec;
1212

@@ -18,7 +18,7 @@ pub use pipeline::*;
1818
pub use pipeline_cache::*;
1919
pub use pipeline_specializer::*;
2020
pub use shader::*;
21-
pub use storage_vec::*;
21+
pub use storage_buffer::*;
2222
pub use texture::*;
2323
pub use uniform_vec::*;
2424

crates/bevy_render/src/render_resource/storage_vec.rs renamed to crates/bevy_render/src/render_resource/storage_buffer.rs

+47-31
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,30 @@ use crate::renderer::{RenderDevice, RenderQueue};
88

99
use super::Buffer;
1010

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> {
14-
values: Vec<T>,
11+
/// A helper for a storage buffer binding with a body, or a variable-sized array, or both.
12+
pub struct StorageBuffer<T: AsStd430, U: AsStd430> {
13+
body: T,
14+
values: Vec<U>,
1515
scratch: Vec<u8>,
1616
storage_buffer: Option<Buffer>,
1717
capacity: usize,
1818
item_size: usize,
1919
}
2020

21-
impl<T: AsStd430> Default for StorageVec<T> {
21+
impl<T: AsStd430 + Default, U: AsStd430> Default for StorageBuffer<T, U> {
2222
fn default() -> Self {
2323
Self {
24+
body: T::default(),
2425
values: Vec::new(),
2526
scratch: Vec::new(),
2627
storage_buffer: None,
2728
capacity: 0,
28-
item_size: T::std430_size_static(),
29+
item_size: U::std430_size_static(),
2930
}
3031
}
3132
}
3233

33-
impl<T: AsStd430> StorageVec<T> {
34+
impl<T: AsStd430, U: AsStd430> StorageBuffer<T, U> {
3435
#[inline]
3536
pub fn storage_buffer(&self) -> Option<&Buffer> {
3637
self.storage_buffer.as_ref()
@@ -55,22 +56,26 @@ impl<T: AsStd430> StorageVec<T> {
5556
self.values.is_empty()
5657
}
5758

59+
pub fn set_body(&mut self, body: T) {
60+
self.body = body;
61+
}
62+
5863
#[inline]
5964
pub fn capacity(&self) -> usize {
6065
self.capacity
6166
}
6267

63-
pub fn push(&mut self, value: T) -> usize {
68+
pub fn push(&mut self, value: U) -> usize {
6469
let index = self.values.len();
6570
self.values.push(value);
6671
index
6772
}
6873

69-
pub fn get_mut(&mut self, index: usize) -> &mut T {
74+
pub fn get_mut(&mut self, index: usize) -> &mut U {
7075
&mut self.values[index]
7176
}
7277

73-
pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) -> bool {
78+
fn reserve(&mut self, capacity: usize, device: &RenderDevice) -> bool {
7479
if self.storage_buffer.is_none() || capacity > self.capacity {
7580
self.capacity = capacity;
7681
let size = self.size();
@@ -87,33 +92,44 @@ impl<T: AsStd430> StorageVec<T> {
8792
}
8893
}
8994

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+
fn size(&self) -> usize {
96+
let mut size = 0;
97+
size += T::std430_size_static();
98+
if size > 0 {
99+
// Pad according to the array item type's alignment
100+
size = (size + <U as AsStd430>::Output::ALIGNMENT - 1)
101+
& !(<U as AsStd430>::Output::ALIGNMENT - 1);
102+
}
103+
// Variable size arrays must have at least 1 element
104+
size += self.item_size * self.capacity.max(1);
105+
size
95106
}
96107

97108
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
98109
self.reserve(self.values.len(), device);
99110
if let Some(storage_buffer) = &self.storage_buffer {
100111
let range = 0..self.size();
101112
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);
104-
// NOTE: Failing to write should be non-fatal. It would likely cause visual
105-
// 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
113-
writer
114-
.write(self.values.as_slice())
115-
.map_err(|e| warn!("{:?}", e))
116-
.ok();
113+
let mut offset = 0;
114+
// First write the struct body if there is one
115+
if T::std430_size_static() > 0 {
116+
if let Ok(new_offset) = writer.write(&self.body).map_err(|e| warn!("{:?}", e)) {
117+
offset = new_offset;
118+
}
119+
}
120+
if self.values.is_empty() {
121+
for i in offset..self.size() {
122+
self.scratch[i] = 0;
123+
}
124+
} else {
125+
// Then write the array. Note that padding bytes may be added between the body
126+
// and the array in order to align the array to the alignment requirements of its
127+
// items
128+
writer
129+
.write(self.values.as_slice())
130+
.map_err(|e| warn!("{:?}", e))
131+
.ok();
132+
}
117133
queue.write_buffer(storage_buffer, 0, &self.scratch[range]);
118134
}
119135
}
@@ -122,7 +138,7 @@ impl<T: AsStd430> StorageVec<T> {
122138
self.values.clear();
123139
}
124140

125-
pub fn values(&self) -> &[T] {
141+
pub fn values(&self) -> &[U] {
126142
&self.values
127143
}
128144
}

0 commit comments

Comments
 (0)