wgpu_types/backend.rs
1//! [`Backend`], [`Backends`], and backend-specific options.
2
3use alloc::string::{String, ToString};
4use core::{hash::Hash, str::FromStr};
5
6#[cfg(any(feature = "serde", test))]
7use serde::{Deserialize, Serialize};
8
9use crate::link_to_wgpu_docs;
10
11#[cfg(doc)]
12use crate::InstanceDescriptor;
13
14/// Backends supported by wgpu.
15///
16/// See also [`Backends`].
17#[repr(u8)]
18#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub enum Backend {
21 /// Dummy backend, which may be used for testing.
22 ///
23 /// It performs no rendering or computation, but allows creation of stub GPU resource types,
24 /// so that code which manages GPU resources can be tested without an available GPU.
25 /// Specifically, the following operations are implemented:
26 ///
27 /// * Enumerating adapters will always return one noop adapter, which can be used to create
28 /// devices.
29 /// * Buffers may be created, written, mapped, and copied to other buffers.
30 /// * Command encoders may be created, but only buffer operations are useful.
31 ///
32 /// Other resources can be created but are nonfunctional; notably,
33 ///
34 /// * Render passes and compute passes are not executed.
35 /// * Textures may be created, but do not store any texels.
36 /// * There are no compatible surfaces.
37 ///
38 /// An adapter using the noop backend can only be obtained if [`NoopBackendOptions`]
39 /// enables it, in addition to the ordinary requirement of [`Backends::NOOP`] being set.
40 /// This ensures that applications not desiring a non-functional backend will not receive it.
41 Noop = 0,
42
43 /// Vulkan API (Windows, Linux, Android, MacOS via `vulkan-portability`/MoltenVK)
44 Vulkan = 1,
45
46 /// Metal API (Apple platforms)
47 Metal = 2,
48
49 /// Direct3D-12 (Windows)
50 Dx12 = 3,
51
52 /// OpenGL 3.3+, OpenGL ES 3.0+, WebGL2.
53 ///
54 /// - On Windows, this is normally OpenGL. If you build with
55 /// `cfg(windows_angle)` to use ANGLE instead, then this is OpenGL ES.
56 ///
57 /// - On Linux, we create a full OpenGL context if possible (Mesa offers
58 /// it), but if that fails we fall back to OpenGL ES.
59 ///
60 /// - On Android and macOS with ANGLE, we get OpenGL ES.
61 ///
62 /// - When running in a web browser, we get WebGL2.
63 Gl = 4,
64
65 /// WebGPU in the browser
66 BrowserWebGpu = 5,
67}
68
69impl Backend {
70 /// Array of all [`Backend`] values, corresponding to [`Backends::all()`].
71 pub const ALL: [Backend; Backends::all().bits().count_ones() as usize] = [
72 Self::Noop,
73 Self::Vulkan,
74 Self::Metal,
75 Self::Dx12,
76 Self::Gl,
77 Self::BrowserWebGpu,
78 ];
79
80 /// Returns the string name of the backend.
81 #[must_use]
82 pub const fn to_str(self) -> &'static str {
83 match self {
84 Backend::Noop => "noop",
85 Backend::Vulkan => "vulkan",
86 Backend::Metal => "metal",
87 Backend::Dx12 => "dx12",
88 Backend::Gl => "gl",
89 Backend::BrowserWebGpu => "webgpu",
90 }
91 }
92}
93
94impl core::fmt::Display for Backend {
95 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96 f.write_str(self.to_str())
97 }
98}
99
100bitflags::bitflags! {
101 /// Represents the backends that wgpu will use.
102 #[repr(transparent)]
103 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
104 #[cfg_attr(feature = "serde", serde(transparent))]
105 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
106 pub struct Backends: u32 {
107 /// [`Backend::Noop`].
108 const NOOP = 1 << Backend::Noop as u32;
109
110 /// [`Backend::Vulkan`].
111 /// Supported on Windows, Linux/Android, and macOS/iOS via Vulkan Portability (with the Vulkan feature enabled)
112 const VULKAN = 1 << Backend::Vulkan as u32;
113
114 /// [`Backend::Gl`].
115 /// Supported on Linux/Android, the web through webassembly via WebGL, and
116 /// Windows through native OpenGL by default or ANGLE with `cfg(windows_angle)`.
117 const GL = 1 << Backend::Gl as u32;
118
119 /// [`Backend::Metal`].
120 /// Supported on macOS and iOS.
121 const METAL = 1 << Backend::Metal as u32;
122
123 /// [`Backend::Dx12`].
124 /// Supported on Windows 10 and later
125 const DX12 = 1 << Backend::Dx12 as u32;
126
127 /// [`Backend::BrowserWebGpu`].
128 /// Supported when targeting the web through WebAssembly with the `webgpu` feature enabled.
129 ///
130 /// The WebGPU backend is special in several ways:
131 /// It is not not implemented by `wgpu_core` and instead by the higher level `wgpu` crate.
132 /// Whether WebGPU is targeted is decided upon the creation of the `wgpu::Instance`,
133 /// *not* upon adapter creation. See `wgpu::Instance::new`.
134 const BROWSER_WEBGPU = 1 << Backend::BrowserWebGpu as u32;
135
136 /// All the apis that wgpu offers first tier of support for.
137 ///
138 /// * [`Backends::VULKAN`]
139 /// * [`Backends::METAL`]
140 /// * [`Backends::DX12`]
141 /// * [`Backends::BROWSER_WEBGPU`]
142 const PRIMARY = Self::VULKAN.bits()
143 | Self::METAL.bits()
144 | Self::DX12.bits()
145 | Self::BROWSER_WEBGPU.bits();
146
147 /// All the apis that wgpu offers second tier of support for. These may
148 /// be unsupported/still experimental.
149 ///
150 /// * [`Backends::GL`]
151 const SECONDARY = Self::GL.bits();
152 }
153}
154
155impl Default for Backends {
156 fn default() -> Self {
157 Self::all()
158 }
159}
160
161impl From<Backend> for Backends {
162 fn from(backend: Backend) -> Self {
163 Self::from_bits(1 << backend as u32).unwrap()
164 }
165}
166
167impl Backends {
168 /// Gets a set of backends from the environment variable `WGPU_BACKEND`.
169 ///
170 /// See [`Self::from_comma_list()`] for the format of the string.
171 pub fn from_env() -> Option<Self> {
172 let env = crate::env::var("WGPU_BACKEND")?;
173 Some(Self::from_comma_list(&env))
174 }
175
176 /// Takes the given options, modifies them based on the `WGPU_BACKEND` environment variable, and returns the result.
177 pub fn with_env(&self) -> Self {
178 if let Some(env) = Self::from_env() {
179 env
180 } else {
181 *self
182 }
183 }
184
185 /// Generates a set of backends from a comma separated list of case-insensitive backend names.
186 ///
187 /// Whitespace is stripped, so both 'gl, dx12' and 'gl,dx12' are valid.
188 ///
189 /// Always returns WEBGPU on wasm over webgpu.
190 ///
191 /// Names:
192 /// - vulkan = "vulkan" or "vk"
193 /// - dx12 = "dx12" or "d3d12"
194 /// - metal = "metal" or "mtl"
195 /// - gles = "opengl" or "gles" or "gl"
196 /// - webgpu = "webgpu"
197 pub fn from_comma_list(string: &str) -> Self {
198 let mut backends = Self::empty();
199 for backend in string.to_lowercase().split(',') {
200 backends |= match backend.trim() {
201 "vulkan" | "vk" => Self::VULKAN,
202 "dx12" | "d3d12" => Self::DX12,
203 "metal" | "mtl" => Self::METAL,
204 "opengl" | "gles" | "gl" => Self::GL,
205 "webgpu" => Self::BROWSER_WEBGPU,
206 "noop" => Self::NOOP,
207 b => {
208 log::warn!("unknown backend string '{b}'");
209 continue;
210 }
211 }
212 }
213
214 if backends.is_empty() {
215 log::warn!("no valid backend strings found!");
216 }
217
218 backends
219 }
220}
221
222/// Options that are passed to a given backend.
223///
224/// Part of [`InstanceDescriptor`].
225#[derive(Clone, Debug, Default)]
226pub struct BackendOptions {
227 /// Options for the OpenGL/OpenGLES backend, [`Backend::Gl`].
228 pub gl: GlBackendOptions,
229 /// Options for the DX12 backend, [`Backend::Dx12`].
230 pub dx12: Dx12BackendOptions,
231 /// Options for the noop backend, [`Backend::Noop`].
232 pub noop: NoopBackendOptions,
233}
234
235impl BackendOptions {
236 /// Choose backend options by calling `from_env` on every field.
237 ///
238 /// See those methods for more information.
239 #[must_use]
240 pub fn from_env_or_default() -> Self {
241 Self {
242 gl: GlBackendOptions::from_env_or_default(),
243 dx12: Dx12BackendOptions::from_env_or_default(),
244 noop: NoopBackendOptions::from_env_or_default(),
245 }
246 }
247
248 /// Takes the given options, modifies them based on the environment variables, and returns the result.
249 ///
250 /// This is equivalent to calling `with_env` on every field.
251 #[must_use]
252 pub fn with_env(self) -> Self {
253 Self {
254 gl: self.gl.with_env(),
255 dx12: self.dx12.with_env(),
256 noop: self.noop.with_env(),
257 }
258 }
259}
260
261/// Configuration for the OpenGL/OpenGLES backend.
262///
263/// Part of [`BackendOptions`].
264#[derive(Clone, Debug, Default)]
265pub struct GlBackendOptions {
266 /// Which OpenGL ES 3 minor version to request, if using OpenGL ES.
267 pub gles_minor_version: Gles3MinorVersion,
268 /// Behavior of OpenGL fences. Affects how `on_completed_work_done` and `device.poll` behave.
269 pub fence_behavior: GlFenceBehavior,
270 /// Controls whether debug functions (`glPushDebugGroup`, `glPopDebugGroup`,
271 /// `glObjectLabel`, etc.) are enabled when supported by the driver.
272 ///
273 /// By default ([`GlDebugFns::Auto`]), debug functions are automatically
274 /// disabled on devices with known bugs (e.g., Mali GPUs can crash in
275 /// `glPushDebugGroup`). Use [`GlDebugFns::ForceEnabled`] to override this
276 /// behavior, or [`GlDebugFns::Disabled`] to disable debug functions entirely.
277 ///
278 /// See also [`InstanceFlags::DISCARD_HAL_LABELS`], which prevents debug
279 /// markers and labels from being sent to *any* backend, but without the
280 /// driver-specific bug workarounds provided here.
281 ///
282 /// [`InstanceFlags::DISCARD_HAL_LABELS`]: crate::InstanceFlags::DISCARD_HAL_LABELS
283 pub debug_fns: GlDebugFns,
284}
285
286impl GlBackendOptions {
287 /// Choose OpenGL backend options by calling `from_env` on every field.
288 ///
289 /// See those methods for more information.
290 #[must_use]
291 pub fn from_env_or_default() -> Self {
292 let gles_minor_version = Gles3MinorVersion::from_env().unwrap_or_default();
293 let debug_fns = GlDebugFns::from_env().unwrap_or_default();
294 Self {
295 gles_minor_version,
296 fence_behavior: GlFenceBehavior::Normal,
297 debug_fns,
298 }
299 }
300
301 /// Takes the given options, modifies them based on the environment variables, and returns the result.
302 ///
303 /// This is equivalent to calling `with_env` on every field.
304 #[must_use]
305 pub fn with_env(self) -> Self {
306 let gles_minor_version = self.gles_minor_version.with_env();
307 let fence_behavior = self.fence_behavior.with_env();
308 let debug_fns = self.debug_fns.with_env();
309 Self {
310 gles_minor_version,
311 fence_behavior,
312 debug_fns,
313 }
314 }
315}
316
317/// Controls whether OpenGL debug functions are enabled.
318///
319/// Debug functions include `glPushDebugGroup`, `glPopDebugGroup`, `glObjectLabel`, etc.
320/// These are useful for debugging but can cause crashes on some buggy drivers.
321#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
322pub enum GlDebugFns {
323 /// Automatically decide whether to enable debug functions.
324 ///
325 /// Debug functions will be enabled if supported by the driver, unless
326 /// running on a device known to have buggy debug function implementations
327 /// (e.g., Mali GPUs which can crash in `glPushDebugGroup`).
328 ///
329 /// This is the default behavior.
330 #[default]
331 Auto,
332 /// Force enable debug functions if supported by the driver.
333 ///
334 /// This ignores any device-specific workarounds and enables debug functions
335 /// on all devices that support them, including those with known bugs.
336 ForceEnabled,
337 /// Disable debug functions entirely.
338 ///
339 /// Debug functions will not be used even if supported by the driver.
340 Disabled,
341}
342
343impl GlDebugFns {
344 /// Choose debug functions setting from the environment variable `WGPU_GL_DEBUG_FNS`.
345 ///
346 /// Possible values (case insensitive):
347 /// - `auto` - automatically decide based on device
348 /// - `forceenabled`, `force_enabled`, or `enabled` - force enable
349 /// - `disabled` - disable entirely
350 ///
351 /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
352 #[must_use]
353 pub fn from_env() -> Option<Self> {
354 let value = crate::env::var("WGPU_GL_DEBUG_FNS")
355 .as_deref()?
356 .to_lowercase();
357 match value.as_str() {
358 "auto" => Some(Self::Auto),
359 "forceenabled" | "force_enabled" | "enabled" => Some(Self::ForceEnabled),
360 "disabled" => Some(Self::Disabled),
361 _ => None,
362 }
363 }
364
365 /// Takes the given setting, modifies it based on the `WGPU_GL_DEBUG_FNS` environment variable, and returns the result.
366 ///
367 /// See `from_env` for more information.
368 #[must_use]
369 pub fn with_env(self) -> Self {
370 if let Some(debug_fns) = Self::from_env() {
371 debug_fns
372 } else {
373 self
374 }
375 }
376}
377
378/// Used to force wgpu to expose certain features on passthrough shaders even when
379/// those features aren't present on runtime-compiled shaders
380#[derive(Default, Clone, Debug)]
381pub struct ForceShaderModelToken {
382 inner: Option<DxcShaderModel>,
383}
384impl ForceShaderModelToken {
385 /// Creates an unsafe token, opting you in to seeing features that you may not necessarily use
386 /// on standard runtime-compiled shaders.
387 /// # Safety
388 /// Do not make use in runtime-compiled shaders of any features that may not be supported by the FXC or DXC
389 /// version you use.
390 pub unsafe fn with_shader_model(sm: DxcShaderModel) -> Self {
391 Self { inner: Some(sm) }
392 }
393
394 /// Returns the shader model version, if any, in this token.
395 pub fn get(&self) -> Option<DxcShaderModel> {
396 self.inner.clone()
397 }
398}
399
400/// Behavior when the Agility SDK fails to load.
401///
402/// See [`Dx12AgilitySDK`] for details on the Agility SDK.
403#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
404pub enum Dx12AgilitySDKLoadFailure {
405 /// Log a warning and fall back to the system-installed D3D12 runtime.
406 ///
407 /// This is the default behavior and is appropriate for most applications.
408 #[default]
409 Fallback,
410 /// Fail instance creation entirely if the Agility SDK cannot be loaded.
411 ///
412 /// Use this in environments where you are shipping the Agility SDK alongside your application
413 /// and want to ensure that it is being loaded correctly.
414 Error,
415}
416
417impl Dx12AgilitySDKLoadFailure {
418 /// Read the load failure behavior from the environment variable
419 /// `WGPU_DX12_AGILITY_SDK_REQUIRE`.
420 ///
421 /// When set to `1`, returns [`Error`](Self::Error).
422 /// When set to `0`, returns [`Fallback`](Self::Fallback).
423 #[must_use]
424 pub fn from_env() -> Option<Self> {
425 let value = crate::env::var("WGPU_DX12_AGILITY_SDK_REQUIRE")?;
426 match value.as_str() {
427 "1" => Some(Self::Error),
428 "0" => Some(Self::Fallback),
429 _ => None,
430 }
431 }
432
433 /// Takes the given setting, modifies it based on the
434 /// `WGPU_DX12_AGILITY_SDK_REQUIRE` environment variable, and returns the result.
435 ///
436 /// See [`from_env`](Self::from_env) for more information.
437 #[must_use]
438 pub fn with_env(self) -> Self {
439 if let Some(v) = Self::from_env() {
440 v
441 } else {
442 self
443 }
444 }
445}
446
447/// Configuration for loading a specific [DirectX 12 Agility SDK] runtime.
448///
449/// The Agility SDK allows applications to ship a newer version of the D3D12 runtime
450/// (`D3D12Core.dll`) alongside the application, enabling access to the latest D3D12
451/// features without waiting for the OS to update its built-in runtime. This is the
452/// standard way for games and applications to adopt new D3D12 functionality on older
453/// Windows versions.
454///
455/// Downloads and release notes are available at the [DirectX 12 Agility SDK] page.
456///
457/// wgpu loads the Agility SDK via the [Independent Devices API], which allows
458/// specifying the SDK path and version at runtime without requiring exported constants
459/// or developer mode. The [`sdk_version`](Self::sdk_version) must match the version of
460/// the `D3D12Core.dll` in the provided path exactly, or loading will fail, irrespective of
461/// the OS's built-in runtime version.
462///
463/// If the shipped SDK is older than the system runtime, the system runtime will be used.
464/// This allows applications to ship a minimum SDK version while still benefiting from SDK updates on the user's system.
465///
466/// If the Agility SDK fails to load (version mismatch, missing DLL, unsupported OS,
467/// etc.), the behavior is controlled by [`on_load_failure`](Self::on_load_failure).
468/// By default, wgpu logs a warning and falls back to the system-installed D3D12 runtime.
469/// Set it to [`Error`](Dx12AgilitySDKLoadFailure::Error) to fail instance creation instead
470/// (useful in CI/testing).
471///
472/// ## OS requirements
473///
474/// The Independent Devices API requires a Windows update from August/September 2023
475/// or newer:
476///
477/// - [Windows 11 21H2+ (KB5029332)][win11-21h2]
478/// - [Windows 10 22H2+ (KB5029331)][win10-22h2]
479/// - [Windows Server 2022+ (KB5030216)][server-2022]
480///
481/// On older OS builds the Agility SDK will not load and wgpu will log a warning and
482/// fall back to the system runtime (or error, per [`on_load_failure`](Self::on_load_failure)).
483///
484/// [DirectX 12 Agility SDK]: https://devblogs.microsoft.com/directx/directx12agility/
485/// [Independent Devices API]: https://devblogs.microsoft.com/directx/d3d12-independent-devices/
486/// [win11-21h2]: https://support.microsoft.com/en-us/topic/august-22-2023-kb5029332-os-build-22000-2360-preview-8f8aec64-77b4-4225-9a0f-f0153204ae28
487/// [win10-22h2]: https://support.microsoft.com/en-gb/topic/august-22-2023-kb5029331-os-build-19045-3393-preview-9f6c1dbd-0ee6-469b-af24-f9d0bf35ca18
488/// [server-2022]: https://support.microsoft.com/en-au/topic/september-12-2023-kb5030216-os-build-20348-1970-34d4aff3-fd05-4270-b288-4ab6379c7f81
489#[derive(Clone, Debug)]
490pub struct Dx12AgilitySDK {
491 /// The Agility SDK version number (e.g., 614 for SDK version 1.614.0).
492 ///
493 /// This must match the version of the `D3D12Core.dll` at [`sdk_path`](Self::sdk_path)
494 /// exactly, or the runtime will fail to load.
495 pub sdk_version: u32,
496 /// Path to the directory containing the Agility SDK's `D3D12Core.dll`.
497 pub sdk_path: String,
498 /// What to do if the Agility SDK fails to load.
499 ///
500 /// Defaults to [`Fallback`](Dx12AgilitySDKLoadFailure::Fallback).
501 ///
502 /// Can also be set via the `WGPU_DX12_AGILITY_SDK_REQUIRE` environment variable
503 /// (`1` for [`Error`](Dx12AgilitySDKLoadFailure::Error),
504 /// `0` for [`Fallback`](Dx12AgilitySDKLoadFailure::Fallback)).
505 pub on_load_failure: Dx12AgilitySDKLoadFailure,
506}
507
508impl Dx12AgilitySDK {
509 /// Read Agility SDK configuration from environment variables.
510 ///
511 /// Reads `WGPU_DX12_AGILITY_SDK_PATH`, `WGPU_DX12_AGILITY_SDK_VERSION`,
512 /// and `WGPU_DX12_AGILITY_SDK_REQUIRE`.
513 /// Both path and version must be set for this to return `Some`.
514 #[must_use]
515 pub fn from_env() -> Option<Self> {
516 let sdk_path = crate::env::var("WGPU_DX12_AGILITY_SDK_PATH")?;
517 let sdk_version_str = crate::env::var("WGPU_DX12_AGILITY_SDK_VERSION")?;
518 let sdk_version = sdk_version_str.parse::<u32>().ok()?;
519 let on_load_failure = Dx12AgilitySDKLoadFailure::from_env().unwrap_or_default();
520 Some(Self {
521 sdk_version,
522 sdk_path,
523 on_load_failure,
524 })
525 }
526
527 /// Takes the given configuration, overrides fields with environment variables if present,
528 /// and returns the result.
529 ///
530 /// Reads `WGPU_DX12_AGILITY_SDK_PATH`, `WGPU_DX12_AGILITY_SDK_VERSION`,
531 /// and `WGPU_DX12_AGILITY_SDK_REQUIRE`.
532 /// Each variable overrides the corresponding field independently.
533 #[must_use]
534 pub fn with_env(mut self) -> Self {
535 if let Some(sdk_path) = crate::env::var("WGPU_DX12_AGILITY_SDK_PATH") {
536 self.sdk_path = sdk_path;
537 }
538 if let Some(sdk_version_str) = crate::env::var("WGPU_DX12_AGILITY_SDK_VERSION") {
539 if let Ok(sdk_version) = sdk_version_str.parse::<u32>() {
540 self.sdk_version = sdk_version;
541 }
542 }
543 self.on_load_failure = self.on_load_failure.with_env();
544 self
545 }
546}
547
548/// Configuration for the DX12 backend.
549///
550/// Part of [`BackendOptions`].
551#[derive(Clone, Debug, Default)]
552pub struct Dx12BackendOptions {
553 /// Which DX12 shader compiler to use.
554 pub shader_compiler: Dx12Compiler,
555 /// Presentation system to use.
556 pub presentation_system: Dx12SwapchainKind,
557 /// Whether to wait for the latency waitable object before acquiring the next swapchain image.
558 pub latency_waitable_object: Dx12UseFrameLatencyWaitableObject,
559 /// For use with passthrough shaders. Expose features as if this shader model is present, even if you do not
560 /// intend to ship DXC with your app.
561 ///
562 /// This does not override the device's shader model version, only the external shader compiler's version.
563 pub force_shader_model: ForceShaderModelToken,
564 /// Optional Agility SDK configuration for using the Independent Devices API.
565 ///
566 /// When set, wgpu will attempt to load the specified D3D12 runtime via the
567 /// Independent Devices API. If the API is unavailable or the configuration is
568 /// invalid, it falls back to the system-installed D3D12 runtime.
569 ///
570 /// Can also be set via `WGPU_DX12_AGILITY_SDK_PATH` and `WGPU_DX12_AGILITY_SDK_VERSION`
571 /// environment variables.
572 pub agility_sdk: Option<Dx12AgilitySDK>,
573}
574
575impl Dx12BackendOptions {
576 /// Choose DX12 backend options by calling `from_env` on every field.
577 ///
578 /// See those methods for more information.
579 #[must_use]
580 pub fn from_env_or_default() -> Self {
581 let compiler = Dx12Compiler::from_env().unwrap_or_default();
582 let presentation_system = Dx12SwapchainKind::from_env().unwrap_or_default();
583 let latency_waitable_object =
584 Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();
585 let agility_sdk = Dx12AgilitySDK::from_env();
586 Self {
587 shader_compiler: compiler,
588 presentation_system,
589 latency_waitable_object,
590 force_shader_model: ForceShaderModelToken::default(),
591 agility_sdk,
592 }
593 }
594
595 /// Takes the given options, modifies them based on the environment variables, and returns the result.
596 ///
597 /// This is equivalent to calling `with_env` on every field.
598 #[must_use]
599 pub fn with_env(self) -> Self {
600 let shader_compiler = self.shader_compiler.with_env();
601 let presentation_system = self.presentation_system.with_env();
602 let latency_waitable_object = self.latency_waitable_object.with_env();
603 let agility_sdk = self
604 .agility_sdk
605 .map(|s| s.with_env())
606 .or_else(Dx12AgilitySDK::from_env);
607 Self {
608 shader_compiler,
609 presentation_system,
610 latency_waitable_object,
611 force_shader_model: ForceShaderModelToken::default(),
612 agility_sdk,
613 }
614 }
615}
616
617/// Configuration for the noop backend.
618///
619/// Part of [`BackendOptions`].
620#[derive(Clone, Debug, Default)]
621pub struct NoopBackendOptions {
622 /// Whether to allow the noop backend to be used.
623 ///
624 /// The noop backend stubs out all operations except for buffer creation and mapping, so
625 /// it must not be used when not expected. Therefore, it will not be used unless explicitly
626 /// enabled.
627 pub enable: bool,
628
629 /// Specify the reported limits values. If `None`, reports maximally permissive limits.
630 pub limits: Option<crate::Limits>,
631
632 /// Specify the reported feature support. If `None`, reports support for all features.
633 pub features: Option<crate::Features>,
634
635 /// Specify the reported device type. If `None`, uses [`crate::DeviceType::Other`].
636 pub device_type: Option<crate::DeviceType>,
637
638 /// Specify the reported minimum subgroup size.
639 pub subgroup_min_size: Option<u32>,
640
641 /// Specify the reported maximum subgroup size.
642 pub subgroup_max_size: Option<u32>,
643}
644
645impl NoopBackendOptions {
646 /// Enable the noop backend.
647 pub fn enabled() -> Self {
648 Self {
649 enable: true,
650 ..Default::default()
651 }
652 }
653
654 /// Choose whether the noop backend is enabled from the environment.
655 ///
656 /// It will be enabled if the environment variable `WGPU_NOOP_BACKEND` has the value `1`
657 /// and not otherwise. Future versions may assign other meanings to other values.
658 #[must_use]
659 pub fn from_env_or_default() -> Self {
660 Self {
661 enable: Self::enable_from_env().unwrap_or(false),
662 ..Default::default()
663 }
664 }
665
666 /// Takes the given options, modifies them based on the environment variables, and returns the
667 /// result.
668 ///
669 /// See [`from_env_or_default()`](Self::from_env_or_default) for the interpretation.
670 #[must_use]
671 pub fn with_env(self) -> Self {
672 Self {
673 enable: Self::enable_from_env().unwrap_or(self.enable),
674 ..self
675 }
676 }
677
678 fn enable_from_env() -> Option<bool> {
679 let value = crate::env::var("WGPU_NOOP_BACKEND")?;
680 match value.as_str() {
681 "1" => Some(true),
682 "0" => Some(false),
683 _ => None,
684 }
685 }
686}
687
688#[derive(Clone, Debug, Default, Copy, PartialEq, Eq)]
689/// Selects which kind of swapchain to use on DX12.
690pub enum Dx12SwapchainKind {
691 /// Use a DXGI swapchain made directly from the window's HWND.
692 ///
693 /// This does not support transparency but has better support from developer tooling from RenderDoc.
694 #[default]
695 DxgiFromHwnd,
696 /// Use a DXGI swapchain made from a DirectComposition visual made automatically from the window's HWND.
697 ///
698 /// This creates a single [`IDCompositionVisual`] over the entire window that is used by the `Surface`.
699 /// If a user wants to manage the composition tree themselves, they should create their own device and
700 /// composition, and pass the relevant visual down via [`SurfaceTargetUnsafe::CompositionVisual`][CV].
701 ///
702 /// This supports transparent windows, but does not have support from RenderDoc.
703 ///
704 /// [`IDCompositionVisual`]: https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nn-dcomp-idcompositionvisual
705 #[doc = link_to_wgpu_docs!(["CV"]: "struct.SurfaceTargetUnsafe.html#variant.CompositionVisual")]
706 DxgiFromVisual,
707}
708
709impl Dx12SwapchainKind {
710 /// Choose which presentation system to use from the environment variable `WGPU_DX12_PRESENTATION_SYSTEM`.
711 ///
712 /// Valid values, case insensitive:
713 /// - `DxgiFromVisual` or `Visual`
714 /// - `DxgiFromHwnd` or `Hwnd` for [`Self::DxgiFromHwnd`]
715 #[must_use]
716 pub fn from_env() -> Option<Self> {
717 let value = crate::env::var("WGPU_DX12_PRESENTATION_SYSTEM")
718 .as_deref()?
719 .to_lowercase();
720 match value.as_str() {
721 "dxgifromvisual" | "visual" => Some(Self::DxgiFromVisual),
722 "dxgifromhwnd" | "hwnd" => Some(Self::DxgiFromHwnd),
723 _ => None,
724 }
725 }
726
727 /// Takes the given presentation system, modifies it based on the `WGPU_DX12_PRESENTATION_SYSTEM` environment variable, and returns the result.
728 ///
729 /// See [`from_env`](Self::from_env) for more information.
730 #[must_use]
731 pub fn with_env(self) -> Self {
732 if let Some(presentation_system) = Self::from_env() {
733 presentation_system
734 } else {
735 self
736 }
737 }
738}
739
740/// DXC shader model.
741#[derive(Clone, Debug)]
742#[allow(missing_docs)]
743pub enum DxcShaderModel {
744 V6_0,
745 V6_1,
746 V6_2,
747 V6_3,
748 V6_4,
749 V6_5,
750 V6_6,
751 V6_7,
752 V6_8,
753 V6_9,
754}
755
756impl DxcShaderModel {
757 /// Get the shader model supported by a certain DXC version.
758 pub fn from_dxc_version(major: u32, minor: u32) -> Self {
759 // DXC version roughly has corresponded to shader model so far, where DXC 1.x supports SM 6.x.
760 // See discussion in https://discord.com/channels/590611987420020747/996417435374714920/1471234702206701650.
761 // Presumably DXC 2.0 and up will still support shader model 6.9.
762 if major > 1 {
763 Self::V6_9
764 } else {
765 Self::from_parts(6, minor)
766 }
767 }
768
769 /// Parse a DxcShaderModel from its version components.
770 pub fn from_parts(major: u32, minor: u32) -> Self {
771 if major > 6 || minor > 8 {
772 Self::V6_9
773 } else {
774 match minor {
775 0 => DxcShaderModel::V6_0,
776 1 => DxcShaderModel::V6_1,
777 2 => DxcShaderModel::V6_2,
778 3 => DxcShaderModel::V6_3,
779 4 => DxcShaderModel::V6_4,
780 5 => DxcShaderModel::V6_5,
781 6 => DxcShaderModel::V6_6,
782 7 => DxcShaderModel::V6_7,
783 8 => DxcShaderModel::V6_8,
784 9 => DxcShaderModel::V6_9,
785 // > 6.9
786 _ => DxcShaderModel::V6_9,
787 }
788 }
789 }
790}
791
792/// Selects which DX12 shader compiler to use.
793#[derive(Clone, Debug, Default)]
794pub enum Dx12Compiler {
795 /// The Fxc compiler (default) is old, slow and unmaintained.
796 ///
797 /// However, it doesn't require any additional .dlls to be shipped with the application.
798 Fxc,
799 /// The Dxc compiler is new, fast and maintained.
800 ///
801 /// However, it requires `dxcompiler.dll` to be shipped with the application.
802 /// These files can be downloaded from <https://github.com/microsoft/DirectXShaderCompiler/releases>.
803 ///
804 /// Minimum supported version: [v1.8.2502](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.8.2502)
805 ///
806 /// It also requires WDDM 2.1 (Windows 10 version 1607).
807 DynamicDxc {
808 /// Path to `dxcompiler.dll`.
809 dxc_path: String,
810 },
811 /// The statically-linked variant of Dxc.
812 ///
813 /// The `static-dxc` feature is required for this setting to be used successfully on DX12.
814 /// Not available on `windows-aarch64-pc-*` targets.
815 StaticDxc,
816 /// Use statically-linked DXC if available. Otherwise check for dynamically linked DXC on the PATH. Finally, fallback to FXC.
817 #[default]
818 Auto,
819}
820
821impl Dx12Compiler {
822 /// Helper function to construct a `DynamicDxc` variant with default paths.
823 ///
824 /// The dll must support at least shader model 6.8.
825 pub fn default_dynamic_dxc() -> Self {
826 Self::DynamicDxc {
827 dxc_path: String::from("dxcompiler.dll"),
828 }
829 }
830
831 /// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`.
832 ///
833 /// Valid values, case insensitive:
834 /// - `Fxc`
835 /// - `Dxc` or `DynamicDxc`
836 /// - `StaticDxc`
837 #[must_use]
838 pub fn from_env() -> Option<Self> {
839 let env = crate::env::var("WGPU_DX12_COMPILER")?;
840 env.parse().map_err(|expected_msg| {
841 log::warn!(
842 "Unknown value `{env:?}` for `WGPU_DX12_COMPILER` environment variable. {expected_msg}"
843 )
844 })
845 .ok()
846 }
847
848 /// Takes the given compiler, modifies it based on the `WGPU_DX12_COMPILER` environment variable, and returns the result.
849 ///
850 /// See `from_env` for more information.
851 #[must_use]
852 pub fn with_env(self) -> Self {
853 if let Some(compiler) = Self::from_env() {
854 compiler
855 } else {
856 self
857 }
858 }
859}
860
861impl FromStr for Dx12Compiler {
862 type Err = &'static str;
863
864 fn from_str(value: &str) -> Result<Self, Self::Err> {
865 Ok(match value.to_lowercase().as_str() {
866 "dxc" | "dynamicdxc" => Self::default_dynamic_dxc(),
867 "staticdxc" => Self::StaticDxc,
868 "fxc" => Self::Fxc,
869 "auto" => Self::Auto,
870 path => Self::DynamicDxc {
871 dxc_path: path.to_string(),
872 },
873 })
874 }
875}
876
877/// Whether and how to use a waitable handle obtained from `GetFrameLatencyWaitableObject`.
878#[derive(Clone, Debug, Default)]
879pub enum Dx12UseFrameLatencyWaitableObject {
880 /// Do not obtain a waitable handle and do not wait for it. The swapchain will
881 /// be created without the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag.
882 None,
883 /// Obtain a waitable handle and wait for it before acquiring the next swapchain image.
884 #[default]
885 Wait,
886 /// Create the swapchain with the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag and
887 /// obtain a waitable handle, but do not wait for it before acquiring the next swapchain image.
888 /// This is useful if the application wants to wait for the waitable object itself.
889 DontWait,
890}
891
892impl Dx12UseFrameLatencyWaitableObject {
893 /// Choose whether to use a frame latency waitable object from the environment variable `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT`.
894 ///
895 /// Valid values, case insensitive:
896 /// - `None`
897 /// - `Wait`
898 /// - `DontWait`
899 #[must_use]
900 pub fn from_env() -> Option<Self> {
901 let value = crate::env::var("WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT")
902 .as_deref()?
903 .to_lowercase();
904 match value.as_str() {
905 "none" => Some(Self::None),
906 "wait" => Some(Self::Wait),
907 "dontwait" => Some(Self::DontWait),
908 _ => None,
909 }
910 }
911
912 /// Takes the given setting, modifies it based on the `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT` environment variable, and returns the result.
913 ///
914 /// See `from_env` for more information.
915 #[must_use]
916 pub fn with_env(self) -> Self {
917 if let Some(compiler) = Self::from_env() {
918 compiler
919 } else {
920 self
921 }
922 }
923}
924
925/// Selects which OpenGL ES 3 minor version to request.
926///
927/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11.
928#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
929pub enum Gles3MinorVersion {
930 /// No explicit minor version is requested, the driver automatically picks the highest available.
931 #[default]
932 Automatic,
933
934 /// Request an ES 3.0 context.
935 Version0,
936
937 /// Request an ES 3.1 context.
938 Version1,
939
940 /// Request an ES 3.2 context.
941 Version2,
942}
943
944impl Gles3MinorVersion {
945 /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`.
946 ///
947 /// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive.
948 ///
949 /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
950 #[must_use]
951 pub fn from_env() -> Option<Self> {
952 let value = crate::env::var("WGPU_GLES_MINOR_VERSION")
953 .as_deref()?
954 .to_lowercase();
955 match value.as_str() {
956 "automatic" => Some(Self::Automatic),
957 "0" => Some(Self::Version0),
958 "1" => Some(Self::Version1),
959 "2" => Some(Self::Version2),
960 _ => None,
961 }
962 }
963
964 /// Takes the given compiler, modifies it based on the `WGPU_GLES_MINOR_VERSION` environment variable, and returns the result.
965 ///
966 /// See `from_env` for more information.
967 #[must_use]
968 pub fn with_env(self) -> Self {
969 if let Some(compiler) = Self::from_env() {
970 compiler
971 } else {
972 self
973 }
974 }
975}
976
977/// Dictate the behavior of fences in OpenGL.
978#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
979pub enum GlFenceBehavior {
980 /// Fences in OpenGL behave normally. If you don't know what to pick, this is what you want.
981 #[default]
982 Normal,
983 /// Fences in OpenGL are short-circuited to always return `true` immediately.
984 ///
985 /// This solves a very specific issue that arose due to a bug in wgpu-core that made
986 /// many WebGL programs work when they "shouldn't" have. If you have code that is trying
987 /// to call `device.poll(wgpu::PollType::Wait)` on WebGL, you need to enable this option
988 /// for the "Wait" to behave how you would expect.
989 ///
990 /// Previously all `poll(Wait)` acted like the OpenGL fences were signalled even if they weren't.
991 /// See <https://github.com/gfx-rs/wgpu/issues/4589> for more information.
992 ///
993 /// When this is set `Queue::on_completed_work_done` will always return the next time the device
994 /// is maintained, not when the work is actually done on the GPU.
995 AutoFinish,
996}
997
998impl GlFenceBehavior {
999 /// Returns true if the fence behavior is `AutoFinish`.
1000 pub fn is_auto_finish(&self) -> bool {
1001 matches!(self, Self::AutoFinish)
1002 }
1003
1004 /// Returns true if the fence behavior is `Normal`.
1005 pub fn is_normal(&self) -> bool {
1006 matches!(self, Self::Normal)
1007 }
1008
1009 /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GL_FENCE_BEHAVIOR`.
1010 ///
1011 /// Possible values are `Normal` or `AutoFinish`. Case insensitive.
1012 ///
1013 /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
1014 #[must_use]
1015 pub fn from_env() -> Option<Self> {
1016 let value = crate::env::var("WGPU_GL_FENCE_BEHAVIOR")
1017 .as_deref()?
1018 .to_lowercase();
1019 match value.as_str() {
1020 "normal" => Some(Self::Normal),
1021 "autofinish" => Some(Self::AutoFinish),
1022 _ => None,
1023 }
1024 }
1025
1026 /// Takes the given compiler, modifies it based on the `WGPU_GL_FENCE_BEHAVIOR` environment variable, and returns the result.
1027 ///
1028 /// See `from_env` for more information.
1029 #[must_use]
1030 pub fn with_env(self) -> Self {
1031 if let Some(fence) = Self::from_env() {
1032 fence
1033 } else {
1034 self
1035 }
1036 }
1037}