Skip to content

Commit 3a8ffb9

Browse files
committed
[add] write_slice and write_bytes to the buffer.
1 parent 5b5e501 commit 3a8ffb9

File tree

1 file changed

+82
-7
lines changed

1 file changed

+82
-7
lines changed

crates/lambda-rs/src/render/buffer.rs

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)