@@ -142,15 +142,67 @@ impl Buffer {
142142 /// byte offset. This is intended for updating uniform buffer contents from
143143 /// the CPU. The `data` type must be trivially copyable.
144144 pub fn write_value < T : Copy > ( & self , gpu : & Gpu , offset : u64 , data : & T ) {
145- let bytes = unsafe {
146- std:: slice:: from_raw_parts (
147- ( data as * const T ) as * const u8 ,
148- std:: mem:: size_of :: < T > ( ) ,
149- )
150- } ;
145+ let bytes = value_as_bytes ( data) ;
146+ self . write_bytes ( gpu, offset, bytes) ;
147+ }
151148
152- self . buffer . write_bytes ( gpu. platform ( ) , offset, bytes) ;
149+ /// Write raw bytes into this buffer at the specified byte offset.
150+ ///
151+ /// This is useful when data is already available as a byte slice (for
152+ /// example, asset blobs or staging buffers).
153+ ///
154+ /// Example
155+ /// ```rust,ignore
156+ /// let raw_data: &[u8] = load_binary_data();
157+ /// buffer.write_bytes(render_context.gpu(), 0, raw_data);
158+ /// ```
159+ pub fn write_bytes ( & self , gpu : & Gpu , offset : u64 , data : & [ u8 ] ) {
160+ self . buffer . write_bytes ( gpu. platform ( ) , offset, data) ;
153161 }
162+
163+ /// Write a slice of plain-old-data values into this buffer at the
164+ /// specified byte offset.
165+ ///
166+ /// This is intended for uploading arrays of vertices, indices, instance
167+ /// data, or uniform blocks. The `T` type MUST be plain-old-data (POD) and
168+ /// safely representable as bytes.
169+ ///
170+ /// Example
171+ /// ```rust,ignore
172+ /// let transforms: Vec<InstanceTransform> = compute_transforms();
173+ /// instance_buffer.write_slice(render_context.gpu(), 0, &transforms);
174+ /// ```
175+ pub fn write_slice < T : Copy > ( & self , gpu : & Gpu , offset : u64 , data : & [ T ] ) {
176+ let bytes = slice_as_bytes ( data) ;
177+ self . write_bytes ( gpu, offset, bytes) ;
178+ }
179+ }
180+
181+ fn value_as_bytes < T : Copy > ( data : & T ) -> & [ u8 ] {
182+ let bytes = unsafe {
183+ std:: slice:: from_raw_parts (
184+ ( data as * const T ) as * const u8 ,
185+ std:: mem:: size_of :: < T > ( ) ,
186+ )
187+ } ;
188+ return bytes;
189+ }
190+
191+ fn slice_as_bytes < T : Copy > ( data : & [ T ] ) -> & [ u8 ] {
192+ let element_size = std:: mem:: size_of :: < T > ( ) ;
193+ let Some ( byte_len) = element_size. checked_mul ( data. len ( ) ) else {
194+ debug_assert ! (
195+ false ,
196+ "Buffer::write_slice byte length overflow: element_size={}, len={}" ,
197+ element_size,
198+ data. len( )
199+ ) ;
200+ return & [ ] ;
201+ } ;
202+
203+ let bytes =
204+ unsafe { std:: slice:: from_raw_parts ( data. as_ptr ( ) as * const u8 , byte_len) } ;
205+ return bytes;
154206}
155207
156208/// Strongly‑typed uniform buffer wrapper for ergonomics and safety.
@@ -375,4 +427,27 @@ mod tests {
375427 // Test module is a child of this module and can access private fields.
376428 assert_eq ! ( builder. label. as_deref( ) , Some ( "buffer-test" ) ) ;
377429 }
430+
431+ #[ test]
432+ fn value_as_bytes_matches_native_bytes ( ) {
433+ let value: u32 = 0x1122_3344 ;
434+ let expected = value. to_ne_bytes ( ) ;
435+ assert_eq ! ( value_as_bytes( & value) , expected. as_slice( ) ) ;
436+ }
437+
438+ #[ test]
439+ fn slice_as_bytes_matches_native_bytes ( ) {
440+ let values: [ u16 ; 3 ] = [ 0x1122 , 0x3344 , 0x5566 ] ;
441+ let mut expected: Vec < u8 > = Vec :: new ( ) ;
442+ for value in values {
443+ expected. extend_from_slice ( & value. to_ne_bytes ( ) ) ;
444+ }
445+ assert_eq ! ( slice_as_bytes( & values) , expected. as_slice( ) ) ;
446+ }
447+
448+ #[ test]
449+ fn slice_as_bytes_empty_is_empty ( ) {
450+ let values: [ u32 ; 0 ] = [ ] ;
451+ assert_eq ! ( slice_as_bytes( & values) , & [ ] ) ;
452+ }
378453}
0 commit comments