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}