diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 3a7e043c..b61a676c 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -44,10 +44,10 @@ use { INVALID_MODIFIER, Modifier, dmabuf::DmaBufId, drm::{ - ConnectorStatus, ConnectorType, DRM_CLIENT_CAP_ATOMIC, DrmBlob, DrmConnector, - DrmCrtc, DrmEncoder, DrmError, DrmEvent, DrmFb, DrmLease, DrmMaster, DrmModeInfo, - DrmObject, DrmPlane, DrmProperty, DrmPropertyDefinition, DrmPropertyType, - DrmVersion, HDMI_EOTF_TRADITIONAL_GAMMA_SDR, drm_mode_modeinfo, + ConnectorStatus, ConnectorType, DRM_CLIENT_CAP_ATOMIC, DrmBlob, DrmCardResources, + DrmConnector, DrmCrtc, DrmEncoder, DrmError, DrmEvent, DrmFb, DrmLease, DrmMaster, + DrmModeInfo, DrmObject, DrmPlane, DrmProperty, DrmPropertyDefinition, + DrmPropertyType, DrmVersion, HDMI_EOTF_TRADITIONAL_GAMMA_SDR, drm_mode_modeinfo, hdr_output_metadata, }, gbm::GbmDevice, @@ -105,13 +105,10 @@ pub struct MetalDrmDevice { pub devnum: c::dev_t, pub devnode: CString, pub master: Rc, + pub supports_kms: bool, pub crtcs: AHashMap>, pub encoders: AHashMap>, pub planes: AHashMap>, - pub _min_width: u32, - pub _max_width: u32, - pub _min_height: u32, - pub _max_height: u32, pub cursor_width: u64, pub cursor_height: u64, pub supports_async_commit: bool, @@ -1822,6 +1819,9 @@ impl MetalBackend { } fn handle_drm_change_(self: &Rc, dev: &Rc) -> Result<(), MetalError> { + if !dev.dev.supports_kms { + return Ok(()); + } if let Err(e) = self.update_device_properties(dev) { return Err(MetalError::UpdateProperties(e)); } @@ -1982,46 +1982,44 @@ impl MetalBackend { pending: PendingDrmDevice, master: &Rc, ) -> Result, MetalError> { - if let Err(e) = master.set_client_cap(DRM_CLIENT_CAP_ATOMIC, 2) { - return Err(MetalError::AtomicModesetting(e)); - } - let resources = master.get_resources()?; - - let (cursor_width, cursor_height) = match master.get_cursor_size() { - Ok(s) => s, - Err(e) => { + let mut resources = DrmCardResources::default(); + let mut planes = AHashMap::new(); + let mut crtcs = AHashMap::new(); + let mut encoders = AHashMap::new(); + let (mut cursor_width, mut cursor_height) = (1, 1); + let supports_kms = master.supports_get_resources()?; + if supports_kms { + if let Err(e) = master.set_client_cap(DRM_CLIENT_CAP_ATOMIC, 2) { + return Err(MetalError::AtomicModesetting(e)); + } + resources = master.get_resources()?; + (cursor_width, cursor_height) = master.get_cursor_size().unwrap_or_else(|e| { log::warn!("Can't determine size of cursor planes: {}", ErrorFmt(e)); (64, 64) - } - }; - - let mut planes = AHashMap::new(); - for plane in master.get_planes()? { - match create_plane(plane, master) { - Ok(p) => { - planes.insert(p.id, Rc::new(p)); + }); + for plane in master.get_planes()? { + match create_plane(plane, master) { + Ok(p) => { + planes.insert(p.id, Rc::new(p)); + } + Err(e) => return Err(MetalError::CreatePlane(e)), } - Err(e) => return Err(MetalError::CreatePlane(e)), } - } - - let mut crtcs = AHashMap::new(); - for (idx, crtc) in resources.crtcs.iter().copied().enumerate() { - match create_crtc(crtc, idx, master, &planes) { - Ok(c) => { - crtcs.insert(c.id, Rc::new(c)); + for (idx, crtc) in resources.crtcs.iter().copied().enumerate() { + match create_crtc(crtc, idx, master, &planes) { + Ok(c) => { + crtcs.insert(c.id, Rc::new(c)); + } + Err(e) => return Err(MetalError::CreateCrtc(e)), } - Err(e) => return Err(MetalError::CreateCrtc(e)), } - } - - let mut encoders = AHashMap::new(); - for encoder in resources.encoders { - match create_encoder(encoder, master, &crtcs) { - Ok(e) => { - encoders.insert(e.id, Rc::new(e)); + for encoder in resources.encoders { + match create_encoder(encoder, master, &crtcs) { + Ok(e) => { + encoders.insert(e.id, Rc::new(e)); + } + Err(e) => return Err(MetalError::CreateEncoder(e)), } - Err(e) => return Err(MetalError::CreateEncoder(e)), } } @@ -2072,13 +2070,10 @@ impl MetalBackend { devnum: pending.devnum, devnode: pending.devnode, master: master.clone(), + supports_kms, crtcs, encoders, planes, - _min_width: resources.min_width, - _max_width: resources.max_width, - _min_height: resources.min_height, - _max_height: resources.max_height, cursor_width, cursor_height, supports_async_commit: master.supports_async_commit(), @@ -2099,7 +2094,11 @@ impl MetalBackend { min_post_commit_margin: Cell::new(DEFAULT_POST_COMMIT_MARGIN), }); - let (connectors, futures) = get_connectors(self, &dev, &resources.connectors)?; + let mut connectors = CopyHashMap::new(); + let mut futures = CopyHashMap::new(); + if supports_kms { + (connectors, futures) = get_connectors(self, &dev, &resources.connectors)?; + } let slf = Rc::new(MetalDrmDeviceData { dev: dev.clone(), @@ -2574,6 +2573,9 @@ impl MetalBackend { fn init_drm_device(&self, dev: &Rc) -> Result<(), MetalError> { self.break_leases(dev); + if dev.connectors.is_empty() { + return Ok(()); + } enum Quirks { DirectScanout, NonDefaultFormat, diff --git a/src/egui_adapter/egui_vulkan.rs b/src/egui_adapter/egui_vulkan.rs index aae9f29d..110efae3 100644 --- a/src/egui_adapter/egui_vulkan.rs +++ b/src/egui_adapter/egui_vulkan.rs @@ -408,50 +408,57 @@ impl EgvRenderer { .enumerate_physical_devices() .map_err(EgvError::EnumeratePhysicalDevice)? }; - 'outer: for phy in devices { - let res = unsafe { instance.enumerate_device_extension_properties(phy) }; - let exts = match res { - Ok(res) => map_extension_properties(res), - Err(e) => { - log::error!( - "Could not enumerate extensions of physical device: {}", - ErrorFmt(e), - ); - continue; + for software in [false, true] { + 'outer: for &phy in &devices { + let res = unsafe { instance.enumerate_device_extension_properties(phy) }; + let exts = match res { + Ok(res) => map_extension_properties(res), + Err(e) => { + log::error!( + "Could not enumerate extensions of physical device: {}", + ErrorFmt(e), + ); + continue; + } + }; + let mut drm_props = PhysicalDeviceDrmPropertiesEXT::default(); + let mut props = PhysicalDeviceProperties2::default().push_next(&mut drm_props); + unsafe { + instance.get_physical_device_properties2(phy, &mut props); } - }; - let mut drm_props = PhysicalDeviceDrmPropertiesEXT::default(); - let mut props = PhysicalDeviceProperties2::default().push_next(&mut drm_props); - unsafe { - instance.get_physical_device_properties2(phy, &mut props); - } - let props = props.properties; - physical_device = phy; - device_extensions = exts; - device_properties = props; - if let Some(dev) = dev { - if device_extensions.not_contains_key(physical_device_drm::NAME) { - continue 'outer; - } - let major = uapi::major(dev) as i64; - let minor = uapi::minor(dev) as i64; - let matches = (drm_props.has_primary == vk::TRUE - && drm_props.primary_major == major - && drm_props.primary_minor == minor) - || (drm_props.has_render == vk::TRUE - && drm_props.render_major == major - && drm_props.render_minor == minor); - if matches { - break 'find_device; - } - } else { - if device_properties.device_type == PhysicalDeviceType::CPU { - break 'find_device; + let props = props.properties; + physical_device = phy; + device_extensions = exts; + device_properties = props; + if let Some(dev) = dev + && !software + { + if device_extensions.not_contains_key(physical_device_drm::NAME) { + continue 'outer; + } + let major = uapi::major(dev) as i64; + let minor = uapi::minor(dev) as i64; + let matches = (drm_props.has_primary == vk::TRUE + && drm_props.primary_major == major + && drm_props.primary_minor == minor) + || (drm_props.has_render == vk::TRUE + && drm_props.render_major == major + && drm_props.render_minor == minor); + if matches { + break 'find_device; + } + } else { + if device_properties.device_type == PhysicalDeviceType::CPU { + break 'find_device; + } } } } return Err(EgvError::NoVulkanDevice); } + if device_properties.device_type == PhysicalDeviceType::CPU && dev.is_some() { + log::warn!("Using software rendering"); + } if device_properties.api_version < VULKAN_API_VERSION { return Err(EgvError::NoVulkan13); } diff --git a/src/video/drm.rs b/src/video/drm.rs index a4396d08..0ce27257 100644 --- a/src/video/drm.rs +++ b/src/video/drm.rs @@ -26,7 +26,8 @@ use { get_version, mode_addfb2, mode_atomic, mode_create_blob, mode_destroy_blob, mode_get_resources, mode_getconnector, mode_getencoder, mode_getplane, mode_getplaneresources, mode_getprobblob, mode_getproperty, mode_obj_getproperties, - mode_rmfb, prime_fd_to_handle, queue_sequence, revoke_lease, set_client_cap, + mode_rmfb, mode_supports_get_resources, prime_fd_to_handle, queue_sequence, + revoke_lease, set_client_cap, }, }, }, @@ -168,11 +169,13 @@ fn reopen(fd: c::c_int, need_primary: bool) -> Result, DrmError> { return Ok(Rc::new(fd)); } let path = 'path: { - if get_node_type_from_fd(fd).map_err(DrmError::GetDeviceType)? == NodeType::Render { - break 'path uapi::format_ustr!("/proc/self/fd/{}", fd); - } - if !need_primary && let Ok(path) = render_node_name(fd) { - break 'path path; + if !need_primary { + if get_node_type_from_fd(fd).map_err(DrmError::GetDeviceType)? == NodeType::Render { + break 'path uapi::format_ustr!("/proc/self/fd/{}", fd); + } + if let Ok(path) = render_node_name(fd) { + break 'path path; + } } device_node_name(fd)? }; @@ -212,6 +215,10 @@ impl Drm { self.fd.raw() } + pub fn dup_primary(&self) -> Result { + Self::reopen(self.fd.raw(), true) + } + pub fn dup_render(&self) -> Result { Self::reopen(self.fd.raw(), false) } @@ -333,6 +340,10 @@ impl DrmMaster { mode_get_resources(self.raw()) } + pub fn supports_get_resources(&self) -> Result { + mode_supports_get_resources(self.raw()) + } + pub fn get_cap(&self, cap: u64) -> Result { get_cap(self.raw(), cap) } @@ -745,12 +756,12 @@ drm_obj!(DrmFb, DRM_MODE_OBJECT_FB); drm_obj!(DrmBlob, DRM_MODE_OBJECT_BLOB); drm_obj!(DrmPlane, DRM_MODE_OBJECT_PLANE); -#[derive(Debug)] +#[derive(Debug, Default)] pub struct DrmCardResources { - pub min_width: u32, - pub max_width: u32, - pub min_height: u32, - pub max_height: u32, + pub _min_width: u32, + pub _max_width: u32, + pub _min_height: u32, + pub _max_height: u32, pub _fbs: Vec, pub crtcs: Vec, pub connectors: Vec, diff --git a/src/video/drm/sys.rs b/src/video/drm/sys.rs index e0a55ccf..ffc876da 100644 --- a/src/video/drm/sys.rs +++ b/src/video/drm/sys.rs @@ -17,7 +17,11 @@ use { ffi::CString, io::{BufRead, BufReader}, }, - uapi::{OwnedFd, Pod, Ustring, c, pod_zeroed}, + uapi::{ + OwnedFd, Pod, Ustring, + c::{self, c_int}, + pod_zeroed, + }, }; pub unsafe fn ioctl(fd: c::c_int, request: c::c_ulong, t: &mut T) -> Result { @@ -546,10 +550,10 @@ pub fn mode_get_resources(fd: c::c_int) -> Result { } Ok(DrmCardResources { - min_width: res.min_width, - max_width: res.max_width, - min_height: res.min_height, - max_height: res.max_height, + _min_width: res.min_width, + _max_width: res.max_width, + _min_height: res.min_height, + _max_height: res.max_height, _fbs: fbs, crtcs, connectors, @@ -557,6 +561,16 @@ pub fn mode_get_resources(fd: c::c_int) -> Result { }) } +pub fn mode_supports_get_resources(fd: c_int) -> Result { + let mut res = drm_mode_card_res::default(); + let res = unsafe { ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &mut res) }; + match res { + Ok(_) => Ok(true), + Err(e) if e.0 == c::EOPNOTSUPP => Ok(false), + Err(e) => Err(DrmError::GetResources(e)), + } +} + #[repr(C)] struct drm_mode_get_plane_res { plane_id_ptr: u64, diff --git a/src/video/gbm.rs b/src/video/gbm.rs index 52ebb7ae..eb34ca71 100644 --- a/src/video/gbm.rs +++ b/src/video/gbm.rs @@ -7,8 +7,8 @@ use { BO_USE_RENDERING, BO_USE_SCANOUT, BO_USE_WRITE, BufferObject, BufferUsage, MappedBuffer, }, - format::{Format, formats}, - utils::oserror::OsError, + format::{Format, XRGB8888, formats}, + utils::{errorfmt::ErrorFmt, oserror::OsError}, video::{ INVALID_MODIFIER, Modifier, dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec}, @@ -214,14 +214,26 @@ unsafe fn export_bo(dmabuf_ids: &DmaBufIds, bo: *mut Bo) -> Result Result { - let drm = drm.dup_render()?; - let dev = unsafe { gbm_create_device(drm.raw()) }; - if dev.is_null() { - Err(GbmError::CreateDevice) - } else { - let dev = Rc::new(DeviceHolder { dev }); - Ok(Self { drm, dev }) - } + let open = |drm: Drm| { + let dev = unsafe { gbm_create_device(drm.raw()) }; + if dev.is_null() { + Err(GbmError::CreateDevice) + } else { + let dev = Rc::new(DeviceHolder { dev }); + Ok(Self { drm, dev }) + } + }; + let dma_buf_ids = DmaBufIds::default(); + let create_bo = + |gbm: &GbmDevice| gbm.create_bo(&dma_buf_ids, 1, 1, XRGB8888, &[INVALID_MODIFIER], 0); + let gbm = open(drm.dup_render()?)?; + match create_bo(&gbm) { + Ok(..) => return Ok(gbm), + Err(e) => log::warn!("Render node cannot allocate buffers: {}", ErrorFmt(e)), + }; + let gbm = open(drm.dup_primary()?)?; + create_bo(&gbm)?; + Ok(gbm) } pub fn raw(&self) -> *mut Device {