Skip to main content

cubecl_wgpu/
graphics.rs

1pub use wgpu::Backend;
2/// The basic trait to specify which graphics API to use as Backend.
3///
4/// Options are:
5///   - [Vulkan](Vulkan)
6///   - [Metal](Metal)
7///   - [OpenGL](OpenGl)
8///   - [DirectX 12](Dx12)
9///   - [WebGpu](WebGpu)
10pub trait GraphicsApi: Send + Sync + core::fmt::Debug + Default + Clone + 'static {
11    /// The wgpu backend.
12    fn backend() -> Backend;
13
14    /// The wgpu backend `device` comes up on when set up through this API.
15    ///
16    /// A named API is itself, whatever the device. [`AutoGraphicsApi`] is the
17    /// one that defers, to the API the device pins where it pins one.
18    fn backend_for(device: &crate::WgpuDevice) -> Backend {
19        let _ = device;
20        Self::backend()
21    }
22}
23
24/// Vulkan graphics API.
25#[derive(Default, Debug, Clone)]
26pub struct Vulkan;
27
28/// Metal graphics API.
29#[derive(Default, Debug, Clone)]
30pub struct Metal;
31
32/// OpenGL graphics API.
33#[derive(Default, Debug, Clone)]
34pub struct OpenGl;
35
36/// DirectX 12 graphics API.
37#[derive(Default, Debug, Clone)]
38pub struct Dx12;
39
40/// `WebGpu` graphics API.
41#[derive(Default, Debug, Clone)]
42pub struct WebGpu;
43
44/// Automatic graphics API based on OS.
45#[derive(Default, Debug, Clone)]
46pub struct AutoGraphicsApi;
47
48impl GraphicsApi for Vulkan {
49    fn backend() -> Backend {
50        Backend::Vulkan
51    }
52}
53
54impl GraphicsApi for Metal {
55    fn backend() -> Backend {
56        Backend::Metal
57    }
58}
59
60impl GraphicsApi for OpenGl {
61    fn backend() -> Backend {
62        Backend::Gl
63    }
64}
65
66impl GraphicsApi for Dx12 {
67    fn backend() -> Backend {
68        Backend::Dx12
69    }
70}
71
72impl GraphicsApi for WebGpu {
73    fn backend() -> Backend {
74        Backend::BrowserWebGpu
75    }
76}
77
78impl AutoGraphicsApi {
79    /// The graphics APIs to try on this machine, best first.
80    ///
81    /// Vulkan leads wherever it reaches a GPU: it is the one that compiles to
82    /// `SPIR-V`, and the rest are what a machine without it still offers. An
83    /// API with only a software rasterizer is passed over for a later one
84    /// with a GPU, and taken only when none has one. Backends this machine has
85    /// no driver for enumerate nothing, so a list costs only the asking.
86    ///
87    /// This crate's own tests can narrow it to one with `AUTO_GRAPHICS_BACKEND`,
88    /// which then holds for every `Auto` device, not only those set up through
89    /// [`GraphicsApi::backend`].
90    pub fn chain() -> alloc::vec::Vec<Backend> {
91        #[cfg(all(feature = "std", test))]
92        if let Ok(backend) = std::env::var("AUTO_GRAPHICS_BACKEND") {
93            let backend = match backend.to_lowercase().as_str() {
94                "metal" => Backend::Metal,
95                "vulkan" => Backend::Vulkan,
96                "dx12" => Backend::Dx12,
97                "opengl" => Backend::Gl,
98                "webgpu" => Backend::BrowserWebGpu,
99                _ => {
100                    eprintln!(
101                        "Invalid graphics backend specified in AUTO_GRAPHICS_BACKEND environment \
102                         variable"
103                    );
104                    std::process::exit(1);
105                }
106            };
107
108            return alloc::vec![backend];
109        }
110
111        cfg_if::cfg_if! {
112            if #[cfg(target_family = "wasm")] {
113                alloc::vec![Backend::BrowserWebGpu]
114            } else if #[cfg(target_os = "macos")] {
115                alloc::vec![Backend::Metal]
116            } else {
117                alloc::vec![Backend::Vulkan, Backend::Dx12, Backend::Gl]
118            }
119        }
120    }
121}
122
123impl GraphicsApi for AutoGraphicsApi {
124    /// The first of the [chain](Self::chain) this machine has an adapter for —
125    /// the API a [`WgpuBackend::Auto`](crate::WgpuBackend::Auto) device comes
126    /// up on, so a setup made through this lands where a client made on first
127    /// use would.
128    fn backend() -> Backend {
129        crate::runtime::resolve_backend(crate::WgpuBackend::Auto)
130    }
131
132    /// The API `device` pins, or where it pins none, [`backend`](Self::backend).
133    fn backend_for(device: &crate::WgpuDevice) -> Backend {
134        crate::runtime::resolve_backend(device.backend)
135    }
136}