ggez/graphics/gpu/
growing.rs

1use super::arc::ArcBuffer;
2
3/// Simple buffer sub-allocation helper.
4///
5/// In short, the allocator is:
6/// - linear: i.e., just a moving cursor into each buffer -- individual deallocations are not possible
7/// - growing: When the allocator is unable to find a buffer with enough free space for an allocation, it creates a new buffer
8/// - aligned: This is particularly important for uniform buffers as GPUs have a restriction on min alignment for dynamic offsets into UBOs
9#[derive(Debug)]
10pub struct GrowingBufferArena {
11    buffers: Vec<(ArcBuffer, u64)>,
12    alignment: u64,
13    desc: wgpu::BufferDescriptor<'static>,
14}
15
16impl GrowingBufferArena {
17    pub fn new(
18        device: &wgpu::Device,
19        alignment: u64,
20        desc: wgpu::BufferDescriptor<'static>,
21    ) -> Self {
22        GrowingBufferArena {
23            buffers: vec![(ArcBuffer::new(device.create_buffer(&desc)), 0)],
24            alignment,
25            desc,
26        }
27    }
28
29    pub fn allocate(&mut self, device: &wgpu::Device, size: u64) -> ArenaAllocation {
30        let size = align(self.alignment, size);
31        assert!(size <= self.desc.size);
32
33        for (buffer, cursor) in &mut self.buffers {
34            if size <= self.desc.size - *cursor {
35                let offset = *cursor;
36                *cursor += size;
37                return ArenaAllocation {
38                    buffer: buffer.clone(),
39                    offset,
40                };
41            }
42        }
43
44        self.grow(device);
45        self.allocate(device, size)
46    }
47
48    /// This frees **all** the allocations at once.
49    pub fn free(&mut self) {
50        for (_, cursor) in &mut self.buffers {
51            *cursor = 0;
52        }
53    }
54
55    fn grow(&mut self, device: &wgpu::Device) {
56        self.buffers
57            .push((ArcBuffer::new(device.create_buffer(&self.desc)), 0));
58    }
59}
60
61#[derive(Debug, Clone)]
62pub struct ArenaAllocation {
63    pub buffer: ArcBuffer,
64    pub offset: u64,
65}
66
67fn align(alignment: u64, size: u64) -> u64 {
68    (size + alignment - 1) & !(alignment - 1)
69}