diff --git a/src/backend.rs b/src/backend.rs index 706a8862..0d1a7a5d 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -4,7 +4,7 @@ use { fixed::Fixed, ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL}, render::Framebuffer, - video::drm::ConnectorType, + video::drm::{ConnectorType, DrmError, DrmVersion}, }, std::{ any::Any, @@ -222,4 +222,5 @@ pub trait BackendDrmDevice { fn on_change(&self, cb: Rc); fn dev_t(&self) -> c::dev_t; fn make_render_device(self: Rc); + fn version(&self) -> Result; } diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 49a900dd..3259f47b 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -21,9 +21,9 @@ use { drm::{ drm_mode_modeinfo, Change, ConnectorStatus, ConnectorType, DrmBlob, DrmConnector, DrmCrtc, DrmEncoder, DrmError, DrmEvent, DrmFramebuffer, DrmMaster, DrmModeInfo, - DrmObject, DrmPlane, DrmProperty, DrmPropertyDefinition, DrmPropertyType, PropBlob, - DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET, DRM_MODE_ATOMIC_NONBLOCK, - DRM_MODE_PAGE_FLIP_EVENT, + DrmObject, DrmPlane, DrmProperty, DrmPropertyDefinition, DrmPropertyType, + DrmVersion, PropBlob, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET, + DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT, }, gbm::{GbmDevice, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT}, ModifiedFormat, INVALID_MODIFIER, @@ -93,6 +93,10 @@ impl BackendDrmDevice for MetalDrmDevice { fn make_render_device(self: Rc) { self.backend.make_render_device(&self, true); } + + fn version(&self) -> Result { + self.gbm.drm.version() + } } pub struct HandleEvents { diff --git a/src/backends/x.rs b/src/backends/x.rs index 990adf03..1d3553b4 100644 --- a/src/backends/x.rs +++ b/src/backends/x.rs @@ -17,7 +17,7 @@ use { queue::AsyncQueue, syncqueue::SyncQueue, }, video::{ - drm::{ConnectorType, Drm, DrmError}, + drm::{ConnectorType, Drm, DrmError, DrmVersion}, gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING}, ModifiedFormat, INVALID_MODIFIER, }, @@ -291,7 +291,7 @@ impl XBackend { self.state .backend_events .push(BackendEvent::NewDrmDevice(Rc::new(XDrmDevice { - _backend: self.clone(), + backend: self.clone(), id: self.drm_device_id, dev: self.drm_dev, }))); @@ -939,7 +939,7 @@ impl XBackend { } struct XDrmDevice { - _backend: Rc, + backend: Rc, id: DrmDeviceId, dev: dev_t, } @@ -965,6 +965,10 @@ impl BackendDrmDevice for XDrmDevice { log::warn!("make_render_device is not supported by the X backend"); // nothing } + + fn version(&self) -> Result { + self.backend.gbm.drm.version() + } } struct XOutput { diff --git a/src/state.rs b/src/state.rs index ae885e74..37ec26c0 100644 --- a/src/state.rs +++ b/src/state.rs @@ -49,6 +49,7 @@ use { xwayland::{self, XWaylandEvent}, }, ahash::AHashMap, + bstr::ByteSlice, jay_config::PciId, std::{ cell::{Cell, RefCell}, @@ -284,8 +285,21 @@ impl State { config.devices_enumerated() } if self.render_ctx.get().is_none() { - if let Some(dev) = self.drm_devs.lock().values().next() { + for dev in self.drm_devs.lock().values() { + if let Ok(version) = dev.dev.version() { + if version.name.contains_str("nvidia") { + continue; + } + } dev.make_render_device(); + if self.render_ctx.get().is_some() { + break; + } + } + if self.render_ctx.get().is_none() { + if let Some(dev) = self.drm_devs.lock().values().next() { + dev.make_render_device(); + } } } } diff --git a/src/video/drm.rs b/src/video/drm.rs index cf6ccba4..6691a45e 100644 --- a/src/video/drm.rs +++ b/src/video/drm.rs @@ -34,7 +34,7 @@ use crate::{ utils::{errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt}, video::{ dmabuf::DmaBuf, - drm::sys::{DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH}, + drm::sys::{get_version, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH}, INVALID_MODIFIER, }, }; @@ -103,6 +103,8 @@ pub enum DrmError { ReadEvents(#[source] OsError), #[error("Read invalid data from drm device")] InvalidRead, + #[error("Could not determine the drm version")] + Version(#[source] OsError), } fn render_node_name(fd: c::c_int) -> Result { @@ -165,6 +167,10 @@ impl Drm { pub fn get_nodes(&self) -> Result, DrmError> { get_nodes(self.fd.raw()).map_err(DrmError::GetNodes) } + + pub fn version(&self) -> Result { + get_version(self.fd.raw()).map_err(DrmError::Version) + } } pub struct DrmMaster { @@ -590,6 +596,16 @@ pub struct DrmModeInfo { pub name: BString, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct DrmVersion { + pub version_major: i32, + pub version_minor: i32, + pub version_patchlevel: i32, + pub name: BString, + pub date: BString, + pub desc: BString, +} + impl DrmModeInfo { pub fn create_blob(&self, master: &Rc) -> Result { let raw = self.to_raw(); diff --git a/src/video/drm/sys.rs b/src/video/drm/sys.rs index 48cd71bd..7acbcb92 100644 --- a/src/video/drm/sys.rs +++ b/src/video/drm/sys.rs @@ -8,7 +8,7 @@ use { DrmBlob, DrmCardResources, DrmConnector, DrmConnectorInfo, DrmCrtc, DrmEncoder, DrmEncoderInfo, DrmError, DrmFb, DrmModeInfo, DrmPlane, DrmPlaneInfo, DrmProperty, DrmPropertyDefinition, DrmPropertyEnumValue, DrmPropertyType, DrmPropertyValue, - NodeType, + DrmVersion, NodeType, }, }, ahash::AHashMap, @@ -18,7 +18,7 @@ use { io::{BufRead, BufReader}, mem, }, - uapi::{c, OwnedFd, Pod, Ustring}, + uapi::{c, pod_zeroed, OwnedFd, Pod, Ustring}, }; pub unsafe fn ioctl(fd: c::c_int, request: c::c_ulong, t: &mut T) -> Result { @@ -1075,3 +1075,60 @@ pub fn mode_getprobblob( } Ok(res.length as _) } + +#[repr(C)] +struct drm_version { + version_major: c::c_int, + version_minor: c::c_int, + version_patchlevel: c::c_int, + name_len: usize, // actually __kernel_size_t but nobody cares about x32 + name: *mut u8, + date_len: usize, + date: *mut u8, + desc_len: usize, + desc: *mut u8, +} + +unsafe impl Pod for drm_version {} + +const DRM_IOCTL_VERSION: u64 = drm_iowr::(0x00); + +pub fn get_version(fd: c::c_int) -> Result { + let mut name = Vec::::new(); + let mut date = Vec::::new(); + let mut desc = Vec::::new(); + let mut res: drm_version = pod_zeroed(); + loop { + res.name_len = name.capacity(); + res.name = name.as_mut_ptr(); + res.date_len = date.capacity(); + res.date = date.as_mut_ptr(); + res.desc_len = desc.capacity(); + res.desc = desc.as_mut_ptr(); + unsafe { + ioctl(fd, DRM_IOCTL_VERSION, &mut res)?; + } + if res.name_len <= name.capacity() + && res.date_len <= date.capacity() + && res.desc_len <= desc.capacity() + { + break; + } + name.reserve_exact(res.name_len); + date.reserve_exact(res.date_len); + desc.reserve_exact(res.desc_len); + } + unsafe { + name.set_len(res.name_len); + date.set_len(res.date_len); + desc.set_len(res.desc_len); + } + Ok(DrmVersion { + version_major: res.version_major, + version_minor: res.version_minor, + version_patchlevel: res.version_patchlevel, + name: name.into(), + date: date.into(), + desc: desc.into(), + }) +}