use crate::{capability::CapabilityFlags, device::DeviceDescriptor, error::Result};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum BackendKind {
Cuda,
Rocm,
Metal,
QualcommNpu,
Cpu,
Vulkan,
OpenGl,
Dx12,
WebGpu,
Tpu,
LevelZero,
Neuron,
}
impl BackendKind {
pub const ALL: &'static [BackendKind] = &[
BackendKind::Cuda,
BackendKind::Rocm,
BackendKind::Metal,
BackendKind::QualcommNpu,
BackendKind::Cpu,
BackendKind::Vulkan,
BackendKind::OpenGl,
BackendKind::Dx12,
BackendKind::WebGpu,
BackendKind::Tpu,
BackendKind::LevelZero,
BackendKind::Neuron,
];
pub const fn name(self) -> &'static str {
match self {
BackendKind::Cuda => "cuda",
BackendKind::Rocm => "rocm",
BackendKind::Metal => "metal",
BackendKind::QualcommNpu => "qnn",
BackendKind::Cpu => "cpu",
BackendKind::Vulkan => "vulkan",
BackendKind::OpenGl => "opengl",
BackendKind::Dx12 => "dx12",
BackendKind::WebGpu => "webgpu",
BackendKind::Tpu => "tpu",
BackendKind::LevelZero => "level-zero",
BackendKind::Neuron => "neuron",
}
}
}
pub trait Backend: Send + Sync + 'static {
fn kind(&self) -> BackendKind;
fn is_available(&self) -> bool;
fn enumerate(&self) -> Result<Vec<DeviceDescriptor>>;
fn capabilities(&self, device: u32) -> Result<CapabilityFlags>;
}
pub struct BackendRegistry {
entries: Vec<&'static dyn Backend>,
}
impl BackendRegistry {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn register(&mut self, backend: &'static dyn Backend) {
if !self.entries.iter().any(|b| b.kind() == backend.kind()) {
self.entries.push(backend);
}
}
pub fn get(&self, kind: BackendKind) -> Option<&'static dyn Backend> {
self.entries.iter().copied().find(|b| b.kind() == kind)
}
pub fn iter(&self) -> impl Iterator<Item = &'static dyn Backend> + '_ {
self.entries.iter().copied()
}
pub fn available(&self) -> impl Iterator<Item = &'static dyn Backend> + '_ {
self.iter().filter(|b| b.is_available())
}
pub fn describe_all(&self) -> Vec<DeviceDescriptor> {
self.available()
.flat_map(|b| b.enumerate().unwrap_or_default())
.collect()
}
}
impl Default for BackendRegistry {
fn default() -> Self {
Self::new()
}
}