wgpu_types/
adapter.rs

1use alloc::string::String;
2use core::{fmt, mem};
3
4use crate::{link_to_wgpu_docs, Backend, Backends};
5
6#[cfg(any(feature = "serde", test))]
7use serde::{Deserialize, Serialize};
8
9#[cfg(doc)]
10use crate::{Features, TextureUsages};
11
12/// A set of requested capabilities when choosing a physical adapter.
13///
14/// Corresponds to the defined values of [WebGPU feature level string](
15/// https://gpuweb.github.io/gpuweb/#feature-level-string).
16///
17/// `wgpu` does not support compatibility-level adapters per se.
18#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
21pub enum FeatureLevel {
22    #[default]
23    /// The `core` capability set
24    Core,
25    /// The `compatibility` capability set
26    Compatibility,
27}
28
29/// Options for requesting adapter.
30///
31/// Corresponds to [WebGPU `GPURequestAdapterOptions`](
32/// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions).
33#[repr(C)]
34#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36pub struct RequestAdapterOptions<S> {
37    /// Power preference for the adapter.
38    pub power_preference: PowerPreference,
39    /// Indicates that only a fallback adapter can be returned. This is generally a "software"
40    /// implementation on the system.
41    pub force_fallback_adapter: bool,
42    /// Surface that is required to be presentable with the requested adapter. This does not
43    /// create the surface, only guarantees that the adapter can present to said surface.
44    /// For WebGL, this is strictly required, as an adapter can not be created without a surface.
45    pub compatible_surface: Option<S>,
46}
47
48impl<S> Default for RequestAdapterOptions<S> {
49    fn default() -> Self {
50        Self {
51            power_preference: PowerPreference::default(),
52            force_fallback_adapter: false,
53            compatible_surface: None,
54        }
55    }
56}
57
58/// Power Preference when choosing a physical adapter.
59///
60/// Corresponds to [WebGPU `GPUPowerPreference`](
61/// https://gpuweb.github.io/gpuweb/#enumdef-gpupowerpreference).
62#[repr(C)]
63#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
66pub enum PowerPreference {
67    #[default]
68    /// Power usage is not considered when choosing an adapter.
69    None = 0,
70    /// Adapter that uses the least possible power. This is often an integrated GPU.
71    LowPower = 1,
72    /// Adapter that has the highest performance. This is often a discrete GPU.
73    HighPerformance = 2,
74}
75
76impl PowerPreference {
77    /// Get a power preference from the environment variable `WGPU_POWER_PREF`.
78    pub fn from_env() -> Option<Self> {
79        let env = crate::env::var("WGPU_POWER_PREF")?;
80        match env.to_lowercase().as_str() {
81            "low" => Some(Self::LowPower),
82            "high" => Some(Self::HighPerformance),
83            "none" => Some(Self::None),
84            _ => None,
85        }
86    }
87}
88
89/// Supported physical device types.
90#[repr(u8)]
91#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93pub enum DeviceType {
94    /// Other or Unknown.
95    Other,
96    /// Integrated GPU with shared CPU/GPU memory.
97    IntegratedGpu,
98    /// Discrete GPU with separate CPU/GPU memory.
99    DiscreteGpu,
100    /// Virtual / Hosted.
101    VirtualGpu,
102    /// Cpu / Software Rendering.
103    Cpu,
104}
105
106//TODO: convert `vendor` and `device` to `u32`
107
108/// Information about an adapter.
109#[derive(Clone, Debug, Eq, PartialEq, Hash)]
110#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
111pub struct AdapterInfo {
112    /// Adapter name
113    pub name: String,
114    /// [`Backend`]-specific vendor ID of the adapter
115    ///
116    /// This generally is a 16-bit PCI vendor ID in the least significant bytes of this field.
117    /// However, more significant bytes may be non-zero if the backend uses a different
118    /// representation.
119    ///
120    /// * For [`Backend::Vulkan`], the [`VkPhysicalDeviceProperties::vendorID`] is used, which is
121    ///   a superset of PCI IDs.
122    ///
123    /// [`VkPhysicalDeviceProperties::vendorID`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html
124    pub vendor: u32,
125    /// [`Backend`]-specific device ID of the adapter
126    ///
127    ///
128    /// This generally is a 16-bit PCI device ID in the least significant bytes of this field.
129    /// However, more significant bytes may be non-zero if the backend uses a different
130    /// representation.
131    ///
132    /// * For [`Backend::Vulkan`], the [`VkPhysicalDeviceProperties::deviceID`] is used, which is
133    ///   a superset of PCI IDs.
134    ///
135    /// [`VkPhysicalDeviceProperties::deviceID`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html
136    pub device: u32,
137    /// Type of device
138    pub device_type: DeviceType,
139    /// [`Backend`]-specific PCI bus ID of the adapter.
140    ///
141    /// * For [`Backend::Vulkan`], [`VkPhysicalDevicePCIBusInfoPropertiesEXT`] is used,
142    ///   if available, in the form `bus:device.function`, e.g. `0000:01:00.0`.
143    ///
144    /// [`VkPhysicalDevicePCIBusInfoPropertiesEXT`]: https://registry.khronos.org/vulkan/specs/latest/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html
145    pub device_pci_bus_id: String,
146    /// Driver name
147    pub driver: String,
148    /// Driver info
149    pub driver_info: String,
150    /// Backend used for device
151    pub backend: Backend,
152    /// Minimum possible size of a subgroup on this adapter. Will
153    /// never be lower than [`crate::MINIMUM_SUBGROUP_MIN_SIZE`].
154    ///
155    /// This will vary from device to device. Typical values are listed below.
156    ///
157    /// - NVIDIA: 32
158    /// - AMD GCN/Vega: 64
159    /// - AMD RDNA+: 32
160    /// - Intel: 8 or 16
161    /// - Qualcomm: 64
162    /// - WARP: 4
163    /// - lavapipe: 8
164    pub subgroup_min_size: u32,
165    /// Maximum possible size of a subgroup on this adapter. Will
166    /// never be higher than [`crate::MAXIMUM_SUBGROUP_MAX_SIZE`].
167    ///
168    /// This will vary from device to device. Typical values are listed below:
169    ///
170    /// - NVIDIA: 32
171    /// - AMD GCN/Vega: 64
172    /// - AMD RDNA+: 64
173    /// - Intel: 16 or 32
174    /// - Qualcomm: 128
175    /// - WARP: 4 or 128
176    /// - lavapipe: 8
177    pub subgroup_max_size: u32,
178    /// If true, adding [`TextureUsages::TRANSIENT`] to a texture will decrease memory usage.
179    pub transient_saves_memory: bool,
180}
181
182/// Error when [`Instance::request_adapter()`] fails.
183///
184/// This type is not part of the WebGPU standard, where `requestAdapter()` would simply return null.
185///
186#[doc = link_to_wgpu_docs!(["`Instance::request_adapter()`"]: "struct.Instance.html#method.request_adapter")]
187#[derive(Clone, Debug, PartialEq)]
188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
189#[non_exhaustive]
190pub enum RequestAdapterError {
191    /// No adapter available via the instance’s backends matched the request’s adapter criteria.
192    NotFound {
193        // These fields must be set by wgpu-core and wgpu, but are not intended to be stable API,
194        // only data for the production of the error message.
195        #[doc(hidden)]
196        active_backends: Backends,
197        #[doc(hidden)]
198        requested_backends: Backends,
199        #[doc(hidden)]
200        supported_backends: Backends,
201        #[doc(hidden)]
202        no_fallback_backends: Backends,
203        #[doc(hidden)]
204        no_adapter_backends: Backends,
205        #[doc(hidden)]
206        incompatible_surface_backends: Backends,
207    },
208
209    /// Attempted to obtain adapter specified by environment variable, but the environment variable
210    /// was not set.
211    EnvNotSet,
212}
213
214impl core::error::Error for RequestAdapterError {}
215impl fmt::Display for RequestAdapterError {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        match self {
218            RequestAdapterError::NotFound {
219                active_backends,
220                requested_backends,
221                supported_backends,
222                no_fallback_backends,
223                no_adapter_backends,
224                incompatible_surface_backends,
225            } => {
226                write!(f, "No suitable graphics adapter found; ")?;
227                let mut first = true;
228                for backend in Backend::ALL {
229                    let bit = Backends::from(backend);
230                    let comma = if mem::take(&mut first) { "" } else { ", " };
231                    let explanation = if !requested_backends.contains(bit) {
232                        // We prefer reporting this, because it makes the error most stable with
233                        // respect to what is directly controllable by the caller, as opposed to
234                        // compilation options or the run-time environment.
235                        "not requested"
236                    } else if !supported_backends.contains(bit) {
237                        "support not compiled in"
238                    } else if no_adapter_backends.contains(bit) {
239                        "found no adapters"
240                    } else if incompatible_surface_backends.contains(bit) {
241                        "not compatible with provided surface"
242                    } else if no_fallback_backends.contains(bit) {
243                        "had no fallback adapters"
244                    } else if !active_backends.contains(bit) {
245                        // Backend requested but not active in this instance
246                        if backend == Backend::Noop {
247                            "not explicitly enabled"
248                        } else {
249                            "drivers/libraries could not be loaded"
250                        }
251                    } else {
252                        // This path should be unreachable, but don't crash.
253                        "[unknown reason]"
254                    };
255                    write!(f, "{comma}{backend} {explanation}")?;
256                }
257            }
258            RequestAdapterError::EnvNotSet => f.write_str("WGPU_ADAPTER_NAME not set")?,
259        }
260        Ok(())
261    }
262}
263
264/// The underlying scalar type of the cooperative matrix component.
265#[repr(u8)]
266#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
267#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
268pub enum CooperativeScalarType {
269    /// 32-bit floating point.
270    F32,
271    /// 16-bit floating point.
272    F16,
273    /// 32-bit signed integer.
274    I32,
275    /// 32-bit unsigned integer.
276    U32,
277}
278
279/// Describes a supported cooperative matrix configuration.
280///
281/// Cooperative matrices perform the operation `C = A * B + C` where:
282/// - `A` is an M×K matrix
283/// - `B` is a K×N matrix
284/// - `C` is an M×N matrix (both input accumulator and output)
285#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
286pub struct CooperativeMatrixProperties {
287    /// Number of rows in matrices A and C (M dimension)
288    pub m_size: u32,
289    /// Number of columns in matrices B and C (N dimension)
290    pub n_size: u32,
291    /// Number of columns in A / rows in B (K dimension)
292    pub k_size: u32,
293    /// Element type for input matrices A and B
294    pub ab_type: CooperativeScalarType,
295    /// Element type for accumulator matrix C and the result
296    pub cr_type: CooperativeScalarType,
297    /// Whether saturating accumulation is supported.
298    ///
299    /// When true, the multiply-add operation clamps the result to prevent overflow.
300    pub saturating_accumulation: bool,
301}