Skip to main content

trueno/monitor/
types.rs

1//! GPU vendor, backend, and device info types (TRUENO-SPEC-010 Section 3)
2
3#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
4use super::backends::{enumerate_wgpu_devices, query_wgpu_device_info};
5#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
6use super::MonitorError;
7
8// ============================================================================
9// GPU Vendor Identification (TRUENO-SPEC-010 Section 3.2)
10// ============================================================================
11
12/// GPU vendor identifier based on PCI vendor ID
13///
14/// Vendor IDs from PCI-SIG registry:
15/// - NVIDIA: 0x10de
16/// - AMD: 0x1002
17/// - Intel: 0x8086
18/// - Apple: 0x106b
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum GpuVendor {
21    /// NVIDIA Corporation (0x10de)
22    Nvidia,
23    /// Advanced Micro Devices (0x1002)
24    Amd,
25    /// Intel Corporation (0x8086)
26    Intel,
27    /// Apple Inc. (0x106b)
28    Apple,
29    /// Unknown vendor with raw PCI vendor ID
30    Unknown(u32),
31}
32
33impl GpuVendor {
34    /// Create vendor from PCI vendor ID
35    #[must_use]
36    pub const fn from_vendor_id(id: u32) -> Self {
37        match id {
38            0x10de => Self::Nvidia,
39            0x1002 => Self::Amd,
40            0x8086 => Self::Intel,
41            0x106b => Self::Apple,
42            other => Self::Unknown(other),
43        }
44    }
45
46    /// Get the display name for the vendor
47    #[must_use]
48    pub const fn name(&self) -> &'static str {
49        match self {
50            Self::Nvidia => "NVIDIA",
51            Self::Amd => "AMD",
52            Self::Intel => "Intel",
53            Self::Apple => "Apple",
54            Self::Unknown(_) => "Unknown",
55        }
56    }
57
58    /// Check if this is an NVIDIA GPU (supports CUDA)
59    #[must_use]
60    pub const fn is_nvidia(&self) -> bool {
61        matches!(self, Self::Nvidia)
62    }
63}
64
65impl std::fmt::Display for GpuVendor {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        match self {
68            Self::Unknown(id) => write!(f, "Unknown (0x{id:04x})"),
69            Self::Nvidia | Self::Amd | Self::Intel | Self::Apple => write!(f, "{}", self.name()),
70        }
71    }
72}
73
74// ============================================================================
75// GPU Backend Selection (TRUENO-SPEC-010 Section 3.2)
76// ============================================================================
77
78/// GPU compute backend
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
80pub enum GpuBackend {
81    /// Vulkan (Linux, Windows, Android)
82    Vulkan,
83    /// Metal (macOS, iOS)
84    Metal,
85    /// DirectX 12 (Windows)
86    Dx12,
87    /// DirectX 11 (Windows, fallback)
88    Dx11,
89    /// WebGPU (WASM browser)
90    WebGpu,
91    /// Native CUDA (NVIDIA only, via trueno-gpu)
92    Cuda,
93    /// OpenGL (fallback)
94    OpenGl,
95    /// CPU fallback (no GPU)
96    Cpu,
97}
98
99impl GpuBackend {
100    /// Get the display name for the backend
101    #[must_use]
102    pub const fn name(&self) -> &'static str {
103        match self {
104            Self::Vulkan => "Vulkan",
105            Self::Metal => "Metal",
106            Self::Dx12 => "DirectX 12",
107            Self::Dx11 => "DirectX 11",
108            Self::WebGpu => "WebGPU",
109            Self::Cuda => "CUDA",
110            Self::OpenGl => "OpenGL",
111            Self::Cpu => "CPU",
112        }
113    }
114
115    /// Check if this is a GPU backend (not CPU fallback)
116    #[must_use]
117    pub const fn is_gpu(&self) -> bool {
118        !matches!(self, Self::Cpu)
119    }
120
121    /// Check if this backend supports compute shaders
122    #[must_use]
123    pub const fn supports_compute(&self) -> bool {
124        matches!(self, Self::Vulkan | Self::Metal | Self::Dx12 | Self::WebGpu | Self::Cuda)
125    }
126}
127
128impl std::fmt::Display for GpuBackend {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        write!(f, "{}", self.name())
131    }
132}
133
134// ============================================================================
135// GPU Device Information (TRUENO-SPEC-010 Section 3.1)
136// ============================================================================
137
138/// GPU device information (TRUENO-SPEC-010)
139///
140/// Contains static device properties that don't change during runtime.
141#[derive(Debug, Clone)]
142pub struct GpuDeviceInfo {
143    /// Device index (0-based)
144    pub index: u32,
145    /// Device name (e.g., "NVIDIA GeForce RTX 4090")
146    pub name: String,
147    /// Vendor identifier
148    pub vendor: GpuVendor,
149    /// Total VRAM in bytes
150    pub vram_total: u64,
151    /// Compute capability (NVIDIA) or architecture info as (major, minor)
152    pub compute_capability: Option<(u32, u32)>,
153    /// Driver version string
154    pub driver_version: Option<String>,
155    /// PCI bus ID (e.g., "0000:01:00.0")
156    pub pci_bus_id: Option<String>,
157    /// wgpu/CUDA backend being used
158    pub backend: GpuBackend,
159}
160
161impl GpuDeviceInfo {
162    /// Create a new device info with required fields
163    #[must_use]
164    pub fn new(
165        index: u32,
166        name: impl Into<String>,
167        vendor: GpuVendor,
168        backend: GpuBackend,
169    ) -> Self {
170        Self {
171            index,
172            name: name.into(),
173            vendor,
174            vram_total: 0,
175            compute_capability: None,
176            driver_version: None,
177            pci_bus_id: None,
178            backend,
179        }
180    }
181
182    /// Set VRAM total
183    #[must_use]
184    pub fn with_vram(mut self, bytes: u64) -> Self {
185        self.vram_total = bytes;
186        self
187    }
188
189    /// Set compute capability
190    #[must_use]
191    pub fn with_compute_capability(mut self, major: u32, minor: u32) -> Self {
192        self.compute_capability = Some((major, minor));
193        self
194    }
195
196    /// Set driver version
197    #[must_use]
198    pub fn with_driver_version(mut self, version: impl Into<String>) -> Self {
199        self.driver_version = Some(version.into());
200        self
201    }
202
203    /// Set PCI bus ID
204    #[must_use]
205    pub fn with_pci_bus_id(mut self, bus_id: impl Into<String>) -> Self {
206        self.pci_bus_id = Some(bus_id.into());
207        self
208    }
209
210    /// Query device info via wgpu (cross-platform, native only)
211    ///
212    /// On WASM, use async methods with `wasm_bindgen_futures`.
213    ///
214    /// # Errors
215    ///
216    /// Returns error if no GPU is available or query fails.
217    #[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
218    pub fn query() -> Result<Self, MonitorError> {
219        query_wgpu_device_info(0)
220    }
221
222    /// Query device info via wgpu for a specific device index (native only)
223    ///
224    /// On WASM, use async methods with `wasm_bindgen_futures`.
225    ///
226    /// # Errors
227    ///
228    /// Returns error if device index is invalid or query fails.
229    #[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
230    pub fn query_device(index: u32) -> Result<Self, MonitorError> {
231        query_wgpu_device_info(index)
232    }
233
234    /// Enumerate all available GPU devices (native only)
235    ///
236    /// On WASM, use async methods with `wasm_bindgen_futures`.
237    ///
238    /// # Errors
239    ///
240    /// Returns error if enumeration fails.
241    #[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
242    pub fn enumerate() -> Result<Vec<Self>, MonitorError> {
243        enumerate_wgpu_devices()
244    }
245
246    /// Get VRAM in megabytes (convenience method)
247    #[must_use]
248    pub fn vram_mb(&self) -> u64 {
249        self.vram_total / (1024 * 1024)
250    }
251
252    /// Get VRAM in gigabytes (convenience method)
253    #[must_use]
254    pub fn vram_gb(&self) -> f64 {
255        self.vram_total as f64 / (1024.0 * 1024.0 * 1024.0)
256    }
257
258    /// Check if device supports CUDA (is NVIDIA)
259    #[must_use]
260    pub fn supports_cuda(&self) -> bool {
261        self.vendor.is_nvidia()
262    }
263}
264
265impl std::fmt::Display for GpuDeviceInfo {
266    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267        write!(
268            f,
269            "[{}] {} ({}) - {:.1} GB VRAM",
270            self.index,
271            self.name,
272            self.backend,
273            self.vram_gb()
274        )
275    }
276}