#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
use super::backends::{enumerate_wgpu_devices, query_wgpu_device_info};
#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
use super::MonitorError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GpuVendor {
Nvidia,
Amd,
Intel,
Apple,
Unknown(u32),
}
impl GpuVendor {
#[must_use]
pub const fn from_vendor_id(id: u32) -> Self {
match id {
0x10de => Self::Nvidia,
0x1002 => Self::Amd,
0x8086 => Self::Intel,
0x106b => Self::Apple,
other => Self::Unknown(other),
}
}
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Nvidia => "NVIDIA",
Self::Amd => "AMD",
Self::Intel => "Intel",
Self::Apple => "Apple",
Self::Unknown(_) => "Unknown",
}
}
#[must_use]
pub const fn is_nvidia(&self) -> bool {
matches!(self, Self::Nvidia)
}
}
impl std::fmt::Display for GpuVendor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Unknown(id) => write!(f, "Unknown (0x{id:04x})"),
Self::Nvidia | Self::Amd | Self::Intel | Self::Apple => write!(f, "{}", self.name()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GpuBackend {
Vulkan,
Metal,
Dx12,
Dx11,
WebGpu,
Cuda,
OpenGl,
Cpu,
}
impl GpuBackend {
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Vulkan => "Vulkan",
Self::Metal => "Metal",
Self::Dx12 => "DirectX 12",
Self::Dx11 => "DirectX 11",
Self::WebGpu => "WebGPU",
Self::Cuda => "CUDA",
Self::OpenGl => "OpenGL",
Self::Cpu => "CPU",
}
}
#[must_use]
pub const fn is_gpu(&self) -> bool {
!matches!(self, Self::Cpu)
}
#[must_use]
pub const fn supports_compute(&self) -> bool {
matches!(self, Self::Vulkan | Self::Metal | Self::Dx12 | Self::WebGpu | Self::Cuda)
}
}
impl std::fmt::Display for GpuBackend {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
#[derive(Debug, Clone)]
pub struct GpuDeviceInfo {
pub index: u32,
pub name: String,
pub vendor: GpuVendor,
pub vram_total: u64,
pub compute_capability: Option<(u32, u32)>,
pub driver_version: Option<String>,
pub pci_bus_id: Option<String>,
pub backend: GpuBackend,
}
impl GpuDeviceInfo {
#[must_use]
pub fn new(
index: u32,
name: impl Into<String>,
vendor: GpuVendor,
backend: GpuBackend,
) -> Self {
Self {
index,
name: name.into(),
vendor,
vram_total: 0,
compute_capability: None,
driver_version: None,
pci_bus_id: None,
backend,
}
}
#[must_use]
pub fn with_vram(mut self, bytes: u64) -> Self {
self.vram_total = bytes;
self
}
#[must_use]
pub fn with_compute_capability(mut self, major: u32, minor: u32) -> Self {
self.compute_capability = Some((major, minor));
self
}
#[must_use]
pub fn with_driver_version(mut self, version: impl Into<String>) -> Self {
self.driver_version = Some(version.into());
self
}
#[must_use]
pub fn with_pci_bus_id(mut self, bus_id: impl Into<String>) -> Self {
self.pci_bus_id = Some(bus_id.into());
self
}
#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
pub fn query() -> Result<Self, MonitorError> {
query_wgpu_device_info(0)
}
#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
pub fn query_device(index: u32) -> Result<Self, MonitorError> {
query_wgpu_device_info(index)
}
#[cfg(all(feature = "gpu", not(target_arch = "wasm32")))]
pub fn enumerate() -> Result<Vec<Self>, MonitorError> {
enumerate_wgpu_devices()
}
#[must_use]
pub fn vram_mb(&self) -> u64 {
self.vram_total / (1024 * 1024)
}
#[must_use]
pub fn vram_gb(&self) -> f64 {
self.vram_total as f64 / (1024.0 * 1024.0 * 1024.0)
}
#[must_use]
pub fn supports_cuda(&self) -> bool {
self.vendor.is_nvidia()
}
}
impl std::fmt::Display for GpuDeviceInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[{}] {} ({}) - {:.1} GB VRAM",
self.index,
self.name,
self.backend,
self.vram_gb()
)
}
}