1#![cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
2
3use core::mem::MaybeUninit;
4use std::{string::ToString, vec::Vec};
5
6use ash::{ext, khr, vk};
7
8impl super::Instance {
9 pub unsafe fn create_surface_from_drm(
15 &self,
16 fd: i32,
17 plane: u32,
18 connector_id: u32,
19 width: u32,
20 height: u32,
21 refresh_rate: u32,
22 ) -> Result<super::Surface, crate::InstanceError> {
23 if !self
24 .shared
25 .extensions
26 .contains(&ext::acquire_drm_display::NAME)
27 {
28 return Err(crate::InstanceError::new(
29 "Vulkan driver does not support VK_EXT_acquire_drm_display".to_string(),
30 ));
31 }
32
33 let drm_stat = {
34 let mut stat = MaybeUninit::<libc::stat>::uninit();
35
36 if unsafe { libc::fstat(fd, stat.as_mut_ptr()) } != 0 {
37 return Err(crate::InstanceError::new(
38 "Unable to fstat drm device".to_string(),
39 ));
40 }
41
42 unsafe { stat.assume_init() }
43 };
44
45 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
46 Ok(devices) => devices,
47 Err(err) => {
48 log::error!("enumerate_adapters: {}", err);
49 Vec::new()
50 }
51 };
52
53 let mut physical_device = None;
54
55 for device in raw_devices {
56 let properties2 = vk::PhysicalDeviceProperties2KHR::default();
57
58 let mut drm_props = vk::PhysicalDeviceDrmPropertiesEXT::default();
59 let mut properties2 = properties2.push_next(&mut drm_props);
60
61 unsafe {
62 self.shared
63 .raw
64 .get_physical_device_properties2(device, &mut properties2)
65 };
66
67 let primary_devid =
76 libc::makedev(drm_props.primary_major as _, drm_props.primary_minor as _);
77 let render_devid =
78 libc::makedev(drm_props.render_major as _, drm_props.render_minor as _);
79
80 #[allow(clippy::useless_conversion)]
83 if [primary_devid, render_devid]
84 .map(u64::from)
85 .contains(&drm_stat.st_rdev)
86 {
87 physical_device = Some(device)
88 }
89 }
90
91 let physical_device = physical_device.ok_or(crate::InstanceError::new(
92 "Failed to find suitable drm device".to_string(),
93 ))?;
94
95 let acquire_drm_display_instance =
96 ext::acquire_drm_display::Instance::new(&self.shared.entry, &self.shared.raw);
97
98 let display = unsafe {
99 acquire_drm_display_instance
100 .get_drm_display(physical_device, fd, connector_id)
101 .expect("Failed to get drm display")
102 };
103
104 unsafe {
105 acquire_drm_display_instance
106 .acquire_drm_display(physical_device, fd, display)
107 .expect("Failed to acquire drm display")
108 }
109
110 let display_instance = khr::display::Instance::new(&self.shared.entry, &self.shared.raw);
111
112 let modes = unsafe {
113 display_instance
114 .get_display_mode_properties(physical_device, display)
115 .expect("Failed to get display modes")
116 };
117
118 let mut mode = None;
119
120 for current_mode in modes {
121 log::trace!(
122 "Comparing mode {}x{}@{} with {width}x{height}@{refresh_rate}",
123 current_mode.parameters.visible_region.width,
124 current_mode.parameters.visible_region.height,
125 current_mode.parameters.refresh_rate
126 );
127 if current_mode.parameters.refresh_rate == refresh_rate
128 && current_mode.parameters.visible_region.width == width
129 && current_mode.parameters.visible_region.height == height
130 {
131 mode = Some(current_mode)
132 }
133 }
134
135 let mode = mode.ok_or(crate::InstanceError::new(
136 "Failed to find suitable display mode".to_string(),
137 ))?;
138
139 let create_info = vk::DisplaySurfaceCreateInfoKHR::default()
140 .display_mode(mode.display_mode)
141 .image_extent(mode.parameters.visible_region)
142 .transform(vk::SurfaceTransformFlagsKHR::IDENTITY)
143 .alpha_mode(vk::DisplayPlaneAlphaFlagsKHR::OPAQUE)
144 .plane_index(plane);
145
146 let surface = unsafe { display_instance.create_display_plane_surface(&create_info, None) }
147 .expect("Failed to create DRM surface");
148
149 Ok(self.create_surface_from_vk_surface_khr(surface))
150 }
151}