use std::os::fd::{AsRawFd, OwnedFd, RawFd}; use std::ffi::{OsString, c_void}; use libc; use crate::gpu::i915::DrmDeviceNode; use super::native; use super::get_drm_version; use std::fs; use std::fs::File; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EngineClass { Render, Copy, Video, VideoEnhance, Compute, Invalid } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct EngineClassInstance { pub engine_class: EngineClass, pub engine_instance: u16, } pub type EngineInfoFlags = u64; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct EngineInfo { pub engine: EngineClassInstance, pub logical_instance: u16, pub flags: EngineInfoFlags, pub capabilities: u64, } #[derive(Debug, PartialEq, Eq)] pub struct DrmGemHandle { pub handle: u32, } fn engine_class_from_u16(engine_class: u16) -> EngineClass { match engine_class { 0 => EngineClass::Render, 1 => EngineClass::Copy, 2 => EngineClass::Video, 3 => EngineClass::VideoEnhance, 4 => EngineClass::Compute, _ => EngineClass::Invalid, } } fn engine_class_instance_from_native(engine_class_instance: native::i915_engine_class_instance) -> EngineClassInstance { EngineClassInstance { engine_class: engine_class_from_u16(engine_class_instance.engine_class), engine_instance: engine_class_instance.engine_instance, } } fn engine_info_from_native(engine_info: native::drm_i915_engine_info) -> EngineInfo { EngineInfo { engine: engine_class_instance_from_native(engine_info.engine), logical_instance: engine_info.logical_instance, flags: engine_info.flags, capabilities: engine_info.capabilities, } } impl EngineInfo { pub fn to_native(&self) -> native::drm_i915_engine_info { native::drm_i915_engine_info { engine: native::i915_engine_class_instance { engine_class: match self.engine.engine_class { EngineClass::Render => 0, EngineClass::Copy => 1, EngineClass::Video => 2, EngineClass::VideoEnhance => 3, EngineClass::Compute => 4, EngineClass::Invalid => 0xFFFF, }, engine_instance: self.engine.engine_instance, }, logical_instance: self.logical_instance, flags: self.flags, capabilities: self.capabilities, rsvd0: 0, rsvd1: [0; 3], rsvd2: [0; 3], } } pub fn from_native(engine_info: native::drm_i915_engine_info) -> EngineInfo { engine_info_from_native(engine_info) } } pub unsafe fn do_query(fd: RawFd, query_id: u32) -> Option<*mut T> { let mut query_item = native::drm_i915_query_item { query_id: query_id as u64, length: 0, data_ptr: core::ptr::null_mut::() as u64, flags: 0, }; let mut query = native::drm_i915_query { items_ptr: (&mut query_item) as *mut native::drm_i915_query_item as u64, num_items: 1, flags: 0, }; let res = libc::ioctl(fd.as_raw_fd(), native::DRM_IOCTL_I915_QUERY, &mut query); if res != 0 { return None; } let result_info = libc::malloc(query_item.length as usize) as *mut T; libc::memset(result_info as *mut c_void, 0, query_item.length as usize); query_item.data_ptr = result_info as u64; let res = libc::ioctl(fd.as_raw_fd(), native::DRM_IOCTL_I915_QUERY, &mut query); if res != 0 { return None; } Some(result_info) } pub fn get_engines(fd: RawFd) -> Option> { unsafe { let engine_data = do_query::(fd, native::DRM_I915_QUERY_ENGINE_INFO)? .as_mut().unwrap(); let engines = engine_data.engines.as_mut_slice(engine_data.num_engines as usize); let mut engines_res: Vec = Vec::new(); for i in 0..engine_data.num_engines { let engine = EngineInfo::from_native(engines[i as usize]); engines_res.push(engine); } Some(engines_res) } } pub fn get_param(fd: RawFd, param_id: i32) -> Option { unsafe { let mut value: i32 = 0; let mut param = native::drm_i915_getparam { param: param_id, value: &mut value as *mut i32 }; let res = libc::ioctl(fd, native::DRM_IOCTL_I915_GETPARAM, &mut param); if res != 0 { return None; } Some(value) } } pub fn get_context_param(fd: RawFd, context_id: u32, param_id: u32) -> Option { unsafe { let mut param = native::drm_i915_gem_context_param { ctx_id: context_id, param: param_id as u64, value: 0, size: 0, }; let res = libc::ioctl(fd, native::DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &mut param); if res != 0 { return None; } Some(param.value) } } pub fn make_gem(fd: RawFd, size: u64) -> Option { unsafe { let mut create = native::drm_i915_gem_create { size: size, handle: 0, pad: 0, }; let res = libc::ioctl(fd, native::DRM_IOCTL_I915_GEM_CREATE, &mut create); if res != 0 { return None; } let handle = DrmGemHandle { handle: create.handle, }; Some(handle) } } pub unsafe fn close_gem_ref(fd: RawFd, handle: &DrmGemHandle) -> Result<(), i32> { unsafe { let mut close = native::drm_gem_close { handle: handle.handle, pad: 0, }; let res = libc::ioctl(fd, native::DRM_IOCTL_GEM_CLOSE, &mut close); if res != 0 { return Err(res); } Ok(()) } } pub fn close_gem(fd: RawFd, handle: DrmGemHandle) -> Result<(), i32> { unsafe { close_gem_ref(fd, &handle) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GemIoctlError { InvalidHandle, PermissionDenied, UnsupportedOnDevice, UnsupportedOnHandle, Unknown(i32), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DrmGemTileInfo { pub tiling_mode: u32, pub swizzle_mode: u32, pub phys_swizzle_mode: u32, } pub fn gem_get_tiling(fd: RawFd, handle: &DrmGemHandle) -> Result { unsafe { let mut tiling = native::drm_i915_gem_get_tiling { handle: handle.handle, tiling_mode: 0, swizzle_mode: 0, phys_swizzle_mode: 0, }; let res = libc::ioctl(fd, native::DRM_IOCTL_I915_GEM_GET_TILING, &mut tiling); let tile_info = DrmGemTileInfo { tiling_mode: tiling.tiling_mode, swizzle_mode: tiling.swizzle_mode, phys_swizzle_mode: tiling.phys_swizzle_mode, }; let errno = *libc::__errno_location(); match errno { 0 => Ok(tile_info), libc::ENOENT => Err(GemIoctlError::InvalidHandle), libc::EPERM => Err(GemIoctlError::PermissionDenied), libc::EOPNOTSUPP => Err(GemIoctlError::UnsupportedOnDevice), _ => Err(GemIoctlError::Unknown(res)), } } } pub fn gem_has_tiling(fd: RawFd, handle: &DrmGemHandle) -> Result { let res = gem_get_tiling(fd, handle); if res.is_ok() { return Ok(true); } if res.is_err() && res.unwrap_err() == GemIoctlError::UnsupportedOnDevice { return Ok(false); } return Err(res.unwrap_err()); } pub fn gem_get_caching(fd: RawFd, handle: &DrmGemHandle) -> Result { unsafe { let mut caching = native::drm_i915_gem_caching { handle: handle.handle, caching: 0, }; let res = libc::ioctl(fd, native::DRM_IOCTL_I915_GEM_GET_CACHING, &mut caching); let errno = *libc::__errno_location(); match errno { 0 => Ok(caching.caching), libc::ENOENT => Err(GemIoctlError::InvalidHandle), libc::EPERM => Err(GemIoctlError::PermissionDenied), libc::ENODEV => Err(GemIoctlError::UnsupportedOnDevice), libc::EOPNOTSUPP => Err(GemIoctlError::UnsupportedOnHandle), _ => Err(GemIoctlError::Unknown(res)), } } } pub fn gem_is_valid(fd: RawFd, handle: &DrmGemHandle) -> Result { let res = gem_has_tiling(fd, handle); if res.is_ok() && res.unwrap() { return Ok(true); } if res.is_err() && res.unwrap_err() == GemIoctlError::InvalidHandle { return Ok(false); } return Err(res.unwrap_err()); } pub fn find_node() -> Option { let inodes = fs::read_dir("/dev/dri").ok()?; for inode in inodes { let inode = inode.ok()?; let path = inode.path(); let path = path.to_str()?; if path.starts_with("/dev/dri/renderD") { let file = File::open(path).unwrap(); let dev = get_drm_version(file.as_raw_fd()); if dev.is_some() && dev.unwrap().name.to_str().unwrap() == "i915" { return Some(DrmDeviceNode { fd: OwnedFd::from(file), path: Some(OsString::from(path)), }); } } } None } pub fn find_fd() -> Option { return find_node().map(|node| node.fd); }