You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
9.3 KiB
309 lines
9.3 KiB
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<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 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<DrmGemTileInfo, GemIoctlError> {
|
|
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<bool, GemIoctlError> {
|
|
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<u32, GemIoctlError> {
|
|
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<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::InvalidHandle {
|
|
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);
|
|
} |