1use crate::squire;
2use serde_json::Value;
3use std::collections::HashMap;
4
5fn get_gpu_info_darwin(lib_path: &str) -> Vec<HashMap<String, String>> {
15 let result: Result<String, String> = squire::util::run_command(
16 lib_path,
17 &["SPDisplaysDataType", "-json"],
18 true,
19 );
20 let displays: Vec<Value>;
21 match result {
22 Ok(json_str) => {
23 match serde_json::from_str::<Value>(&json_str) {
24 Ok(json) => {
25 if let Some(d) = json.get("SPDisplaysDataType").and_then(Value::as_array) {
26 displays = d.to_vec();
27 } else {
28 log::error!("Key 'SPDisplaysDataType' not found or is not an array.");
29 return Vec::new();
30 }
31 }
32 Err(err) => {
33 log::error!("Failed to parse JSON: {}", err);
34 return Vec::new();
35 }
36 }
37 }
38 Err(err) => {
39 log::error!("Error retrieving result: {}", err);
40 return Vec::new();
41 }
42 }
43 let mut gpu_info = Vec::new();
44 let na = "N/A".to_string();
45 for display in displays {
46 if let Some(model) = display.get("sppci_model") {
47 let mut info = HashMap::new();
48 info.insert(
49 "model".to_string(),
50 model.as_str()
51 .unwrap_or(na.as_str())
52 .to_string(),
53 );
54
55 info.insert(
57 "cores".to_string(),
58 display.get("sppci_cores")
59 .or(display.get("spdisplays_cores"))
60 .and_then(|v| v.as_str())
61 .unwrap_or(&na)
62 .to_string(),
63 );
64
65 info.insert(
67 "memory".to_string(),
68 display.get("sppci_vram")
69 .or(display.get("spdisplays_vram"))
70 .and_then(|v| v.as_str())
71 .unwrap_or(&na)
72 .to_string(),
73 );
74
75 info.insert(
77 "vendor".to_string(),
78 display.get("sppci_vendor")
79 .and_then(|v| v.as_str())
80 .unwrap_or(&na)
81 .to_string(),
82 );
83 gpu_info.push(info);
84 }
85 }
86 gpu_info
87}
88
89fn get_gpu_info_linux(lib_path: &str) -> Vec<HashMap<String, String>> {
99 let result = squire::util::run_command(
100 lib_path,
101 &[],
102 true,
103 );
104 let output = match result {
105 Ok(output) => output,
106 Err(_) => return Vec::new(),
107 };
108 let mut gpu_info = Vec::new();
109 for line in output.lines() {
110 if line.contains("VGA") {
111 let gpu = line.split(':').last().unwrap().trim();
112 let mut info = HashMap::new();
113 info.insert("model".to_string(), gpu.to_string());
114 gpu_info.push(info);
115 }
116 }
117 gpu_info
118}
119
120fn get_gpu_info_windows(lib_path: &str) -> Vec<HashMap<String, String>> {
130 let result = squire::util::run_command(
131 lib_path,
132 &["path", "win32_videocontroller", "get", "Name,AdapterCompatibility", "/format:csv"],
133 true,
134 );
135 let output = match result {
136 Ok(output) => output.to_uppercase(),
137 Err(_) => {
138 return Vec::new();
139 }
140 };
141 let gpus_raw: Vec<&str> = output.lines().filter(|line| !line.trim().is_empty()).collect();
142 if gpus_raw.is_empty() {
143 log::info!("No GPUs found!");
144 return vec![];
145 }
146
147 let keys: Vec<String> = gpus_raw[0]
148 .trim()
149 .to_lowercase()
150 .replace("adaptercompatibility", "vendor")
151 .replace("name", "model")
152 .split(',')
153 .map(|key| key.to_string())
154 .collect();
155
156 let binding = gpus_raw[1..].join("");
157 let values: Vec<&str> = binding.trim().split(",").collect();
158 let mut gpu_info = Vec::new();
159 let key_len = keys.len();
160 for chunk in values.chunks(key_len) {
161 let mut map = HashMap::new();
162 for (key, value) in keys.iter().zip(chunk) {
163 map.insert(key.to_string(), value.to_string());
164 }
165 gpu_info.push(map);
166 }
167 gpu_info
168}
169
170pub fn get_gpu_info() -> Vec<HashMap<String, String>> {
176 let operating_system = std::env::consts::OS;
177 match operating_system {
178 "macos" => get_gpu_info_darwin("/usr/sbin/system_profiler"),
179 "linux" => get_gpu_info_linux("/usr/bin/lspci"),
180 "windows" => get_gpu_info_windows("C:\\Windows\\System32\\wbem\\wmic.exe"),
181 _ => {
182 log::error!("Unsupported operating system: {}", operating_system);
183 Vec::new()
184 }
185 }
186}