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 trace,
16 },
17 anyhow::{bail, Context, 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 logical_device
69 .ash
70 .get_physical_device_memory_properties(physical_device)
71 };
72 let (handle, client) = Self::spawn_allocator_thread(
73 logical_device.clone(),
74 memory_properties,
75 );
76 Ok(Self {
77 logical_device,
78 client,
79 allocation_thread: Some(handle),
80 memory_properties,
81 })
82 }
83
84 pub fn allocate_memory(
86 &self,
87 requirements: &vk::MemoryRequirements,
88 memory_property_flags: vk::MemoryPropertyFlags,
89 memory_allocate_flags: vk::MemoryAllocateFlags,
90 dedicated: bool,
91 ) -> Result<Block> {
92 let requirements = AllocationRequirements::new(
93 &self.memory_properties,
94 requirements,
95 memory_property_flags,
96 memory_allocate_flags,
97 dedicated,
98 )?;
99
100 let (response_sender, response) =
102 std::sync::mpsc::sync_channel::<Result<Block>>(1);
103 if self
104 .client
105 .send(Request::Allocate(requirements, response_sender))
106 .is_err()
107 {
108 bail!(trace!("Unable to send allocation request!")());
109 }
110
111 response
113 .recv()
114 .with_context(trace!("Error while receiving response!"))?
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}