wgpu_types/
adapter.rs

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