use std::{mem, ops::Deref};
use wgpu::util::DeviceExt;
pub struct ImmutableBuffer<T> {
buffer: wgpu::Buffer,
cap: u64,
len: u64,
data: std::marker::PhantomData<T>,
}
impl<T: bytemuck::Pod> ImmutableBuffer<T> {
pub fn from_data(device: &wgpu::Device, usage: wgpu::BufferUsages, data: &[T]) -> Self {
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(data),
usage,
});
let len = data.len() as u64;
Self {
buffer,
cap: len,
len,
data: std::marker::PhantomData,
}
}
pub fn handle(&self) -> &wgpu::Buffer {
&self.buffer
}
pub fn len(&self) -> u64 {
self.len
}
pub fn cap(&self) -> u64 {
self.cap
}
}
pub struct MutableBuffer<T>(ImmutableBuffer<T>);
impl<T: bytemuck::Pod> Deref for MutableBuffer<T> {
type Target = ImmutableBuffer<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: bytemuck::Pod> MutableBuffer<T> {
pub fn with_capacity(device: &wgpu::Device, usage: wgpu::BufferUsages, cap: u64) -> Self {
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: mem::size_of::<T>() as u64 * cap,
usage: usage | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
Self(ImmutableBuffer {
buffer,
cap,
len: 0,
data: std::marker::PhantomData,
})
}
pub fn from_data(device: &wgpu::Device, usage: wgpu::BufferUsages, data: &[T]) -> Self {
Self(ImmutableBuffer::from_data(
device,
usage | wgpu::BufferUsages::COPY_DST,
data,
))
}
pub fn upload(&self, queue: &wgpu::Queue, data: &[T]) {
let data = bytemuck::cast_slice(data);
queue.write_buffer(&self.0.buffer, 0, data);
}
}