1use bytemuck::{Pod, cast_slice};
2use wgpu::{Buffer, BufferUsages, Device, Queue};
3
4pub struct Table<T: Pod> {
5 label: &'static str,
6 buffer: Buffer,
7 capacity: usize,
8 _marker: std::marker::PhantomData<T>,
9}
10
11impl<T: Pod> Table<T> {
12 pub fn new(device: &Device, label: &'static str) -> Self {
13 Self::with_capacity(device, label, 1)
14 }
15
16 pub fn with_capacity(device: &Device, label: &'static str, capacity: usize) -> Self {
17 assert!(capacity > 0, "a storage table holds at least one row");
18 Self {
19 label,
20 buffer: storage_buffer::<T>(device, label, capacity),
21 capacity,
22 _marker: std::marker::PhantomData,
23 }
24 }
25
26 pub fn write(&mut self, device: &Device, queue: &Queue, rows: &[T]) -> bool {
27 let grown = self.reserve(device, rows.len());
28 if !rows.is_empty() {
29 queue.write_buffer(&self.buffer, 0, cast_slice(rows));
30 }
31 grown
32 }
33
34 pub fn reserve(&mut self, device: &Device, capacity: usize) -> bool {
35 if capacity <= self.capacity {
36 return false;
37 }
38 self.capacity = capacity.next_power_of_two();
39 self.buffer = storage_buffer::<T>(device, self.label, self.capacity);
40 true
41 }
42
43 pub fn buffer(&self) -> &Buffer {
44 &self.buffer
45 }
46}
47
48fn storage_buffer<T: Pod>(device: &Device, label: &'static str, capacity: usize) -> Buffer {
49 device.create_buffer(&wgpu::BufferDescriptor {
50 label: Some(label),
51 size: (capacity * size_of::<T>()) as u64,
52 usage: BufferUsages::STORAGE | BufferUsages::COPY_DST,
53 mapped_at_creation: false,
54 })
55}