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