Skip to main content

lgpu_hal/vulkan/
device.rs

1//! Vulkan logical device and execution context.
2
3use 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 {}