rootvg_core/
buffer.rs

1use std::marker::PhantomData;
2use std::ops::Range;
3
4/// A helper struct for a [`wgpu::Buffer`].
5pub struct Buffer<T> {
6    pub raw: wgpu::Buffer,
7
8    label: &'static str,
9    size: u64,
10    usage: wgpu::BufferUsages,
11    type_: PhantomData<T>,
12}
13
14impl<T: bytemuck::Pod> Buffer<T> {
15    pub fn new(
16        device: &wgpu::Device,
17        label: &'static str,
18        amount: usize,
19        usage: wgpu::BufferUsages,
20    ) -> Self {
21        let size = next_copy_size::<T>(amount);
22
23        let raw = device.create_buffer(&wgpu::BufferDescriptor {
24            label: Some(label),
25            size,
26            usage,
27            mapped_at_creation: false,
28        });
29
30        Self {
31            label,
32            size,
33            usage,
34            raw,
35            type_: PhantomData,
36        }
37    }
38
39    /// Returns `true` if the buffer was expanded.
40    pub fn expand_to_fit_new_size(&mut self, device: &wgpu::Device, new_count: usize) -> bool {
41        let new_size = (std::mem::size_of::<T>() * new_count) as u64;
42
43        if self.size < new_size {
44            self.raw = device.create_buffer(&wgpu::BufferDescriptor {
45                label: Some(self.label),
46                size: new_size,
47                usage: self.usage,
48                mapped_at_creation: false,
49            });
50
51            self.size = new_size;
52
53            true
54        } else {
55            false
56        }
57    }
58
59    /// Returns the size of the written bytes.
60    pub fn write(&mut self, queue: &wgpu::Queue, offset: usize, contents: &[T]) -> usize {
61        let offset = offset as u64 * std::mem::size_of::<T>() as u64;
62
63        let bytes: &[u8] = bytemuck::cast_slice(contents);
64        queue.write_buffer(&self.raw, offset, bytes);
65
66        bytes.len()
67    }
68
69    pub fn slice(&self, range: Range<usize>) -> wgpu::BufferSlice<'_> {
70        self.raw.slice(
71            range.start as u64 * std::mem::size_of::<T>() as u64
72                ..range.end as u64 * std::mem::size_of::<T>() as u64,
73        )
74    }
75
76    pub fn label(&self) -> &'static str {
77        self.label
78    }
79}
80
81pub fn next_copy_size<T>(amount: usize) -> u64 {
82    let align_mask = wgpu::COPY_BUFFER_ALIGNMENT - 1;
83
84    (((std::mem::size_of::<T>() * amount).next_power_of_two() as u64 + align_mask) & !align_mask)
85        .max(wgpu::COPY_BUFFER_ALIGNMENT)
86}