demo_vk/graphics/vulkan/buffers/
uniform_buffer.rs1use {
2 crate::{
3 graphics::vulkan::{
4 raii, Frame, FramesInFlight, OwnedBlock, VulkanContext,
5 },
6 trace,
7 },
8 anyhow::{bail, Result},
9 ash::vk,
10 std::marker::PhantomData,
11};
12
13#[derive(Debug)]
16pub struct UniformBuffer<DataT: Sized + Copy> {
17 buffer: raii::Buffer,
18 block: OwnedBlock,
19 aligned_unit_size: usize,
20 count: usize,
21 _phantom_data: PhantomData<DataT>,
22}
23
24impl<DataT> UniformBuffer<DataT>
25where
26 DataT: Sized + Copy,
27{
28 pub fn allocate(cxt: &VulkanContext, count: usize) -> Result<Self> {
31 let properties = unsafe {
33 cxt.instance
34 .get_physical_device_properties(cxt.physical_device)
35 };
36 let aligned_unit_size: u64 = {
37 let count = size_of::<DataT>() as u64
38 / properties.limits.min_uniform_buffer_offset_alignment;
39 (count + 1) * properties.limits.min_uniform_buffer_offset_alignment
40 };
41
42 let buffer_size_in_bytes = aligned_unit_size * count as u64;
43
44 let (block, buffer) = OwnedBlock::allocate_buffer(
45 cxt.allocator.clone(),
46 &vk::BufferCreateInfo {
47 size: buffer_size_in_bytes,
48 usage: vk::BufferUsageFlags::UNIFORM_BUFFER,
49 sharing_mode: vk::SharingMode::EXCLUSIVE,
50 queue_family_index_count: 1,
51 p_queue_family_indices: &cxt.graphics_queue_family_index,
52 ..Default::default()
53 },
54 vk::MemoryPropertyFlags::HOST_VISIBLE
55 | vk::MemoryPropertyFlags::HOST_COHERENT,
56 )?;
57
58 Ok(Self {
59 buffer,
60 block,
61 count,
62 aligned_unit_size: aligned_unit_size as usize,
63 _phantom_data: PhantomData,
64 })
65 }
66
67 pub fn allocate_per_frame(
70 cxt: &VulkanContext,
71 frames_in_flight: &FramesInFlight,
72 ) -> Result<Self> {
73 Self::allocate(cxt, frames_in_flight.frame_count())
74 }
75
76 pub fn buffer(&self) -> vk::Buffer {
78 self.buffer.raw
79 }
80
81 pub fn update_frame_data(
83 &mut self,
84 frame: &Frame,
85 data: DataT,
86 ) -> Result<()> {
87 unsafe { self.write_indexed(frame.frame_index(), data) }
91 }
92
93 pub fn offset_for_index(&self, frame_index: usize) -> u64 {
96 (frame_index * self.aligned_unit_size) as u64
97 }
98
99 pub unsafe fn write_indexed(
106 &mut self,
107 index: usize,
108 data: DataT,
109 ) -> Result<()> {
110 if index >= self.count {
111 bail!(
112 trace!("Attempt to write to index {}/{}", index, self.count)()
113 );
114 }
115
116 let offset = self.offset_for_index(index) as isize;
117 std::ptr::copy_nonoverlapping(
118 &data,
119 self.block.mapped_ptr().byte_offset(offset) as *mut DataT,
120 1,
121 );
122
123 Ok(())
124 }
125}