demo_vk/graphics/vulkan/buffers/
uniform_buffer.rs1use {
2 crate::{
3 graphics::vulkan::{
4 raii, Frame, FramesInFlight, OwnedBlock, VulkanContext,
5 },
6 unwrap_here,
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 = {
33 let mut physical_device_properties =
34 vk::PhysicalDeviceProperties2::default();
35 unsafe {
36 cxt.instance.get_physical_device_properties2(
37 cxt.physical_device,
38 &mut physical_device_properties,
39 );
40 }
41 physical_device_properties.properties
42 };
43 let aligned_unit_size: u64 = {
44 let count = size_of::<DataT>() as u64
45 / properties.limits.min_uniform_buffer_offset_alignment;
46 (count + 1) * properties.limits.min_uniform_buffer_offset_alignment
47 };
48
49 let buffer_size_in_bytes = aligned_unit_size * count as u64;
50
51 let (block, buffer) = unwrap_here!(
52 "Allocate host visible and coherent memory",
53 OwnedBlock::allocate_buffer(
54 cxt.allocator.clone(),
55 &vk::BufferCreateInfo {
56 size: buffer_size_in_bytes,
57 usage: vk::BufferUsageFlags::UNIFORM_BUFFER,
58 sharing_mode: vk::SharingMode::EXCLUSIVE,
59 queue_family_index_count: 1,
60 p_queue_family_indices: &cxt.graphics_queue_family_index,
61 ..Default::default()
62 },
63 vk::MemoryPropertyFlags::HOST_VISIBLE
64 | vk::MemoryPropertyFlags::HOST_COHERENT,
65 )
66 );
67
68 Ok(Self {
69 buffer,
70 block,
71 count,
72 aligned_unit_size: aligned_unit_size as usize,
73 _phantom_data: PhantomData,
74 })
75 }
76
77 pub fn allocate_per_frame(
80 cxt: &VulkanContext,
81 frames_in_flight: &FramesInFlight,
82 ) -> Result<Self> {
83 Self::allocate(cxt, frames_in_flight.frame_count())
84 }
85
86 pub fn buffer(&self) -> vk::Buffer {
88 self.buffer.raw
89 }
90
91 pub fn update_frame_data(
93 &mut self,
94 frame: &Frame,
95 data: DataT,
96 ) -> Result<()> {
97 unsafe { self.write_indexed(frame.frame_index(), data) }
101 }
102
103 pub fn offset_for_index(&self, frame_index: usize) -> u64 {
106 (frame_index * self.aligned_unit_size) as u64
107 }
108
109 pub unsafe fn write_indexed(
116 &mut self,
117 index: usize,
118 data: DataT,
119 ) -> Result<()> {
120 if index >= self.count {
121 bail!("Attempt to write to index {}/{}", index, self.count);
122 }
123
124 let offset = self.offset_for_index(index) as isize;
125 std::ptr::copy_nonoverlapping(
126 &data,
127 self.block.mapped_ptr().byte_offset(offset) as *mut DataT,
128 1,
129 );
130
131 Ok(())
132 }
133}