#![allow(unused_imports)] use gpu::i915::GemHandle; use intel_gpu::*; use uapi::i915::{self, DrmGemHandle}; use std::fs; use std::{fs::File, os::fd::{AsRawFd, RawFd}}; use std::thread; #[test] fn test_i915_uapi_get_version() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let drm_version = uapi::get_drm_version(node.fd.as_raw_fd()).expect("Failed to get drm version"); assert_eq!(drm_version.name.to_str().unwrap(), "i915"); assert_eq!(drm_version.desc.to_str().unwrap(), "Intel Graphics"); } } #[test] fn test_i915_uapi_get_engines() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let _engines = i915::get_engines(node.fd.as_raw_fd()).expect("Failed to get engines"); let fail_fd = File::open("/dev/null").expect("Failed to open /dev/null"); assert!(i915::get_engines(fail_fd.as_raw_fd()).is_none()); } } #[test] fn test_i915_uapi_get_param_fail() { let fd = File::open("/dev/null").expect("Failed to open /dev/null"); let param = i915::get_param(fd.as_raw_fd(), native::I915_PARAM_CHIPSET_ID as i32); assert!(param.is_none()); } #[test] fn test_i915_uapi_native_engine_info() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let engines = i915::get_engines(node.fd.as_raw_fd()).expect("Failed to get engines"); for engine in engines { let native_engine = engine.to_native(); let from_native = i915::EngineInfo::from_native(native_engine); assert_eq!(&engine, &from_native); } } } // TODO #[test] fn test_i915_uapi_find_fd() { let fd = i915::find_fd().expect("Failed to find i915 fd"); let drm_version = uapi::get_drm_version(fd.as_raw_fd()).expect("Failed to get drm version"); assert_eq!(drm_version.name.to_str().unwrap(), "i915"); assert_eq!(drm_version.desc.to_str().unwrap(), "Intel Graphics"); } #[test] fn test_i915_uapi_get_context_param() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { // Mesa uses context id of 0 for init so it's surely okay, right? let param = i915::get_context_param(node.fd.as_raw_fd(), 0, native::I915_CONTEXT_PARAM_GTT_SIZE as u32) .expect("Failed to get context param"); assert!(param > 0); } } #[test] fn test_i915_uapi_gem_lifecycle() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let gem = i915::make_gem(node.fd.as_raw_fd(), 4096).expect("Failed to make gem"); assert!(gem.handle > 0); assert!(i915::gem_is_valid(node.fd.as_raw_fd(), &gem).unwrap()); let tmp = i915::DrmGemHandle { handle: gem.handle }; i915::close_gem(node.fd.as_raw_fd(), tmp).expect("Failed to close gem"); assert!(!i915::gem_is_valid(node.fd.as_raw_fd(), &gem).unwrap()); let invalid_fd = File::open("/dev/null").expect("Failed to open /dev/null"); assert!(i915::make_gem(invalid_fd.as_raw_fd(), 4096).is_none()); } } #[test] fn test_i915_uapi_gem_tiling() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let gem = i915::make_gem(node.fd.as_raw_fd(), 4096).expect("Failed to make gem"); // TODO figure out which devices this holds for let tiling = i915::gem_get_tiling(node.fd.as_raw_fd(), &gem); if tiling.is_err() { // Unsupported on DG continue; } assert!(i915::gem_has_tiling(node.fd.as_raw_fd(), &gem).is_ok_and(|e| e == true)); i915::close_gem(node.fd.as_raw_fd(), gem).expect("Failed to close gem"); } } #[test] fn test_i915_uapi_gem_caching() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let gem = i915::make_gem(node.fd.as_raw_fd(), 4096).expect("Failed to make gem"); let caching = i915::gem_get_caching(node.fd.as_raw_fd(), &gem); if caching.is_err() { // Unsupported on DG continue; } let caching = caching.unwrap(); assert!(caching > 0); i915::close_gem(node.fd.as_raw_fd(), gem).expect("Failed to close gem"); } } #[test] fn test_i915_uapi_gem_thread() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let gem = i915::make_gem(node.fd.as_raw_fd(), 4096).expect("Failed to make gem"); thread::scope(|s| { let handle = s.spawn(|| { assert!(i915::gem_is_valid(node.fd.as_raw_fd(), &gem).unwrap()); }); assert!(i915::gem_is_valid(node.fd.as_raw_fd(), &gem).unwrap()); handle.join().expect("Failed to join thread"); }); } } #[test] fn test_i915_uapi_gem_fork_parent() { let nodes = i915::find_all_nodes(); assert!(nodes.len() > 0); for node in nodes { let gem = i915::make_gem(node.fd.as_raw_fd(), 4096).expect("Failed to make gem"); let pid = unsafe { libc::fork() }; if pid == 0 { if i915::gem_is_valid(node.fd.as_raw_fd(), &gem).unwrap() { std::process::exit(0); } else { std::process::exit(-1); } } else { assert!(i915::gem_is_valid(node.fd.as_raw_fd(), &gem).unwrap()); let mut status = 0; unsafe { libc::waitpid(pid, &mut status, 0) }; assert_eq!(status, 0); } } } // TODO: Fix this test // Shared mem needs to be used to communicate the gem handle between parent and child // Test both a shared fd and separate fd // #[test] // fn test_i915_uapi_gem_fork_child() { // let pid = unsafe { libc::fork() }; // if pid == 0 { // let node = i915::find_node().expect("Failed to find i915 fd"); // let gem = i915::make_gem(node.fd.as_raw_fd(), 4096).expect("Failed to make gem"); // if i915::gem_is_valid(node.fd.as_raw_fd(), &gem).unwrap() { // println!("handle 1: {}", gem.handle); // std::process::exit(gem.handle as i32); // } else { // std::process::exit(-1); // } // } else { // let node = i915::find_node().expect("Failed to find i915 fd"); // let mut status = 0; // unsafe { libc::waitpid(pid, &mut status, 0) }; // assert!(i915::gem_is_valid(node.fd.as_raw_fd(), &DrmGemHandle {handle: 1}).unwrap()); // } // }