demo_vk/graphics/vulkan/allocator/
mod.rs1mod allocation_requirements;
2pub mod block;
3mod composable_allocator;
4mod humanized_size;
5pub mod owned_block;
6
7use {
8 self::{
9 allocation_requirements::AllocationRequirements,
10 composable_allocator::ComposableAllocator,
11 humanized_size::HumanizedSize,
12 },
13 crate::{
14 graphics::vulkan::{raii, Block},
15 unwrap_here,
16 },
17 anyhow::Result,
18 ash::vk,
19 std::{
20 sync::{
21 mpsc::{Sender, SyncSender},
22 Arc,
23 },
24 thread::JoinHandle,
25 },
26};
27
28enum Request {
30 Allocate(AllocationRequirements, SyncSender<Result<Block>>),
32
33 Free(Block),
35
36 ShutDown,
38}
39
40pub struct Allocator {
56 logical_device: Arc<raii::Device>,
57 client: Sender<Request>,
58 allocation_thread: Option<JoinHandle<()>>,
59 memory_properties: vk::PhysicalDeviceMemoryProperties,
60}
61
62impl Allocator {
63 pub fn new(
64 logical_device: Arc<raii::Device>,
65 physical_device: vk::PhysicalDevice,
66 ) -> Result<Self> {
67 let memory_properties = unsafe {
68 let mut physical_device_memory_properties =
69 vk::PhysicalDeviceMemoryProperties2::default();
70 logical_device.ash.get_physical_device_memory_properties2(
71 physical_device,
72 &mut physical_device_memory_properties,
73 );
74 physical_device_memory_properties.memory_properties
75 };
76 let (handle, client) = Self::spawn_allocator_thread(
77 logical_device.clone(),
78 memory_properties,
79 );
80 Ok(Self {
81 logical_device,
82 client,
83 allocation_thread: Some(handle),
84 memory_properties,
85 })
86 }
87
88 pub fn allocate_memory(
90 &self,
91 requirements: &vk::MemoryRequirements,
92 memory_property_flags: vk::MemoryPropertyFlags,
93 memory_allocate_flags: vk::MemoryAllocateFlags,
94 dedicated: bool,
95 ) -> Result<Block> {
96 let requirements = unwrap_here!(
97 "Identify allocation requirements",
98 AllocationRequirements::new(
99 &self.memory_properties,
100 requirements,
101 memory_property_flags,
102 memory_allocate_flags,
103 dedicated,
104 )
105 );
106
107 let (response_sender, response) =
108 std::sync::mpsc::sync_channel::<Result<Block>>(1);
109 unwrap_here!(
110 "Send allocation request",
111 self.client
112 .send(Request::Allocate(requirements, response_sender))
113 );
114 unwrap_here!("Wait for allocation response", response.recv())
115 }
116
117 pub fn free(&self, block: &Block) {
119 if self.client.send(Request::Free(*block)).is_err() {
120 log::error!("Error while attempting to free memory: {:#?}", block);
121 }
122 }
123
124 fn spawn_allocator_thread(
127 logical_device: Arc<raii::Device>,
128 memory_properties: vk::PhysicalDeviceMemoryProperties,
129 ) -> (JoinHandle<()>, Sender<Request>) {
130 let (sender, receiver) = std::sync::mpsc::channel::<Request>();
131 let handle = std::thread::spawn(move || {
132 let mut allocator = composable_allocator::create_system_allocator(
133 logical_device,
134 memory_properties,
135 );
136 'main: loop {
137 let allocation_request = if let Ok(request) = receiver.recv() {
138 request
139 } else {
140 log::warn!("Memory allocation client hung up!");
141 break 'main;
142 };
143
144 match allocation_request {
145 Request::Allocate(requirements, response) => {
146 let result = allocator.allocate_memory(requirements);
147 if let Err(error) = response.send(result) {
148 log::error!(
149 "Unable to send block to requester! {}",
150 error
151 );
152 break 'main;
153 }
154 }
155 Request::Free(block) => {
156 allocator.free_memory(&block);
157 }
158 Request::ShutDown => {
159 log::trace!("Shutdown requested");
160 break 'main;
161 }
162 }
163 }
164 log::trace!("Device memory allocator shut down.");
165 });
166 (handle, sender)
167 }
168}
169
170impl std::fmt::Debug for Allocator {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 f.debug_struct("Allocator").finish_non_exhaustive()
173 }
174}
175
176impl Drop for Allocator {
177 fn drop(&mut self) {
178 if self.client.send(Request::ShutDown).is_err() {
179 log::error!("Error while sending shutdown request!");
180 }
181 let allocator_thread_result =
182 self.allocation_thread.take().unwrap().join();
183 if let Err(error) = allocator_thread_result {
184 log::error!("Error in allocator thread!\n\n{:?}", error);
185 }
186 }
187}