diff --git a/crates/cardwire-cli/src/main.rs b/crates/cardwire-cli/src/main.rs index 29f985a7..8018c31a 100644 --- a/crates/cardwire-cli/src/main.rs +++ b/crates/cardwire-cli/src/main.rs @@ -2,6 +2,7 @@ mod args; mod completion; mod dbus; mod display; +mod types; use std::{collections::BTreeMap, process::Stdio}; @@ -9,7 +10,7 @@ use args::{Args, CliMode, Commands, ConfigAction, DebugAction, ManagerAction}; use clap::{CommandFactory, Parser}; use dbus::DaemonClient; -use crate::display::print_devices_pci; +use crate::{display::print_devices_pci, types::SystemType}; const BIN_NAME: &str = "cardwire"; @@ -299,18 +300,28 @@ async fn main() -> anyhow::Result<()> { )); } target + // No gpu specified } else { - let mut candidates: Vec<(&usize, &display::GpuDevice)> = - available_gpu.iter().collect(); - candidates.sort_by_key(|(_, gpu)| match (gpu.default, gpu.discrete) { - (false, true) => 0, - (_, true) => 1, - (true, _) => 2, - _ => 3, - }); - candidates - .into_iter() - .find_map(|(_, gpu)| gpu.launchable.then_some(gpu)) + available_gpu.retain(|_, gpu| gpu.available && gpu.launchable); + let system_type = SystemType::from_gpulist(&available_gpu); + match system_type { + // 2 GPUs, one iGPU and one dGPU + SystemType::Laptop => available_gpu + .iter() + .find(|(_, gpu)| !gpu.default && gpu.discrete), + // 2 GPUs, use default discrete GPU + SystemType::Desktop => available_gpu + .iter() + .find(|(_, gpu)| gpu.default && gpu.discrete), + // 1 GPU or 3+ GPUs, get in this priority: + // 0. Default Discrete GPU + // 1. non-Default discrete GPU + // 2. Others + SystemType::Manual => available_gpu.iter().max_by_key(|(_, gpu)| { + (gpu.default && gpu.discrete, gpu.discrete, gpu.default) + }), + } + .map(|(_, gpu)| gpu) }; if let Some(gpu) = target_gpu { diff --git a/crates/cardwire-cli/src/types.rs b/crates/cardwire-cli/src/types.rs new file mode 100644 index 00000000..c1dcc27d --- /dev/null +++ b/crates/cardwire-cli/src/types.rs @@ -0,0 +1,44 @@ +use std::collections::BTreeMap; + +use crate::display::GpuDevice; + +#[derive(Clone, Debug, PartialEq)] +pub enum SystemType { + Laptop, + Desktop, + Manual, +} +impl SystemType { + pub fn from_gpulist(gpu_list: &BTreeMap) -> Self { + let available_gpus: Vec<(usize, bool, bool)> = gpu_list + .iter() + .filter(|(_, gpu)| gpu.available) + .map(|(id, gpu)| (*id, gpu.default, gpu.discrete)) + .collect(); + + if available_gpus.len() != 2 { + Self::Manual + } else if available_gpus + .iter() + .any(|(_, default, discrete)| *default && *discrete) + && available_gpus + .iter() + .any(|(_, default, discrete)| !*discrete && !*default) + { + // Has a default discrete GPU and a non-default non-discrete GPU + Self::Desktop + } else if available_gpus + .iter() + .any(|(_, default, discrete)| *discrete && !*default) + && available_gpus + .iter() + .any(|(_, default, discrete)| !*discrete && *default) + { + // Has a non-default discrete GPU and a default non-discrete GPU + Self::Laptop + } else { + // Even if it's a desktop, we treat it as a Manual if it doesn't have the iGPU + Self::Manual + } + } +}