wgpu_types/
adapter.rs

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