demo_vk/graphics/vulkan/allocator/
owned_block.rs

1use {
2    crate::{
3        graphics::vulkan::{raii, Allocator, Block},
4        unwrap_here,
5    },
6    anyhow::Result,
7    ash::vk,
8    std::sync::Arc,
9};
10
11/// A block allocation that frees itself when dropped.
12#[derive(Debug)]
13pub struct OwnedBlock {
14    block: Block,
15    allocator: Arc<Allocator>,
16}
17
18impl OwnedBlock {
19    /// Creates an image and allocates memory to back it.
20    ///
21    /// The image is bound to the memory prior to return, so the caller can use
22    /// it right away.
23    pub fn allocate_image(
24        allocator: Arc<Allocator>,
25        image_create_info: &vk::ImageCreateInfo,
26        memory_property_flags: vk::MemoryPropertyFlags,
27    ) -> Result<(Self, raii::Image)> {
28        let image = unwrap_here!(
29            "Create Vulkan image",
30            raii::Image::new(
31                "Allocated Image",
32                allocator.logical_device.clone(),
33                image_create_info,
34            )
35        );
36
37        let (requirements, dedicated) = {
38            let mut dedicated = vk::MemoryDedicatedRequirements::default();
39            let requirements = unsafe {
40                let mut out = vk::MemoryRequirements2::default()
41                    .push_next(&mut dedicated);
42
43                allocator.logical_device.get_image_memory_requirements2(
44                    &vk::ImageMemoryRequirementsInfo2 {
45                        image: image.raw,
46                        ..Default::default()
47                    },
48                    &mut out,
49                );
50
51                out.memory_requirements
52            };
53            (
54                requirements,
55                dedicated.prefers_dedicated_allocation == vk::TRUE
56                    || dedicated.requires_dedicated_allocation == vk::TRUE,
57            )
58        };
59
60        let block = unwrap_here!(
61            "Allocate memory for Vulkan image",
62            allocator.allocate_memory(
63                &requirements,
64                memory_property_flags,
65                vk::MemoryAllocateFlags::empty(),
66                dedicated,
67            )
68        );
69
70        unwrap_here!("Bind memory to Vulkan image", unsafe {
71            allocator.logical_device.bind_image_memory(
72                image.raw,
73                block.memory(),
74                block.offset(),
75            )
76        });
77
78        Ok((Self { block, allocator }, image))
79    }
80
81    /// Creates a buffer and allocates memory to back it.
82    ///
83    /// The buffer is bound to the memory prior to return, so the caller can use
84    /// it right away.
85    pub fn allocate_buffer(
86        allocator: Arc<Allocator>,
87        buffer_create_info: &vk::BufferCreateInfo,
88        memory_property_flags: vk::MemoryPropertyFlags,
89    ) -> Result<(OwnedBlock, raii::Buffer)> {
90        let buffer = unwrap_here!(
91            "Create Vulkan buffer",
92            raii::Buffer::new(
93                "Allocated Buffer",
94                allocator.logical_device.clone(),
95                buffer_create_info,
96            )
97        );
98
99        let (requirements, dedicated) = {
100            let mut dedicated = vk::MemoryDedicatedRequirements::default();
101            let requirements = unsafe {
102                let mut out = vk::MemoryRequirements2::default()
103                    .push_next(&mut dedicated);
104
105                allocator.logical_device.get_buffer_memory_requirements2(
106                    &vk::BufferMemoryRequirementsInfo2 {
107                        buffer: buffer.raw,
108                        ..Default::default()
109                    },
110                    &mut out,
111                );
112
113                out.memory_requirements
114            };
115            (
116                requirements,
117                dedicated.prefers_dedicated_allocation == vk::TRUE
118                    || dedicated.requires_dedicated_allocation == vk::TRUE,
119            )
120        };
121
122        let memory_allocate_flags = if buffer_create_info
123            .usage
124            .contains(vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS)
125        {
126            vk::MemoryAllocateFlags::DEVICE_ADDRESS
127        } else {
128            vk::MemoryAllocateFlags::empty()
129        };
130
131        let block = unwrap_here!(
132            "Allocate memory for Vulkan buffer",
133            allocator.allocate_memory(
134                &requirements,
135                memory_property_flags,
136                memory_allocate_flags,
137                dedicated,
138            )
139        );
140
141        unwrap_here!("Bind memory to Vulkan buffer", unsafe {
142            allocator.logical_device.bind_buffer_memory(
143                buffer.raw,
144                block.memory(),
145                block.offset(),
146            )
147        });
148
149        Ok((Self { block, allocator }, buffer))
150    }
151}
152
153impl std::ops::Deref for OwnedBlock {
154    type Target = Block;
155
156    fn deref(&self) -> &Self::Target {
157        &self.block
158    }
159}
160
161impl Drop for OwnedBlock {
162    fn drop(&mut self) {
163        self.allocator.free(&self.block);
164    }
165}