lgpu_hal/vulkan/
device.rs1use super::{allocator, bindless, VulkanCommandRecorder};
4use crate::HalError;
5use ash::vk;
6
7pub struct VulkanDevice {
8 pub device: ash::Device,
9 pub physical_device: vk::PhysicalDevice,
10 pub queue: std::sync::Mutex<vk::Queue>,
11 pub queue_family_index: u32,
12 pub memory_properties: vk::PhysicalDeviceMemoryProperties,
13 pub non_coherent_atom_size: u64,
14 pub bindless_heap: Option<bindless::VulkanBindlessHeap>,
15 pub swapchain_loader: Option<ash::khr::swapchain::Device>,
16 pub command_recorder_cache: std::sync::Mutex<Vec<(vk::CommandPool, vk::CommandBuffer)>>,
17 pub fence_cache: std::sync::Mutex<Vec<vk::Fence>>,
18 pub internal_frame_semaphore: vk::Semaphore,
19 pub internal_frame_counter: std::sync::atomic::AtomicU64,
20 pub pending_async_recorders: std::sync::Mutex<Vec<(u64, Vec<VulkanCommandRecorder>)>>,
21 pub allocator: std::sync::Mutex<allocator::VulkanSuballocator>,
22 pub pipeline_cache: vk::PipelineCache,
23}
24
25impl VulkanDevice {
26 pub(crate) fn find_memory_type(
27 &self,
28 type_filter: u32,
29 required: vk::MemoryPropertyFlags,
30 ) -> Result<(u32, bool), HalError> {
31 let wants_host = required.contains(vk::MemoryPropertyFlags::HOST_VISIBLE);
32 if wants_host {
33 let preferred = required | vk::MemoryPropertyFlags::HOST_COHERENT;
34 for i in 0..self.memory_properties.memory_type_count {
35 if (type_filter & (1 << i)) != 0
36 && (self.memory_properties.memory_types[i as usize].property_flags & preferred)
37 == preferred
38 {
39 return Ok((i, true));
40 }
41 }
42 }
43
44 for i in 0..self.memory_properties.memory_type_count {
45 if (type_filter & (1 << i)) != 0
46 && (self.memory_properties.memory_types[i as usize].property_flags & required)
47 == required
48 {
49 let is_coherent = (self.memory_properties.memory_types[i as usize].property_flags
50 & vk::MemoryPropertyFlags::HOST_COHERENT)
51 == vk::MemoryPropertyFlags::HOST_COHERENT;
52 return Ok((i, is_coherent));
53 }
54 }
55 Err(HalError::OutOfMemory(
56 "Suitable memory type not found".to_string(),
57 ))
58 }
59
60 pub fn wait_idle(&self) -> Result<(), HalError> {
61 unsafe {
62 self.device
63 .device_wait_idle()
64 .map_err(|e| HalError::BackendError(format!("device_wait_idle failed: {e}")))?;
65 }
66 let mut pending = self.pending_async_recorders.lock().unwrap();
67 let mut cache = self.command_recorder_cache.lock().unwrap();
68 for (_, recorders) in pending.drain(..) {
69 for r in recorders {
70 unsafe {
71 self.device
72 .reset_command_buffer(
73 r.command_buffer,
74 vk::CommandBufferResetFlags::empty(),
75 )
76 .ok();
77 }
78 cache.push((r.command_pool, r.command_buffer));
79 }
80 }
81 Ok(())
82 }
83}
84
85impl Drop for VulkanDevice {
86 fn drop(&mut self) {
87 unsafe {
88 let _ = self.device.device_wait_idle();
89 if let Some(heap) = self.bindless_heap.take() {
90 heap.destroy(&self.device);
91 }
92 self.device
93 .destroy_semaphore(self.internal_frame_semaphore, None);
94 for (pool, _) in self.command_recorder_cache.lock().unwrap().drain(..) {
95 self.device.destroy_command_pool(pool, None);
96 }
97 for (_, recorders) in self.pending_async_recorders.lock().unwrap().drain(..) {
98 for r in recorders {
99 self.device.destroy_command_pool(r.command_pool, None);
100 }
101 }
102 for fence in self.fence_cache.lock().unwrap().drain(..) {
103 self.device.destroy_fence(fence, None);
104 }
105 self.allocator.lock().unwrap().destroy(&self.device);
106 self.device
107 .destroy_pipeline_cache(self.pipeline_cache, None);
108 self.device.destroy_device(None);
109 }
110 }
111}
112
113unsafe impl Send for VulkanDevice {}
114unsafe impl Sync for VulkanDevice {}