Skip to main content

grana_gpu/
table.rs

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}