Skip to main content

ursus_core/vulkan/core/
device.rs

1use crate::vulkan::Instance;
2use ash::vk;
3
4pub struct Device {
5    pub handle: ash::Device,
6    pub physical: vk::PhysicalDevice,
7    pub physical_props: vk::PhysicalDeviceProperties,
8    pub graphics_queue: vk::Queue,
9    pub present_queue: vk::Queue,
10    pub graphics_family: u32,
11    pub present_family: u32,
12}
13
14impl Device {
15    pub fn new(instance: &Instance, surface: vk::SurfaceKHR) -> anyhow::Result<Self> {
16        let (physical, graphics_family, present_family) =
17            Self::pick_physical(&instance.handle, &instance.entry, surface)?;
18
19        let physical_props = unsafe { instance.handle.get_physical_device_properties(physical) };
20        let name = unsafe { std::ffi::CStr::from_ptr(physical_props.device_name.as_ptr()) };
21        log::info!("GPU: {:?}", name);
22
23        let unique_families: Vec<u32> = if graphics_family != present_family {
24            vec![graphics_family, present_family]
25        } else {
26            vec![graphics_family]
27        };
28
29        let queue_infos: Vec<_> = unique_families
30            .iter()
31            .map(|&family| vk::DeviceQueueCreateInfo::default().queue_family_index(family).queue_priorities(&[1.0]))
32            .collect();
33
34        let extensions = [ash::khr::swapchain::NAME.as_ptr()];
35
36        let mut features12 = vk::PhysicalDeviceVulkan12Features::default()
37            .buffer_device_address(true)
38            .descriptor_indexing(true)
39            .runtime_descriptor_array(true)
40            .shader_sampled_image_array_non_uniform_indexing(true)
41            .descriptor_binding_sampled_image_update_after_bind(true)
42            .descriptor_binding_partially_bound(true)
43            .descriptor_binding_variable_descriptor_count(true);
44
45        let mut features13 =
46            vk::PhysicalDeviceVulkan13Features::default().dynamic_rendering(true).synchronization2(true);
47
48        let features10 = vk::PhysicalDeviceFeatures::default().sampler_anisotropy(true);
49
50        let create_info = vk::DeviceCreateInfo::default()
51            .queue_create_infos(&queue_infos)
52            .enabled_extension_names(&extensions)
53            .enabled_features(&features10)
54            .push_next(&mut features12)
55            .push_next(&mut features13);
56
57        let handle = unsafe { instance.handle.create_device(physical, &create_info, None)? };
58
59        let graphics_queue = unsafe { handle.get_device_queue(graphics_family, 0) };
60        let present_queue = unsafe { handle.get_device_queue(present_family, 0) };
61
62        log::info!("Logical device created");
63
64        Ok(Self { handle, physical, physical_props, graphics_queue, present_queue, graphics_family, present_family })
65    }
66
67    fn pick_physical(
68        instance: &ash::Instance,
69        entry: &ash::Entry,
70        surface: vk::SurfaceKHR,
71    ) -> anyhow::Result<(vk::PhysicalDevice, u32, u32)> {
72        let surface_loader = ash::khr::surface::Instance::new(entry, instance);
73        let devices = unsafe { instance.enumerate_physical_devices()? };
74
75        let mut fallback = None;
76
77        for device in devices {
78            let props = unsafe { instance.get_physical_device_properties(device) };
79            let queues = unsafe { instance.get_physical_device_queue_family_properties(device) };
80
81            let mut graphics_family = None;
82            let mut present_family = None;
83
84            for (i, q) in queues.iter().enumerate() {
85                let i = i as u32;
86                if q.queue_flags.contains(vk::QueueFlags::GRAPHICS) {
87                    graphics_family = Some(i);
88                }
89                let present_support =
90                    unsafe { surface_loader.get_physical_device_surface_support(device, i, surface)? };
91                if present_support {
92                    present_family = Some(i);
93                }
94            }
95
96            if let (Some(gf), Some(pf)) = (graphics_family, present_family) {
97                if props.device_type == vk::PhysicalDeviceType::DISCRETE_GPU {
98                    return Ok((device, gf, pf));
99                }
100                fallback = Some((device, gf, pf));
101            }
102        }
103
104        fallback.ok_or_else(|| anyhow::anyhow!("Подходящая GPU не найдена"))
105    }
106}
107
108impl Drop for Device {
109    fn drop(&mut self) {
110        unsafe { self.handle.destroy_device(None) };
111        log::debug!("Device destroyed");
112    }
113}