1 use crate::pipe::screen::*;
2
3 use mesa_rust_gen::*;
4 use mesa_rust_util::ptr::ThreadSafeCPtr;
5 use mesa_rust_util::string::c_string_to_string;
6
7 use std::collections::HashMap;
8 use std::ffi::CStr;
9 use std::{env, ptr};
10
11 #[derive(PartialEq)]
12 pub(super) struct PipeLoaderDevice {
13 ldev: ThreadSafeCPtr<pipe_loader_device>,
14 }
15
16 impl PipeLoaderDevice {
new(ldev: *mut pipe_loader_device) -> Option<Self>17 fn new(ldev: *mut pipe_loader_device) -> Option<Self> {
18 Some(Self {
19 // SAFETY: `pipe_loader_device` is considered to be thread-safe
20 ldev: unsafe { ThreadSafeCPtr::new(ldev)? },
21 })
22 }
23
load_screen(self) -> Option<PipeScreen>24 fn load_screen(self) -> Option<PipeScreen> {
25 let s = unsafe { pipe_loader_create_screen(self.ldev.as_ptr(), false) };
26 PipeScreen::new(self, s)
27 }
28
driver_name(&self) -> &CStr29 pub fn driver_name(&self) -> &CStr {
30 // SAFETY: ldev is a valid memory allocation
31 let ldev = unsafe { self.ldev.as_ref() };
32
33 // SAFETY: The driver name is a valid C string pointer
34 unsafe { CStr::from_ptr(ldev.driver_name) }
35 }
36
device_type(&self) -> pipe_loader_device_type37 pub fn device_type(&self) -> pipe_loader_device_type {
38 unsafe { self.ldev.as_ref().type_ }
39 }
40 }
41
42 impl Drop for PipeLoaderDevice {
drop(&mut self)43 fn drop(&mut self) {
44 unsafe {
45 pipe_loader_release(&mut self.ldev.as_ptr(), 1);
46 }
47 }
48 }
49
load_devs() -> impl Iterator<Item = PipeLoaderDevice>50 fn load_devs() -> impl Iterator<Item = PipeLoaderDevice> {
51 let n = unsafe { pipe_loader_probe(ptr::null_mut(), 0, true) };
52 let mut devices: Vec<*mut pipe_loader_device> = vec![ptr::null_mut(); n as usize];
53 unsafe {
54 pipe_loader_probe(devices.as_mut_ptr(), n, true);
55 }
56
57 devices.into_iter().filter_map(PipeLoaderDevice::new)
58 }
59
get_enabled_devs() -> HashMap<String, u32>60 fn get_enabled_devs() -> HashMap<String, u32> {
61 let mut res = HashMap::new();
62
63 // we require the type here as this list can be empty depending on the build options
64 let default_devs: &[&str] = &[
65 #[cfg(any(rusticl_enable_asahi, rusticl_enable_auto))]
66 "asahi",
67 ];
68
69 // I wished we could use different iterators, but that's not really working out.
70 let enabled_devs = env::var("RUSTICL_ENABLE").unwrap_or(default_devs.join(","));
71 let mut last_driver = None;
72 for driver_str in enabled_devs.split(',') {
73 if driver_str.is_empty() {
74 continue;
75 }
76
77 // if the string parses to a number, just updated the device bitset
78 if let Ok(dev_id) = driver_str.parse::<u8>() {
79 if let Some(last_driver) = last_driver {
80 *res.get_mut(last_driver).unwrap() |= 1 << dev_id;
81 }
82 continue;
83 } else {
84 let driver_str: Vec<_> = driver_str.split(':').collect();
85 let mut devices = 0;
86
87 if driver_str.len() == 1 {
88 devices = !0;
89 } else if let Ok(dev_id) = driver_str[1].parse::<u8>() {
90 devices |= 1 << dev_id;
91 }
92
93 let driver_str = match driver_str[0] {
94 "llvmpipe" | "lp" => "swrast",
95 "freedreno" => "msm",
96 a => a,
97 };
98
99 res.insert(driver_str.to_owned(), devices);
100 last_driver = Some(driver_str);
101 }
102 }
103
104 if res.contains_key("panfrost") {
105 res.insert("panthor".to_owned(), res["panfrost"]);
106 }
107
108 res
109 }
110
load_screens() -> impl Iterator<Item = PipeScreen>111 pub fn load_screens() -> impl Iterator<Item = PipeScreen> {
112 let devs = load_devs();
113 let mut enabled_devs = get_enabled_devs();
114
115 devs.filter(move |dev| {
116 let driver_name = unsafe { c_string_to_string(dev.ldev.as_ref().driver_name) };
117
118 if let Some(enabled_devs) = enabled_devs.get_mut(&driver_name) {
119 let res = (*enabled_devs & 1) == 1;
120 *enabled_devs >>= 1;
121
122 res
123 } else {
124 false
125 }
126 })
127 .filter_map(PipeLoaderDevice::load_screen)
128 }
129