Skip to main content

tl_gpu/
device.rs

1// GpuDevice — singleton device manager for wgpu
2
3use std::sync::{Arc, OnceLock};
4use wgpu;
5
6/// A handle to a GPU device and its command queue.
7pub struct GpuDevice {
8    pub device: wgpu::Device,
9    pub queue: wgpu::Queue,
10    pub adapter_name: String,
11    pub backend: String,
12}
13
14static GPU_DEVICE: OnceLock<Option<Arc<GpuDevice>>> = OnceLock::new();
15
16impl GpuDevice {
17    /// Get or lazily initialize the GPU device singleton.
18    /// Returns None if no GPU is available.
19    pub fn get() -> Option<Arc<GpuDevice>> {
20        GPU_DEVICE.get_or_init(|| Self::init_device()).clone()
21    }
22
23    /// Check if a GPU device is available without full initialization.
24    pub fn is_available() -> bool {
25        Self::get().is_some()
26    }
27
28    fn init_device() -> Option<Arc<GpuDevice>> {
29        let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
30            backends: wgpu::Backends::all(),
31            ..Default::default()
32        });
33
34        let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
35            power_preference: wgpu::PowerPreference::HighPerformance,
36            compatible_surface: None,
37            force_fallback_adapter: false,
38        }))?;
39
40        let adapter_name = adapter.get_info().name.clone();
41        let backend = format!("{:?}", adapter.get_info().backend);
42
43        let (device, queue) = pollster::block_on(adapter.request_device(
44            &wgpu::DeviceDescriptor {
45                label: Some("tl-gpu"),
46                required_features: wgpu::Features::empty(),
47                required_limits: wgpu::Limits::default(),
48                ..Default::default()
49            },
50            None,
51        ))
52        .ok()?;
53
54        Some(Arc::new(GpuDevice {
55            device,
56            queue,
57            adapter_name,
58            backend,
59        }))
60    }
61}
62
63impl std::fmt::Debug for GpuDevice {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        write!(f, "GpuDevice({}, {})", self.adapter_name, self.backend)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_gpu_available() {
75        // Should not panic regardless of GPU availability
76        let _available = GpuDevice::is_available();
77    }
78}