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()).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}