demo_vk/graphics/vulkan/buffers/
cpu_buffer.rs

1use {
2    crate::{
3        graphics::vulkan::{raii, OwnedBlock, VulkanContext},
4        unwrap_here,
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) = unwrap_here!(
38            "Allocate host visible and coherent memory",
39            OwnedBlock::allocate_buffer(
40                cxt.allocator.clone(),
41                &vk::BufferCreateInfo {
42                    size: buffer_size_in_bytes,
43                    usage,
44                    sharing_mode: vk::SharingMode::EXCLUSIVE,
45                    queue_family_index_count: 1,
46                    p_queue_family_indices: &cxt.graphics_queue_family_index,
47                    ..Default::default()
48                },
49                vk::MemoryPropertyFlags::HOST_VISIBLE
50                    | vk::MemoryPropertyFlags::HOST_COHERENT,
51            )
52        );
53
54        Ok(Self {
55            buffer,
56            block,
57            count,
58            _phantom_data: PhantomData,
59        })
60    }
61
62    /// Returns a non-owning copy of the Vulkan buffer handle.
63    pub fn buffer(&self) -> vk::Buffer {
64        self.buffer.raw
65    }
66
67    /// The size of the buffer in bytes.
68    pub fn size_in_bytes(&self) -> u64 {
69        (self.count * size_of::<DataT>()) as u64
70    }
71
72    /// The maximum number of items that can be saved in this buffer.
73    pub fn capacity(&self) -> usize {
74        self.count
75    }
76
77    /// Writes data into the GPU memory at the given index.
78    ///
79    /// # Safety
80    ///
81    /// Unsafe because:
82    /// - the caller must synchronize access to the region being written.
83    pub unsafe fn write_data(
84        &mut self,
85        start_index: usize,
86        data: &[DataT],
87    ) -> Result<()> {
88        if start_index + data.len() > self.count {
89            bail!(
90                "Out of bounds write attempted! {}/{}",
91                start_index + data.len(),
92                self.count
93            );
94        }
95
96        std::ptr::copy_nonoverlapping(
97            data.as_ptr(),
98            (self.block.mapped_ptr() as *mut DataT).add(start_index),
99            data.len(),
100        );
101
102        Ok(())
103    }
104}