2023-02-02 16:46:41 +00:00
|
|
|
use bytemuck::{AnyBitPattern, NoUninit};
|
2023-02-02 17:21:15 +00:00
|
|
|
use std::ops::Range;
|
2023-02-02 16:46:41 +00:00
|
|
|
use wgpu::util::DeviceExt;
|
|
|
|
|
|
|
|
pub struct BufferBuilder {
|
|
|
|
inner: Vec<u8>,
|
|
|
|
align_mask: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BufferBuilder {
|
2023-02-02 16:57:23 +00:00
|
|
|
pub fn new(alignment: usize) -> Self {
|
2023-02-02 16:46:41 +00:00
|
|
|
Self {
|
|
|
|
inner: Vec::new(),
|
2023-02-02 17:21:15 +00:00
|
|
|
align_mask: if alignment > 0 { alignment - 1 } else { 0 },
|
2023-02-02 16:46:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 17:21:15 +00:00
|
|
|
pub fn add<T: NoUninit + AnyBitPattern>(&mut self, value: &[T]) -> Range<wgpu::BufferAddress> {
|
|
|
|
if !self.inner.is_empty() && self.align_mask > 0 {
|
2023-02-02 16:46:41 +00:00
|
|
|
// Pad the internal buffer to match alignment requirements
|
|
|
|
// Pad on creation so that we don't wastefully pad the end of the buffer
|
|
|
|
let length = (self.inner.len() + self.align_mask) & !self.align_mask;
|
|
|
|
self.inner.resize(length, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
let address = self.inner.len() as wgpu::BufferAddress;
|
2023-02-02 17:21:15 +00:00
|
|
|
self.inner.extend_from_slice(bytemuck::cast_slice(value));
|
|
|
|
address..(self.inner.len() as wgpu::BufferAddress)
|
2023-02-02 16:46:41 +00:00
|
|
|
}
|
|
|
|
|
2023-02-02 16:57:23 +00:00
|
|
|
pub fn finish(
|
|
|
|
self,
|
|
|
|
device: &wgpu::Device,
|
|
|
|
label: Option<String>,
|
|
|
|
usage: wgpu::BufferUsages,
|
|
|
|
) -> wgpu::Buffer {
|
2023-02-02 16:46:41 +00:00
|
|
|
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
|
|
label: label.as_deref(),
|
|
|
|
contents: &self.inner,
|
2023-02-02 16:57:23 +00:00
|
|
|
usage,
|
2023-02-02 16:46:41 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|