• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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