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, Clone, Copy, 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<T>(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::<c_void>() 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<Vec<EngineInfo>> {
unsafe {
let engine_data =
do_query::<native::drm_i915_query_engine_info>(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<EngineInfo> = 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<i32> {
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<u64> {
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<DrmGemHandle> {
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 fn close_gem(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(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GemIoctlError {
InvalidHandle,
PermissionDenied,
Unknown(i32),
}
pub fn gem_has_tiling(fd: RawFd, handle: DrmGemHandle) -> Result<bool, GemIoctlError> {
unsafe {
let mut tiling = native::drm_i915_gem_set_tiling {
handle: handle.handle,
tiling_mode: 0,
stride: 0,
swizzle_mode: 0,
};
let res = libc::ioctl(fd, native::DRM_IOCTL_I915_GEM_SET_TILING, &mut tiling);
match -res {
0 => Ok(true),
libc::ENOENT => Err(GemIoctlError::InvalidHandle),
libc::EPERM => Err(GemIoctlError::PermissionDenied),
libc::EINVAL => Ok(false),
_ => Err(GemIoctlError::Unknown(res)),
}
}
}
pub fn gem_is_valid(fd: RawFd, handle: DrmGemHandle) -> Result<bool, GemIoctlError> {
let res = gem_has_tiling(fd, handle);
if res.is_ok() && res.unwrap() {
return Ok(true);
}
if res.is_err() && res.unwrap_err() == GemIoctlError::PermissionDenied {
return Ok(false);
}
return Err(res.unwrap_err());
}
pub fn find_node() -> Option<DrmDeviceNode> {
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<OwnedFd> {
return find_node().map(|node| node.fd);
}