Skip to main content

wallr_core/video/
gpu.rs

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()) {
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        .into_iter()
61        .map(|adapter| {
62            let info = adapter.get_info();
63            (
64                adapter,
65                AdapterInfo {
66                    name: info.name,
67                    backend: info.backend,
68                    device_type: info.device_type,
69                    driver: info.driver,
70                    driver_info: info.driver_info,
71                },
72            )
73        })
74        .collect();
75    if adapters.is_empty() {
76        return Err(VideoError::AdapterNotFound(
77            "No GPU adapters detected".to_string(),
78        ));
79    }
80
81    let selected = match preference {
82        GpuSelection::Auto => adapters
83            .iter()
84            .find(|(_, info)| info.is_integrated())
85            .or_else(|| adapters.first()),
86        GpuSelection::Integrated => adapters.iter().find(|(_, info)| info.is_integrated()),
87        GpuSelection::Discrete => adapters.iter().find(|(_, info)| info.is_discrete()),
88        GpuSelection::Named(name) => {
89            let requested = name.to_ascii_lowercase();
90            adapters
91                .iter()
92                .find(|(_, info)| info.name.to_ascii_lowercase().contains(&requested))
93        }
94    };
95
96    let selected = selected.ok_or_else(|| {
97        VideoError::AdapterNotFound(format!("No adapter matching preference: {}", preference))
98    })?;
99
100    tracing::info!("Selected GPU adapter: {}", selected.1);
101    Ok(selected.0.clone())
102}
103
104pub fn adapter_diagnostics(adapter: &wgpu::Adapter) -> String {
105    let info = adapter.get_info();
106    format!(
107        "GPU: {} ({:?})\nBackend: {:?}\nDriver: {}\nDriver Info: {}",
108        info.name, info.device_type, info.backend, info.driver, info.driver_info
109    )
110}