wgpu_types/instance.rs
1//! Types for dealing with Instances.
2
3use macro_rules_attribute::derive;
4
5use crate::{link_to_wgpu_docs, Backends, ConstDefault};
6
7#[cfg(doc)]
8use crate::{Backend, DownlevelFlags};
9
10/// A [`raw_window_handle::HasDisplayHandle`] that can be shared across threads and has no borrows.
11///
12/// This blanket trait is automatically implemented for all objects that qualify.
13pub trait WgpuHasDisplayHandle:
14 raw_window_handle::HasDisplayHandle + core::fmt::Debug + Send + Sync + 'static
15{
16}
17impl<T: raw_window_handle::HasDisplayHandle + core::fmt::Debug + Send + Sync + 'static>
18 WgpuHasDisplayHandle for T
19{
20}
21
22/// Options for creating an instance.
23///
24/// If you want to allow control of instance settings via environment variables, call any of the
25/// `*from_env()` functions or [`InstanceDescriptor::with_env()`]. Each type within this descriptor
26/// has its own equivalent methods, so you can select which options you want to expose to influence
27/// from the environment.
28#[derive(Debug)]
29pub struct InstanceDescriptor {
30 /// Which [`Backends`] to enable.
31 ///
32 /// [`Backends::BROWSER_WEBGPU`] has an additional effect:
33 /// If it is set and a [`navigator.gpu`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/gpu)
34 /// object is present, this instance will *only* be able to create WebGPU adapters.
35 ///
36 /// ⚠️ On some browsers this check is insufficient to determine whether WebGPU is supported,
37 /// as the browser may define the `navigator.gpu` object, but be unable to create any WebGPU adapters.
38 /// For targeting _both_ WebGPU & WebGL, it is recommended to use [`crate::util::new_instance_with_webgpu_detection`](../wgpu/util/fn.new_instance_with_webgpu_detection.html).
39 ///
40 /// If you instead want to force use of WebGL, either disable the `webgpu` compile-time feature
41 /// or don't include the [`Backends::BROWSER_WEBGPU`] flag in this field.
42 /// If it is set and WebGPU support is *not* detected, the instance will use `wgpu-core`
43 /// to create adapters, meaning that if the `webgl` feature is enabled, it is able to create
44 /// a WebGL adapter.
45 pub backends: Backends,
46 /// Flags to tune the behavior of the instance.
47 pub flags: InstanceFlags,
48 /// Memory budget thresholds used by some backends.
49 pub memory_budget_thresholds: MemoryBudgetThresholds,
50 /// Options for configuring the behavior of specific backends.
51 pub backend_options: crate::BackendOptions,
52 /// System platform or compositor connection to connect this `Instance` to.
53 ///
54 /// If not [`None`], it is invalid to pass a different [`raw_window_handle::HasDisplayHandle`] to `create_surface()`.
55 ///
56 /// - On GLES, this is required when intending to present on the platform, especially for Wayland.
57 /// - On Vulkan, Metal and Dx12, this is currently unused.
58 ///
59 /// When used with `winit`, callers are expected to pass its [`OwnedDisplayHandle`] (created from
60 /// the `EventLoop`) here.
61 ///
62 /// [`OwnedDisplayHandle`]: https://docs.rs/winit/latest/winit/event_loop/struct.OwnedDisplayHandle.html
63 pub display: Option<alloc::boxed::Box<dyn WgpuHasDisplayHandle>>,
64}
65
66impl InstanceDescriptor {
67 /// The default instance options, without display handle.
68 #[must_use]
69 pub fn new_without_display_handle() -> Self {
70 Self {
71 backends: Default::default(),
72 flags: Default::default(),
73 memory_budget_thresholds: Default::default(),
74 backend_options: Default::default(),
75 display: None,
76 }
77 }
78
79 /// The default instance options, with display handle.
80 #[must_use]
81 pub fn new_with_display_handle(display: alloc::boxed::Box<dyn WgpuHasDisplayHandle>) -> Self {
82 Self::new_without_display_handle().with_display_handle(display)
83 }
84
85 /// Choose instance options entirely from environment variables.
86 ///
87 /// This is equivalent to calling `from_env` on every field.
88 #[must_use]
89 pub fn new_without_display_handle_from_env() -> Self {
90 Self::new_without_display_handle().with_env()
91 }
92
93 /// Choose instance options entirely from environment variables, while including a display handle.
94 ///
95 /// This is equivalent to calling `from_env` on every field.
96 #[must_use]
97 pub fn new_with_display_handle_from_env(
98 display: alloc::boxed::Box<dyn WgpuHasDisplayHandle>,
99 ) -> Self {
100 // Self::new_without_display_handle_from_env().with_display_handle(display)
101 Self::new_with_display_handle(display).with_env()
102 }
103
104 /// Takes the given options, modifies them based on the environment variables, and returns the result.
105 ///
106 /// This is equivalent to calling `with_env` on every field.
107 #[must_use]
108 pub fn with_env(self) -> Self {
109 let backends = self.backends.with_env();
110 let flags = self.flags.with_env();
111 let backend_options = self.backend_options.with_env();
112 Self {
113 backends,
114 flags,
115 memory_budget_thresholds: MemoryBudgetThresholds::default(),
116 backend_options,
117 display: self.display,
118 }
119 }
120
121 /// Appends the given `display` object to the descriptor.
122 #[must_use]
123 pub fn with_display_handle(self, display: alloc::boxed::Box<dyn WgpuHasDisplayHandle>) -> Self {
124 Self {
125 display: Some(display),
126 ..self
127 }
128 }
129}
130
131bitflags::bitflags! {
132 /// Instance debugging flags.
133 ///
134 /// These are not part of the WebGPU standard.
135 ///
136 /// Defaults to enabling debugging-related flags if the build configuration has `debug_assertions`.
137 #[repr(transparent)]
138 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
139 pub struct InstanceFlags: u32 {
140 /// Generate debug information in shaders and objects.
141 ///
142 /// When `Self::from_env()` is used takes value from `WGPU_DEBUG` environment variable.
143 const DEBUG = 1 << 0;
144 /// Enable validation in the backend API, if possible:
145 ///
146 /// - On the Direct3D `dx12` backend, this calls [`ID3D12Debug::EnableDebugLayer`][dx12].
147 ///
148 /// - On the Vulkan backend, this enables the [Vulkan Validation Layer][vvl].
149 ///
150 /// - On the `gles` backend driving Windows OpenGL, this enables [debug
151 /// output][gl:do], effectively calling `glEnable(GL_DEBUG_OUTPUT)`.
152 ///
153 /// - On non-Windows `gles` backends, this calls
154 /// [`eglDebugMessageControlKHR`][gl:dm] to enable all debugging messages.
155 /// If the GLES implementation is ANGLE running on Vulkan, this also
156 /// enables the Vulkan validation layers by setting
157 /// [`EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED`][gl:av].
158 ///
159 /// When `Self::from_env()` is used, this bit is set if the `WGPU_VALIDATION`
160 /// environment variable has any value but "0".
161 ///
162 /// [dx12]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12sdklayers/nf-d3d12sdklayers-id3d12debug-enabledebuglayer
163 /// [vvl]: https://github.com/KhronosGroup/Vulkan-ValidationLayers
164 /// [gl:dm]: https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_debug.txt
165 /// [gl:do]: https://www.khronos.org/opengl/wiki/Debug_Output
166 /// [gl:av]: https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/EGL_ANGLE_platform_angle.txt
167 const VALIDATION = 1 << 1;
168 /// Don't pass labels to wgpu-hal.
169 ///
170 /// When `Self::from_env()` is used takes value from `WGPU_DISCARD_HAL_LABELS` environment variable.
171 const DISCARD_HAL_LABELS = 1 << 2;
172 /// Whether wgpu should expose adapters that run on top of non-compliant adapters.
173 ///
174 /// Turning this on might mean that some of the functionality provided by the wgpu
175 /// adapter/device is not working or is broken. It could be that all the functionality
176 /// wgpu currently exposes works but we can't tell for sure since we have no additional
177 /// transparency into what is working and what is not on the underlying adapter.
178 ///
179 /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version
180 /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing.
181 ///
182 /// This flag controls whether adapters that don't meet the *native*
183 /// API's own compliance requirements are returned, while
184 /// [`Self::STRICT_WEBGPU_COMPLIANCE`] controls whether adapters that
185 /// can't fully satisfy the *WebGPU v1* spec are excluded.
186 ///
187 /// When `Self::from_env()` is used takes value from `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` environment variable.
188 const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3;
189 /// Enable GPU-based validation. Implies [`Self::VALIDATION`]. Currently, this only changes
190 /// behavior on the DX12 and Vulkan backends.
191 ///
192 /// Supported platforms:
193 ///
194 /// - D3D12; called ["GPU-based validation", or
195 /// "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation)
196 /// - Vulkan, via the `VK_LAYER_KHRONOS_validation` layer; called ["GPU-Assisted
197 /// Validation"](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/e45aeb85079e0835694cb8f03e6681fd18ae72c9/docs/gpu_validation.md#gpu-assisted-validation)
198 ///
199 /// When `Self::from_env()` is used takes value from `WGPU_GPU_BASED_VALIDATION` environment variable.
200 const GPU_BASED_VALIDATION = 1 << 4;
201
202 /// Validate indirect buffer content prior to issuing indirect draws/dispatches.
203 ///
204 /// This validation will transform indirect calls into no-ops if they are not valid:
205 ///
206 /// - When calling `dispatch_workgroups_indirect`, all 3 indirect arguments encoded in the buffer
207 /// must be less than the `max_compute_workgroups_per_dimension` device limit.
208 /// - When calling `draw_indirect`/`draw_indexed_indirect`/`multi_draw_indirect`/`multi_draw_indexed_indirect`:
209 /// - If `Features::INDIRECT_FIRST_INSTANCE` is not enabled on the device, the `first_instance` indirect argument must be 0.
210 /// - The `first_instance` & `instance_count` indirect arguments must form a range that fits within all bound vertex buffers with `step_mode` set to `Instance`.
211 /// - When calling `draw_indirect`/`multi_draw_indirect`:
212 /// - The `first_vertex` & `vertex_count` indirect arguments must form a range that fits within all bound vertex buffers with `step_mode` set to `Vertex`.
213 /// - When calling `draw_indexed_indirect`/`multi_draw_indexed_indirect`:
214 /// - The `first_index` & `index_count` indirect arguments must form a range that fits within the bound index buffer.
215 ///
216 /// __Behavior is undefined if this validation is disabled and the rules above are not satisfied.__
217 ///
218 /// Disabling this will also cause the following built-ins to not report the right values on the D3D12 backend:
219 ///
220 /// - the 3 components of `@builtin(num_workgroups)` will be 0
221 /// - the value of `@builtin(vertex_index)` will not take into account the value of the `first_vertex`/`base_vertex` argument present in the indirect buffer
222 /// - the value of `@builtin(instance_index)` will not take into account the value of the `first_instance` argument present in the indirect buffer
223 ///
224 /// When `Self::from_env()` is used takes value from `WGPU_VALIDATION_INDIRECT_CALL` environment variable.
225 const VALIDATION_INDIRECT_CALL = 1 << 5;
226
227 /// Enable automatic timestamp normalization. This means that in [`CommandEncoder::resolve_query_set`][rqs],
228 /// the timestamps will automatically be normalized to be in nanoseconds instead of the raw timestamp values.
229 ///
230 /// This is disabled by default because it introduces a compute shader into the resolution of query sets.
231 ///
232 /// This can be useful for users that need to read timestamps on the gpu, as the normalization
233 /// can be a hassle to do manually. When this is enabled, the timestamp period returned by the queue
234 /// will always be `1.0`.
235 ///
236 #[doc = link_to_wgpu_docs!(["rqs"]: "struct.CommandEncoder.html#method.resolve_query_set")]
237 const AUTOMATIC_TIMESTAMP_NORMALIZATION = 1 << 6;
238
239 /// Restrict the available feature set to the one defined by the WebGPU specification.
240 ///
241 /// When `Self::from_env()` is used takes value from `WGPU_STRICT_WEBGPU_COMPLIANCE` environment variable.
242 const STRICT_WEBGPU_COMPLIANCE = 1 << 7;
243 }
244}
245
246impl Default for InstanceFlags {
247 fn default() -> Self {
248 Self::from_build_config()
249 }
250}
251
252impl InstanceFlags {
253 /// Enable recommended debugging and validation flags.
254 #[must_use]
255 pub fn debugging() -> Self {
256 InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::VALIDATION_INDIRECT_CALL
257 }
258
259 /// Enable advanced debugging and validation flags (potentially very slow).
260 #[must_use]
261 pub fn advanced_debugging() -> Self {
262 Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION
263 }
264
265 /// Infer decent defaults from the build type.
266 ///
267 /// If `cfg!(debug_assertions)` is true, then this returns [`Self::debugging()`].
268 /// Otherwise, it returns [`Self::empty()`].
269 #[must_use]
270 pub fn from_build_config() -> Self {
271 if cfg!(debug_assertions) {
272 return InstanceFlags::debugging();
273 }
274
275 InstanceFlags::VALIDATION_INDIRECT_CALL
276 }
277
278 /// Derive defaults from environment variables. See [`Self::with_env()`] for more information.
279 #[must_use]
280 pub fn from_env_or_default() -> Self {
281 Self::default().with_env()
282 }
283
284 /// Takes the given flags, modifies them based on the environment variables, and returns the result.
285 ///
286 /// - If an environment variable is set to anything but "0", the corresponding flag is set.
287 /// - If the value is "0", the flag is unset.
288 /// - If the environment variable is not present, then the flag retains its initial value.
289 ///
290 /// For example `let flags = InstanceFlags::debugging().with_env();` with `WGPU_VALIDATION=0`
291 /// does not contain [`InstanceFlags::VALIDATION`].
292 ///
293 /// The environment variables are named after the flags prefixed with "WGPU_". For example:
294 /// - `WGPU_DEBUG`
295 /// - `WGPU_VALIDATION`
296 /// - `WGPU_DISCARD_HAL_LABELS`
297 /// - `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER`
298 /// - `WGPU_GPU_BASED_VALIDATION`
299 /// - `WGPU_VALIDATION_INDIRECT_CALL`
300 /// - `WGPU_STRICT_WEBGPU_COMPLIANCE`
301 #[must_use]
302 pub fn with_env(mut self) -> Self {
303 fn env(key: &str) -> Option<bool> {
304 crate::env::var(key).map(|s| match s.as_str() {
305 "0" => false,
306 _ => true,
307 })
308 }
309
310 if let Some(bit) = env("WGPU_VALIDATION") {
311 self.set(Self::VALIDATION, bit);
312 }
313
314 if let Some(bit) = env("WGPU_DEBUG") {
315 self.set(Self::DEBUG, bit);
316 }
317 if let Some(bit) = env("WGPU_DISCARD_HAL_LABELS") {
318 self.set(Self::DISCARD_HAL_LABELS, bit);
319 }
320 if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") {
321 self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit);
322 }
323 if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") {
324 self.set(Self::GPU_BASED_VALIDATION, bit);
325 }
326 if let Some(bit) = env("WGPU_VALIDATION_INDIRECT_CALL") {
327 self.set(Self::VALIDATION_INDIRECT_CALL, bit);
328 }
329 if let Some(bit) = env("WGPU_STRICT_WEBGPU_COMPLIANCE") {
330 self.set(Self::STRICT_WEBGPU_COMPLIANCE, bit);
331 }
332
333 self
334 }
335}
336
337/// Memory budget thresholds used by backends to try to avoid high memory pressure situations.
338///
339/// Currently only the D3D12 and (optionally) Vulkan backends support these options.
340#[derive(ConstDefault!, Clone, Debug, Copy, Eq, PartialEq)]
341pub struct MemoryBudgetThresholds {
342 /// Threshold at which texture, buffer, query set and acceleration structure creation will start to return OOM errors.
343 /// This is a percent of the memory budget reported by native APIs.
344 ///
345 /// If not specified, resource creation might still return OOM errors.
346 pub for_resource_creation: Option<u8>,
347
348 /// Threshold at which devices will become lost due to memory pressure.
349 /// This is a percent of the memory budget reported by native APIs.
350 ///
351 /// If not specified, devices might still become lost due to memory pressure.
352 pub for_device_loss: Option<u8>,
353}