demo_vk/graphics/vulkan/buffers/
cpu_buffer.rs

1use {
2    crate::{
3        graphics::vulkan::{raii, OwnedBlock, VulkanContext},
4        trace,
5    },
6    anyhow::{bail, Result},
7    ash::vk,
8    std::marker::PhantomData,
9};
10
11/// A CPU accessible buffer with some convenience functions for uploading data.
12///
13/// CPU accessible means that the buffer is both HOST_VISIBLE and HOST_COHERENT
14/// and memory mapped for access from the CPU.
15#[derive(Debug)]
16pub struct CPUBuffer<DataT: Sized + Copy> {
17    buffer: raii::Buffer,
18    block: OwnedBlock,
19    count: usize,
20    _phantom_data: PhantomData<DataT>,
21}
22
23impl<DataT> CPUBuffer<DataT>
24where
25    DataT: Sized + Copy,
26{
27    /// Allocates a new buffer and GPU memory for holding data.
28    ///
29    /// Total size is `count * size_of<DataT>()`.
30    pub fn allocate(
31        cxt: &VulkanContext,
32        count: usize,
33        usage: vk::BufferUsageFlags,
34    ) -> Result<Self> {
35        let buffer_size_in_bytes = (count * size_of::<DataT>()) as u64;
36
37        let (block, buffer) = OwnedBlock::allocate_buffer(
38            cxt.allocator.clone(),
39            &vk::BufferCreateInfo {
40                size: buffer_size_in_bytes,
41                usage,
42                sharing_mode: vk::SharingMode::EXCLUSIVE,
43                queue_family_index_count: 1,
44                p_queue_family_indices: &cxt.graphics_queue_family_index,
45                ..Default::default()
46            },
47            vk::MemoryPropertyFlags::HOST_VISIBLE
48                | vk::MemoryPropertyFlags::HOST_COHERENT,
49        )?;
50
51        Ok(Self {
52            buffer,
53            block,
54            count,
55            _phantom_data: PhantomData,
56        })
57    }
58
59    /// Returns a non-owning copy of the Vulkan buffer handle.
60    pub fn buffer(&self) -> vk::Buffer {
61        self.buffer.raw
62    }
63
64    /// The size of the buffer in bytes.
65    pub fn size_in_bytes(&self) -> u64 {
66        (self.count * size_of::<DataT>()) as u64
67    }
68
69    /// The maximum number of items that can be saved in this buffer.
70    pub fn capacity(&self) -> usize {
71        self.count
72    }
73
74    /// Writes data into the GPU memory at the given index.
75    ///
76    /// # Safety
77    ///
78    /// Unsafe because:
79    /// - the caller must synchronize access to the region being written.
80    pub unsafe fn write_data(
81        &mut self,
82        start_index: usize,
83        data: &[DataT],
84    ) -> Result<()> {
85        if start_index + data.len() > self.count {
86            bail!(trace!(
87                "Out of bounds write attempted! {}/{}",
88                start_index + data.len(),
89                self.count
90            )());
91        }
92
93        std::ptr::copy_nonoverlapping(
94            data.as_ptr(),
95            (self.block.mapped_ptr() as *mut DataT).add(start_index),
96            data.len(),
97        );
98
99        Ok(())
100    }
101}