wgpu_types/instance.rs
1//! Types for dealing with Instances
2
3use alloc::string::String;
4
5use crate::Backends;
6
7#[cfg(doc)]
8use crate::{Backend, DownlevelFlags};
9
10/// Options for creating an instance.
11#[derive(Clone, Debug)]
12pub struct InstanceDescriptor {
13 /// Which `Backends` to enable.
14 pub backends: Backends,
15 /// Flags to tune the behavior of the instance.
16 pub flags: InstanceFlags,
17 /// Options the control the behavior of various backends.
18 pub backend_options: BackendOptions,
19}
20
21impl Default for InstanceDescriptor {
22 fn default() -> Self {
23 Self {
24 backends: Backends::all(),
25 flags: InstanceFlags::default(),
26 backend_options: BackendOptions::default(),
27 }
28 }
29}
30
31impl InstanceDescriptor {
32 /// Choose instance options entirely from environment variables.
33 ///
34 /// This is equivalent to calling `from_env` on every field.
35 #[must_use]
36 pub fn from_env_or_default() -> Self {
37 Self::default().with_env()
38 }
39
40 /// Takes the given options, modifies them based on the environment variables, and returns the result.
41 ///
42 /// This is equivalent to calling `with_env` on every field.
43 #[must_use]
44 pub fn with_env(self) -> Self {
45 let backends = self.backends.with_env();
46 let flags = self.flags.with_env();
47 let backend_options = self.backend_options.with_env();
48 Self {
49 backends,
50 flags,
51 backend_options,
52 }
53 }
54}
55
56bitflags::bitflags! {
57 /// Instance debugging flags.
58 ///
59 /// These are not part of the WebGPU standard.
60 ///
61 /// Defaults to enabling debugging-related flags if the build configuration has `debug_assertions`.
62 #[repr(transparent)]
63 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
64 pub struct InstanceFlags: u32 {
65 /// Generate debug information in shaders and objects.
66 ///
67 /// When `Self::from_env()` is used takes value from `WGPU_DEBUG` environment variable.
68 const DEBUG = 1 << 0;
69 /// Enable validation, if possible.
70 ///
71 /// When `Self::from_env()` is used takes value from `WGPU_VALIDATION` environment variable.
72 const VALIDATION = 1 << 1;
73 /// Don't pass labels to wgpu-hal.
74 ///
75 /// When `Self::from_env()` is used takes value from `WGPU_DISCARD_HAL_LABELS` environment variable.
76 const DISCARD_HAL_LABELS = 1 << 2;
77 /// Whether wgpu should expose adapters that run on top of non-compliant adapters.
78 ///
79 /// Turning this on might mean that some of the functionality provided by the wgpu
80 /// adapter/device is not working or is broken. It could be that all the functionality
81 /// wgpu currently exposes works but we can't tell for sure since we have no additional
82 /// transparency into what is working and what is not on the underlying adapter.
83 ///
84 /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version
85 /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing.
86 ///
87 /// When `Self::from_env()` is used takes value from `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` environment variable.
88 const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3;
89 /// Enable GPU-based validation. Implies [`Self::VALIDATION`]. Currently, this only changes
90 /// behavior on the DX12 and Vulkan backends.
91 ///
92 /// Supported platforms:
93 ///
94 /// - D3D12; called ["GPU-based validation", or
95 /// "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation)
96 /// - Vulkan, via the `VK_LAYER_KHRONOS_validation` layer; called ["GPU-Assisted
97 /// Validation"](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/e45aeb85079e0835694cb8f03e6681fd18ae72c9/docs/gpu_validation.md#gpu-assisted-validation)
98 ///
99 /// When `Self::from_env()` is used takes value from `WGPU_GPU_BASED_VALIDATION` environment variable.
100 const GPU_BASED_VALIDATION = 1 << 4;
101
102 /// Validate indirect buffer content prior to issuing indirect draws/dispatches.
103 ///
104 /// When `Self::from_env()` is used takes value from `WGPU_VALIDATION_INDIRECT_CALL` environment variable.
105 const VALIDATION_INDIRECT_CALL = 1 << 5;
106
107 /// Enable automatic timestamp normalization. This means that in [`CommandEncoder::resolve_query_set`][rqs],
108 /// the timestamps will automatically be normalized to be in nanoseconds instead of the raw timestamp values.
109 ///
110 /// This is disabled by default because it introduces a compute shader into the resolution of query sets.
111 ///
112 /// This can be useful for users that need to read timestamps on the gpu, as the normalization
113 /// can be a hassle to do manually. When this is enabled, the timestamp period returned by the queue
114 /// will always be `1.0`.
115 ///
116 /// [rqs]: ../wgpu/struct.CommandEncoder.html#method.resolve_query_set
117 const AUTOMATIC_TIMESTAMP_NORMALIZATION = 1 << 6;
118 }
119}
120
121impl Default for InstanceFlags {
122 fn default() -> Self {
123 Self::from_build_config()
124 }
125}
126
127impl InstanceFlags {
128 /// Enable recommended debugging and validation flags.
129 #[must_use]
130 pub fn debugging() -> Self {
131 InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::VALIDATION_INDIRECT_CALL
132 }
133
134 /// Enable advanced debugging and validation flags (potentially very slow).
135 #[must_use]
136 pub fn advanced_debugging() -> Self {
137 Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION
138 }
139
140 /// Infer decent defaults from the build type.
141 ///
142 /// If `cfg!(debug_assertions)` is true, then this returns [`Self::debugging()`].
143 /// Otherwise, it returns [`Self::empty()`].
144 #[must_use]
145 pub fn from_build_config() -> Self {
146 if cfg!(debug_assertions) {
147 return InstanceFlags::debugging();
148 }
149
150 InstanceFlags::VALIDATION_INDIRECT_CALL
151 }
152
153 /// Derive defaults from environment variables. See [`Self::with_env()`] for more information.
154 #[must_use]
155 pub fn from_env_or_default() -> Self {
156 Self::default().with_env()
157 }
158
159 /// Takes the given flags, modifies them based on the environment variables, and returns the result.
160 ///
161 /// - If an environment variable is set to anything but "0", the corresponding flag is set.
162 /// - If the value is "0", the flag is unset.
163 /// - If the environment variable is not present, then the flag retains its initial value.
164 ///
165 /// For example `let flags = InstanceFlags::debugging().with_env();` with `WGPU_VALIDATION=0`
166 /// does not contain [`InstanceFlags::VALIDATION`].
167 ///
168 /// The environment variables are named after the flags prefixed with "WGPU_". For example:
169 /// - `WGPU_DEBUG`
170 /// - `WGPU_VALIDATION`
171 /// - `WGPU_DISCARD_HAL_LABELS`
172 /// - `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER`
173 /// - `WGPU_GPU_BASED_VALIDATION`
174 /// - `WGPU_VALIDATION_INDIRECT_CALL`
175 #[must_use]
176 pub fn with_env(mut self) -> Self {
177 fn env(key: &str) -> Option<bool> {
178 crate::env::var(key).map(|s| match s.as_str() {
179 "0" => false,
180 _ => true,
181 })
182 }
183
184 if let Some(bit) = env("WGPU_VALIDATION") {
185 self.set(Self::VALIDATION, bit);
186 }
187
188 if let Some(bit) = env("WGPU_DEBUG") {
189 self.set(Self::DEBUG, bit);
190 }
191 if let Some(bit) = env("WGPU_DISCARD_HAL_LABELS") {
192 self.set(Self::DISCARD_HAL_LABELS, bit);
193 }
194 if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") {
195 self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit);
196 }
197 if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") {
198 self.set(Self::GPU_BASED_VALIDATION, bit);
199 }
200 if let Some(bit) = env("WGPU_VALIDATION_INDIRECT_CALL") {
201 self.set(Self::VALIDATION_INDIRECT_CALL, bit);
202 }
203
204 self
205 }
206}
207
208/// Options that are passed to a given backend.
209///
210/// Part of [`InstanceDescriptor`].
211#[derive(Clone, Debug, Default)]
212pub struct BackendOptions {
213 /// Options for the OpenGL/OpenGLES backend, [`Backend::Gl`].
214 pub gl: GlBackendOptions,
215 /// Options for the DX12 backend, [`Backend::Dx12`].
216 pub dx12: Dx12BackendOptions,
217 /// Options for the noop backend, [`Backend::Noop`].
218 pub noop: NoopBackendOptions,
219}
220
221impl BackendOptions {
222 /// Choose backend options by calling `from_env` on every field.
223 ///
224 /// See those methods for more information.
225 #[must_use]
226 pub fn from_env_or_default() -> Self {
227 Self {
228 gl: GlBackendOptions::from_env_or_default(),
229 dx12: Dx12BackendOptions::from_env_or_default(),
230 noop: NoopBackendOptions::from_env_or_default(),
231 }
232 }
233
234 /// Takes the given options, modifies them based on the environment variables, and returns the result.
235 ///
236 /// This is equivalent to calling `with_env` on every field.
237 #[must_use]
238 pub fn with_env(self) -> Self {
239 Self {
240 gl: self.gl.with_env(),
241 dx12: self.dx12.with_env(),
242 noop: self.noop.with_env(),
243 }
244 }
245}
246
247/// Configuration for the OpenGL/OpenGLES backend.
248///
249/// Part of [`BackendOptions`].
250#[derive(Clone, Debug, Default)]
251pub struct GlBackendOptions {
252 /// Which OpenGL ES 3 minor version to request, if using OpenGL ES.
253 pub gles_minor_version: Gles3MinorVersion,
254 /// Behavior of OpenGL fences. Affects how `on_completed_work_done` and `device.poll` behave.
255 pub fence_behavior: GlFenceBehavior,
256}
257
258impl GlBackendOptions {
259 /// Choose OpenGL backend options by calling `from_env` on every field.
260 ///
261 /// See those methods for more information.
262 #[must_use]
263 pub fn from_env_or_default() -> Self {
264 let gles_minor_version = Gles3MinorVersion::from_env().unwrap_or_default();
265 Self {
266 gles_minor_version,
267 fence_behavior: GlFenceBehavior::Normal,
268 }
269 }
270
271 /// Takes the given options, modifies them based on the environment variables, and returns the result.
272 ///
273 /// This is equivalent to calling `with_env` on every field.
274 #[must_use]
275 pub fn with_env(self) -> Self {
276 let gles_minor_version = self.gles_minor_version.with_env();
277 let short_circuit_fences = self.fence_behavior.with_env();
278 Self {
279 gles_minor_version,
280 fence_behavior: short_circuit_fences,
281 }
282 }
283}
284
285/// Configuration for the DX12 backend.
286///
287/// Part of [`BackendOptions`].
288#[derive(Clone, Debug, Default)]
289pub struct Dx12BackendOptions {
290 /// Which DX12 shader compiler to use.
291 pub shader_compiler: Dx12Compiler,
292}
293
294impl Dx12BackendOptions {
295 /// Choose DX12 backend options by calling `from_env` on every field.
296 ///
297 /// See those methods for more information.
298 #[must_use]
299 pub fn from_env_or_default() -> Self {
300 let compiler = Dx12Compiler::from_env().unwrap_or_default();
301 Self {
302 shader_compiler: compiler,
303 }
304 }
305
306 /// Takes the given options, modifies them based on the environment variables, and returns the result.
307 ///
308 /// This is equivalent to calling `with_env` on every field.
309 #[must_use]
310 pub fn with_env(self) -> Self {
311 let shader_compiler = self.shader_compiler.with_env();
312 Self { shader_compiler }
313 }
314}
315
316/// Configuration for the noop backend.
317///
318/// Part of [`BackendOptions`].
319#[derive(Clone, Debug, Default)]
320pub struct NoopBackendOptions {
321 /// Whether to allow the noop backend to be used.
322 ///
323 /// The noop backend stubs out all operations except for buffer creation and mapping, so
324 /// it must not be used when not expected. Therefore, it will not be used unless explicitly
325 /// enabled.
326 pub enable: bool,
327}
328
329impl NoopBackendOptions {
330 /// Choose whether the noop backend is enabled from the environment.
331 ///
332 /// It will be enabled if the environment variable `WGPU_NOOP_BACKEND` has the value `1`
333 /// and not otherwise. Future versions may assign other meanings to other values.
334 #[must_use]
335 pub fn from_env_or_default() -> Self {
336 Self {
337 enable: Self::enable_from_env().unwrap_or(false),
338 }
339 }
340
341 /// Takes the given options, modifies them based on the environment variables, and returns the
342 /// result.
343 ///
344 /// See [`from_env_or_default()`](Self::from_env_or_default) for the interpretation.
345 #[must_use]
346 pub fn with_env(self) -> Self {
347 Self {
348 enable: Self::enable_from_env().unwrap_or(self.enable),
349 }
350 }
351
352 fn enable_from_env() -> Option<bool> {
353 let value = crate::env::var("WGPU_NOOP_BACKEND")?;
354 match value.as_str() {
355 "1" => Some(true),
356 "0" => Some(false),
357 _ => None,
358 }
359 }
360}
361
362/// DXC shader model.
363#[derive(Clone, Debug)]
364#[allow(missing_docs)]
365pub enum DxcShaderModel {
366 V6_0,
367 V6_1,
368 V6_2,
369 V6_3,
370 V6_4,
371 V6_5,
372 V6_6,
373 V6_7,
374}
375
376/// Selects which DX12 shader compiler to use.
377///
378/// If the `DynamicDxc` option is selected, but `dxcompiler.dll` and `dxil.dll` files aren't found,
379/// then this will fall back to the Fxc compiler at runtime and log an error.
380#[derive(Clone, Debug, Default)]
381pub enum Dx12Compiler {
382 /// The Fxc compiler (default) is old, slow and unmaintained.
383 ///
384 /// However, it doesn't require any additional .dlls to be shipped with the application.
385 #[default]
386 Fxc,
387 /// The Dxc compiler is new, fast and maintained.
388 ///
389 /// However, it requires both `dxcompiler.dll` and `dxil.dll` to be shipped with the application.
390 /// These files can be downloaded from <https://github.com/microsoft/DirectXShaderCompiler/releases>.
391 ///
392 /// Minimum supported version: [v1.5.2010](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.5.2010)
393 ///
394 /// It also requires WDDM 2.1 (Windows 10 version 1607).
395 DynamicDxc {
396 /// Path to `dxcompiler.dll`.
397 dxc_path: String,
398 /// Path to `dxil.dll`.
399 dxil_path: String,
400 /// Maximum shader model the given dll supports.
401 max_shader_model: DxcShaderModel,
402 },
403 /// The statically-linked variant of Dxc.
404 ///
405 /// The `static-dxc` feature is required for this setting to be used successfully on DX12.
406 /// Not available on `windows-aarch64-pc-*` targets.
407 StaticDxc,
408}
409
410impl Dx12Compiler {
411 /// Helper function to construct a `DynamicDxc` variant with default paths.
412 ///
413 /// The dll must support at least shader model 6.5.
414 pub fn default_dynamic_dxc() -> Self {
415 Self::DynamicDxc {
416 dxc_path: String::from("dxcompiler.dll"),
417 dxil_path: String::from("dxil.dll"),
418 max_shader_model: DxcShaderModel::V6_5,
419 }
420 }
421
422 /// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`.
423 ///
424 /// Valid values, case insensitive:
425 /// - `Fxc`
426 /// - `Dxc` or `DynamicDxc`
427 /// - `StaticDxc`
428 #[must_use]
429 pub fn from_env() -> Option<Self> {
430 let value = crate::env::var("WGPU_DX12_COMPILER")
431 .as_deref()?
432 .to_lowercase();
433 match value.as_str() {
434 "dxc" | "dynamicdxc" => Some(Self::default_dynamic_dxc()),
435 "staticdxc" => Some(Self::StaticDxc),
436 "fxc" => Some(Self::Fxc),
437 _ => None,
438 }
439 }
440
441 /// Takes the given compiler, modifies it based on the `WGPU_DX12_COMPILER` environment variable, and returns the result.
442 ///
443 /// See `from_env` for more information.
444 #[must_use]
445 pub fn with_env(self) -> Self {
446 if let Some(compiler) = Self::from_env() {
447 compiler
448 } else {
449 self
450 }
451 }
452}
453
454/// Selects which OpenGL ES 3 minor version to request.
455///
456/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11.
457#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
458pub enum Gles3MinorVersion {
459 /// No explicit minor version is requested, the driver automatically picks the highest available.
460 #[default]
461 Automatic,
462
463 /// Request an ES 3.0 context.
464 Version0,
465
466 /// Request an ES 3.1 context.
467 Version1,
468
469 /// Request an ES 3.2 context.
470 Version2,
471}
472
473impl Gles3MinorVersion {
474 /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`.
475 ///
476 /// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive.
477 ///
478 /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
479 #[must_use]
480 pub fn from_env() -> Option<Self> {
481 let value = crate::env::var("WGPU_GLES_MINOR_VERSION")
482 .as_deref()?
483 .to_lowercase();
484 match value.as_str() {
485 "automatic" => Some(Self::Automatic),
486 "0" => Some(Self::Version0),
487 "1" => Some(Self::Version1),
488 "2" => Some(Self::Version2),
489 _ => None,
490 }
491 }
492
493 /// Takes the given compiler, modifies it based on the `WGPU_GLES_MINOR_VERSION` environment variable, and returns the result.
494 ///
495 /// See `from_env` for more information.
496 #[must_use]
497 pub fn with_env(self) -> Self {
498 if let Some(compiler) = Self::from_env() {
499 compiler
500 } else {
501 self
502 }
503 }
504}
505
506/// Dictate the behavior of fences in OpenGL.
507#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
508pub enum GlFenceBehavior {
509 /// Fences in OpenGL behave normally. If you don't know what to pick, this is what you want.
510 #[default]
511 Normal,
512 /// Fences in OpenGL are short-circuited to always return `true` immediately.
513 ///
514 /// This solves a very specific issue that arose due to a bug in wgpu-core that made
515 /// many WebGL programs work when they "shouldn't" have. If you have code that is trying
516 /// to call `device.poll(wgpu::PollType::Wait)` on WebGL, you need to enable this option
517 /// for the "Wait" to behave how you would expect.
518 ///
519 /// Previously all `poll(Wait)` acted like the OpenGL fences were signalled even if they weren't.
520 /// See <https://github.com/gfx-rs/wgpu/issues/4589> for more information.
521 ///
522 /// When this is set `Queue::on_completed_work_done` will always return the next time the device
523 /// is maintained, not when the work is actually done on the GPU.
524 AutoFinish,
525}
526
527impl GlFenceBehavior {
528 /// Returns true if the fence behavior is `AutoFinish`.
529 pub fn is_auto_finish(&self) -> bool {
530 matches!(self, Self::AutoFinish)
531 }
532
533 /// Returns true if the fence behavior is `Normal`.
534 pub fn is_normal(&self) -> bool {
535 matches!(self, Self::Normal)
536 }
537
538 /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GL_FENCE_BEHAVIOR`.
539 ///
540 /// Possible values are `Normal` or `AutoFinish`. Case insensitive.
541 ///
542 /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
543 #[must_use]
544 pub fn from_env() -> Option<Self> {
545 let value = crate::env::var("WGPU_GL_FENCE_BEHAVIOR")
546 .as_deref()?
547 .to_lowercase();
548 match value.as_str() {
549 "normal" => Some(Self::Normal),
550 "autofinish" => Some(Self::AutoFinish),
551 _ => None,
552 }
553 }
554
555 /// Takes the given compiler, modifies it based on the `WGPU_GL_FENCE_BEHAVIOR` environment variable, and returns the result.
556 ///
557 /// See `from_env` for more information.
558 #[must_use]
559 pub fn with_env(self) -> Self {
560 if let Some(fence) = Self::from_env() {
561 fence
562 } else {
563 self
564 }
565 }
566}