use super::buffer::create_buffer_with_value;
pub unsafe trait ToStd140 {
type Output: Copy;
const STD140_SIZE: u64 = std::mem::size_of::<Self::Output>() as u64;
fn to_std140(&self) -> Self::Output;
}
pub struct UniformsBuffer<T> {
buffer: wgpu::Buffer,
bind_group: wgpu::BindGroup,
dirty: bool,
_phantom: std::marker::PhantomData<fn(&T)>,
}
impl<T: ToStd140> UniformsBuffer<T> {
pub fn from_value(device: &wgpu::Device, value: &T, layout: &wgpu::BindGroupLayout) -> Self {
let buffer = create_buffer_with_value(device, None, &value.to_std140(), wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST);
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("uniforms_bind_group"),
layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &buffer,
offset: 0,
size: None, }),
}],
});
Self {
buffer,
bind_group,
dirty: false,
_phantom: std::marker::PhantomData,
}
}
pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.bind_group
}
pub fn is_dirty(&self) -> bool {
self.dirty
}
pub fn mark_dirty(&mut self, dirty: bool) {
self.dirty = dirty;
}
pub fn update_from(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, value: &T) {
let buffer = create_buffer_with_value(device, None, &value.to_std140(), wgpu::BufferUsages::COPY_SRC);
encoder.copy_buffer_to_buffer(&buffer, 0, &self.buffer, 0, T::STD140_SIZE as wgpu::BufferAddress);
self.mark_dirty(false);
}
}