ursus_core/vulkan/core/
device.rs1use 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}