@@ -8,29 +8,29 @@ use crate::renderer::{RenderDevice, RenderQueue};
88
99use 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