1use crate::video::error::{VideoError, VideoResult};
2use std::fmt;
3
4pub use wallr_common::types::GpuSelection;
5
6#[derive(Debug, Clone)]
7pub struct AdapterInfo {
8 pub name: String,
9 pub backend: wgpu::Backend,
10 pub device_type: wgpu::DeviceType,
11 pub driver: String,
12 pub driver_info: String,
13}
14
15impl AdapterInfo {
16 pub fn is_integrated(&self) -> bool {
17 self.device_type == wgpu::DeviceType::IntegratedGpu
18 }
19
20 pub fn is_discrete(&self) -> bool {
21 self.device_type == wgpu::DeviceType::DiscreteGpu
22 }
23}
24
25impl fmt::Display for AdapterInfo {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 write!(
28 f,
29 "{} ({:?}, {:?}) - {}",
30 self.name, self.device_type, self.backend, self.driver
31 )
32 }
33}
34
35pub async fn detect_adapters(instance: &wgpu::Instance) -> Vec<AdapterInfo> {
36 let mut adapters = Vec::new();
37 for adapter in instance.enumerate_adapters(wgpu::Backends::all()).await {
38 let info = adapter.get_info();
39 adapters.push(AdapterInfo {
40 name: info.name.clone(),
41 backend: info.backend,
42 device_type: info.device_type,
43 driver: info.driver.clone(),
44 driver_info: info.driver_info.clone(),
45 });
46 }
47 tracing::info!("Detected {} GPU adapter(s)", adapters.len());
48 for (i, a) in adapters.iter().enumerate() {
49 tracing::info!(" [{}] {}", i, a);
50 }
51 adapters
52}
53
54pub async fn select_adapter(
55 instance: &wgpu::Instance,
56 preference: &GpuSelection,
57) -> VideoResult<wgpu::Adapter> {
58 let adapters: Vec<_> = instance
59 .enumerate_adapters(wgpu::Backends::all())
60 .await
61 .into_iter()
62 .map(|adapter| {
63 let info = adapter.get_info();
64 (
65 adapter,
66 AdapterInfo {
67 name: info.name,
68 backend: info.backend,
69 device_type: info.device_type,
70 driver: info.driver,
71 driver_info: info.driver_info,
72 },
73 )
74 })
75 .collect();
76 if adapters.is_empty() {
77 return Err(VideoError::AdapterNotFound(
78 "No GPU adapters detected".to_string(),
79 ));
80 }
81
82 let selected = match preference {
83 GpuSelection::Auto => adapters
84 .iter()
85 .find(|(_, info)| info.is_integrated())
86 .or_else(|| adapters.first()),
87 GpuSelection::Integrated => adapters.iter().find(|(_, info)| info.is_integrated()),
88 GpuSelection::Discrete => adapters.iter().find(|(_, info)| info.is_discrete()),
89 GpuSelection::Named(name) => {
90 let requested = name.to_ascii_lowercase();
91 adapters
92 .iter()
93 .find(|(_, info)| info.name.to_ascii_lowercase().contains(&requested))
94 }
95 };
96
97 let selected = selected.ok_or_else(|| {
98 VideoError::AdapterNotFound(format!("No adapter matching preference: {}", preference))
99 })?;
100
101 tracing::info!("Selected GPU adapter: {}", selected.1);
102 Ok(selected.0.clone())
103}
104
105pub fn adapter_diagnostics(adapter: &wgpu::Adapter) -> String {
106 let info = adapter.get_info();
107 format!(
108 "GPU: {} ({:?})\nBackend: {:?}\nDriver: {}\nDriver Info: {}",
109 info.name, info.device_type, info.backend, info.driver, info.driver_info
110 )
111}