wgpu_types/features.rs
1use crate::{link_to_wgpu_docs, link_to_wgpu_item, VertexFormat};
2#[cfg(feature = "serde")]
3use alloc::fmt;
4use alloc::vec::Vec;
5#[cfg(feature = "serde")]
6use bitflags::parser::{ParseError, ParseHex, WriteHex};
7#[cfg(feature = "serde")]
8use bitflags::Bits;
9use bitflags::Flags;
10#[cfg(feature = "serde")]
11use core::mem::size_of;
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15pub use webgpu_impl::*;
16mod webgpu_impl {
17 //! Constant values for [`super::FeaturesWebGPU`], separated so they can be picked up by
18 //! `cbindgen` in `mozilla-central` (where Firefox is developed).
19 #![allow(missing_docs)]
20
21 #[doc(hidden)]
22 pub const WEBGPU_FEATURE_DEPTH_CLIP_CONTROL: u64 = 1 << 0;
23
24 #[doc(hidden)]
25 pub const WEBGPU_FEATURE_DEPTH32FLOAT_STENCIL8: u64 = 1 << 1;
26
27 #[doc(hidden)]
28 pub const WEBGPU_FEATURE_TEXTURE_COMPRESSION_BC: u64 = 1 << 2;
29
30 #[doc(hidden)]
31 pub const WEBGPU_FEATURE_TEXTURE_COMPRESSION_BC_SLICED_3D: u64 = 1 << 3;
32
33 #[doc(hidden)]
34 pub const WEBGPU_FEATURE_TEXTURE_COMPRESSION_ETC2: u64 = 1 << 4;
35
36 #[doc(hidden)]
37 pub const WEBGPU_FEATURE_TEXTURE_COMPRESSION_ASTC: u64 = 1 << 5;
38
39 #[doc(hidden)]
40 pub const WEBGPU_FEATURE_TEXTURE_COMPRESSION_ASTC_SLICED_3D: u64 = 1 << 6;
41
42 #[doc(hidden)]
43 pub const WEBGPU_FEATURE_TIMESTAMP_QUERY: u64 = 1 << 7;
44
45 #[doc(hidden)]
46 pub const WEBGPU_FEATURE_INDIRECT_FIRST_INSTANCE: u64 = 1 << 8;
47
48 #[doc(hidden)]
49 pub const WEBGPU_FEATURE_SHADER_F16: u64 = 1 << 9;
50
51 #[doc(hidden)]
52 pub const WEBGPU_FEATURE_RG11B10UFLOAT_RENDERABLE: u64 = 1 << 10;
53
54 #[doc(hidden)]
55 pub const WEBGPU_FEATURE_BGRA8UNORM_STORAGE: u64 = 1 << 11;
56
57 #[doc(hidden)]
58 pub const WEBGPU_FEATURE_FLOAT32_FILTERABLE: u64 = 1 << 12;
59
60 #[doc(hidden)]
61 pub const WEBGPU_FEATURE_DUAL_SOURCE_BLENDING: u64 = 1 << 13;
62
63 #[doc(hidden)]
64 pub const WEBGPU_FEATURE_CLIP_DISTANCES: u64 = 1 << 14;
65
66 #[doc(hidden)]
67 pub const WEBGPU_FEATURE_IMMEDIATES: u64 = 1 << 15;
68}
69
70macro_rules! bitflags_array_impl {
71 ($impl_name:ident $inner_name:ident $name:ident $op:tt $($struct_names:ident)*) => (
72 impl core::ops::$impl_name for $name {
73 type Output = Self;
74
75 #[inline]
76 fn $inner_name(self, other: Self) -> Self {
77 Self {
78 $($struct_names: self.$struct_names $op other.$struct_names,)*
79 }
80 }
81 }
82 )
83}
84
85macro_rules! bitflags_array_impl_assign {
86 ($impl_name:ident $inner_name:ident $name:ident $op:tt $($struct_names:ident)*) => (
87 impl core::ops::$impl_name for $name {
88 #[inline]
89 fn $inner_name(&mut self, other: Self) {
90 $(self.$struct_names $op other.$struct_names;)*
91 }
92 }
93 )
94}
95
96macro_rules! bit_array_impl {
97 ($impl_name:ident $inner_name:ident $name:ident $op:tt) => (
98 impl core::ops::$impl_name for $name {
99 type Output = Self;
100
101 #[inline]
102 fn $inner_name(mut self, other: Self) -> Self {
103 for (inner, other) in self.0.iter_mut().zip(other.0.iter()) {
104 *inner $op *other;
105 }
106 self
107 }
108 }
109 )
110}
111
112macro_rules! bitflags_independent_two_arg {
113 ($(#[$meta:meta])* $func_name:ident $($struct_names:ident)*) => (
114 $(#[$meta])*
115 pub const fn $func_name(self, other:Self) -> Self {
116 Self { $($struct_names: self.$struct_names.$func_name(other.$struct_names),)* }
117 }
118 )
119}
120
121// For the most part this macro should not be modified, most configuration should be possible
122// without changing this macro.
123/// Macro for creating sets of bitflags, we need this because there are almost more flags than bits
124/// in a u64, we can't use a u128 because of FFI, and the number of flags is increasing.
125macro_rules! bitflags_array {
126 (
127 $(#[$outer:meta])*
128 pub struct $name:ident: [$T:ty; $Len:expr];
129
130 $(
131 $(#[$bit_outer:meta])*
132 $vis:vis struct $inner_name:ident $lower_inner_name:ident {
133 $(
134 $(#[$inner:ident $($args:tt)*])*
135 const $Flag:tt = $value:expr;
136 )*
137 }
138 )*
139 ) => {
140 $(
141 bitflags::bitflags! {
142 $(#[$bit_outer])*
143 $vis struct $inner_name: $T {
144 $(
145 $(#[$inner $($args)*])*
146 const $Flag = $value;
147 )*
148 }
149 }
150 )*
151
152 $(#[$outer])*
153 pub struct $name {
154 $(
155 #[allow(missing_docs)]
156 $vis $lower_inner_name: $inner_name,
157 )*
158 }
159
160 /// Bits from `Features` in array form
161 #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
162 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
163 pub struct FeatureBits(pub [$T; $Len]);
164
165 bitflags_array_impl! { BitOr bitor $name | $($lower_inner_name)* }
166 bitflags_array_impl! { BitAnd bitand $name & $($lower_inner_name)* }
167 bitflags_array_impl! { BitXor bitxor $name ^ $($lower_inner_name)* }
168 impl core::ops::Not for $name {
169 type Output = Self;
170
171 #[inline]
172 fn not(self) -> Self {
173 Self {
174 $($lower_inner_name: !self.$lower_inner_name,)*
175 }
176 }
177 }
178 bitflags_array_impl! { Sub sub $name - $($lower_inner_name)* }
179
180 #[cfg(feature = "serde")]
181 impl Serialize for $name {
182 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
183 where
184 S: serde::Serializer,
185 {
186 bitflags::serde::serialize(self, serializer)
187 }
188 }
189
190 #[cfg(feature = "serde")]
191 impl<'de> Deserialize<'de> for $name {
192 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
193 where
194 D: serde::Deserializer<'de>,
195 {
196 bitflags::serde::deserialize(deserializer)
197 }
198 }
199
200 impl core::fmt::Display for $name {
201 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
202 let mut iter = self.iter_names();
203 // simple look ahead
204 let mut next = iter.next();
205 while let Some((name, _)) = next {
206 f.write_str(name)?;
207 next = iter.next();
208 if next.is_some() {
209 f.write_str(" | ")?;
210 }
211 }
212 Ok(())
213 }
214 }
215
216 bitflags_array_impl_assign! { BitOrAssign bitor_assign $name |= $($lower_inner_name)* }
217 bitflags_array_impl_assign! { BitAndAssign bitand_assign $name &= $($lower_inner_name)* }
218 bitflags_array_impl_assign! { BitXorAssign bitxor_assign $name ^= $($lower_inner_name)* }
219
220 bit_array_impl! { BitOr bitor FeatureBits |= }
221 bit_array_impl! { BitAnd bitand FeatureBits &= }
222 bit_array_impl! { BitXor bitxor FeatureBits ^= }
223
224 impl core::ops::Not for FeatureBits {
225 type Output = Self;
226
227 #[inline]
228 fn not(self) -> Self {
229 let [$($lower_inner_name,)*] = self.0;
230 Self([$(!$lower_inner_name,)*])
231 }
232 }
233
234 #[cfg(feature = "serde")]
235 impl WriteHex for FeatureBits {
236 fn write_hex<W: fmt::Write>(&self, mut writer: W) -> fmt::Result {
237 let [$($lower_inner_name,)*] = self.0;
238 let mut wrote = false;
239 let mut stager = alloc::string::String::with_capacity(size_of::<$T>() * 2);
240 // we don't want to write it if it's just zero as there may be multiple zeros
241 // resulting in something like "00" being written out. We do want to write it if
242 // there has already been something written though.
243 $(if ($lower_inner_name != 0) || wrote {
244 // First we write to a staging string, then we add any zeros (e.g if #1
245 // is f and a u8 and #2 is a then the two combined would be f0a which requires
246 // a 0 inserted)
247 $lower_inner_name.write_hex(&mut stager)?;
248 if (stager.len() != size_of::<$T>() * 2) && wrote {
249 let zeros_to_write = (size_of::<$T>() * 2) - stager.len();
250 for _ in 0..zeros_to_write {
251 writer.write_char('0')?
252 }
253 }
254 writer.write_str(&stager)?;
255 stager.clear();
256 wrote = true;
257 })*
258 if !wrote {
259 writer.write_str("0")?;
260 }
261 Ok(())
262 }
263 }
264
265 #[cfg(feature = "serde")]
266 impl ParseHex for FeatureBits {
267 fn parse_hex(input: &str) -> Result<Self, ParseError> {
268
269 let mut unset = Self::EMPTY;
270 let mut end = input.len();
271 if end == 0 {
272 return Err(ParseError::empty_flag())
273 }
274 // we iterate starting at the least significant places and going up
275 for (idx, _) in [$(stringify!($lower_inner_name),)*].iter().enumerate().rev() {
276 // A byte is two hex places - u8 (1 byte) = 0x00 (2 hex places).
277 let checked_start = end.checked_sub(size_of::<$T>() * 2);
278 let start = checked_start.unwrap_or(0);
279
280 let cur_input = &input[start..end];
281 unset.0[idx] = <$T>::from_str_radix(cur_input, 16)
282 .map_err(|_|ParseError::invalid_hex_flag(cur_input))?;
283
284 end = start;
285
286 if let None = checked_start {
287 break;
288 }
289 }
290 Ok(unset)
291 }
292 }
293
294 impl bitflags::Bits for FeatureBits {
295 const EMPTY: Self = $name::empty().bits();
296
297 const ALL: Self = $name::all().bits();
298 }
299
300 impl Flags for $name {
301 const FLAGS: &'static [bitflags::Flag<Self>] = $name::FLAGS;
302
303 type Bits = FeatureBits;
304
305 fn bits(&self) -> FeatureBits {
306 FeatureBits([
307 $(self.$lower_inner_name.bits(),)*
308 ])
309 }
310
311 fn from_bits_retain(bits: FeatureBits) -> Self {
312 let [$($lower_inner_name,)*] = bits.0;
313 Self {
314 $($lower_inner_name: $inner_name::from_bits_retain($lower_inner_name),)*
315 }
316 }
317
318 fn empty() -> Self {
319 Self::empty()
320 }
321
322 fn all() -> Self {
323 Self::all()
324 }
325 }
326
327 impl $name {
328 pub(crate) const FLAGS: &'static [bitflags::Flag<Self>] = &[
329 $(
330 $(
331 bitflags::Flag::new(stringify!($Flag), $name::$Flag),
332 )*
333 )*
334 ];
335
336 /// Gets the set flags as a container holding an array of bits.
337 pub const fn bits(&self) -> FeatureBits {
338 FeatureBits([
339 $(self.$lower_inner_name.bits(),)*
340 ])
341 }
342
343 /// Returns self with no flags set.
344 pub const fn empty() -> Self {
345 Self {
346 $($lower_inner_name: $inner_name::empty(),)*
347 }
348 }
349
350 /// Returns self with all flags set.
351 pub const fn all() -> Self {
352 Self {
353 $($lower_inner_name: $inner_name::all(),)*
354 }
355 }
356
357 /// Whether all the bits set in `other` are all set in `self`
358 pub const fn contains(self, other:Self) -> bool {
359 // we need an annoying true to catch the last && >:(
360 $(self.$lower_inner_name.contains(other.$lower_inner_name) &&)* true
361 }
362
363 /// Returns whether any bit set in `self` matched any bit set in `other`.
364 pub const fn intersects(self, other:Self) -> bool {
365 $(self.$lower_inner_name.intersects(other.$lower_inner_name) ||)* false
366 }
367
368 /// Returns whether there is no flag set.
369 pub const fn is_empty(self) -> bool {
370 $(self.$lower_inner_name.is_empty() &&)* true
371 }
372
373 /// Returns whether the struct has all flags set.
374 pub const fn is_all(self) -> bool {
375 $(self.$lower_inner_name.is_all() &&)* true
376 }
377
378 bitflags_independent_two_arg! {
379 /// Bitwise or - `self | other`
380 union $($lower_inner_name)*
381 }
382
383 bitflags_independent_two_arg! {
384 /// Bitwise and - `self & other`
385 intersection $($lower_inner_name)*
386 }
387
388 bitflags_independent_two_arg! {
389 /// Bitwise and of the complement of other - `self & !other`
390 difference $($lower_inner_name)*
391 }
392
393 bitflags_independent_two_arg! {
394 /// Bitwise xor - `self ^ other`
395 symmetric_difference $($lower_inner_name)*
396 }
397
398 /// Bitwise not - `!self`
399 pub const fn complement(self) -> Self {
400 Self {
401 $($lower_inner_name: self.$lower_inner_name.complement(),)*
402 }
403 }
404
405 /// Calls [`Self::insert`] if `set` is true and otherwise calls [`Self::remove`].
406 pub fn set(&mut self, other:Self, set: bool) {
407 $(self.$lower_inner_name.set(other.$lower_inner_name, set);)*
408 }
409
410 /// Inserts specified flag(s) into self
411 pub fn insert(&mut self, other:Self) {
412 $(self.$lower_inner_name.insert(other.$lower_inner_name);)*
413 }
414
415 /// Removes specified flag(s) from self
416 pub fn remove(&mut self, other:Self) {
417 $(self.$lower_inner_name.remove(other.$lower_inner_name);)*
418 }
419
420 /// Toggles specified flag(s) in self
421 pub fn toggle(&mut self, other:Self) {
422 $(self.$lower_inner_name.toggle(other.$lower_inner_name);)*
423 }
424
425 /// Takes in [`FeatureBits`] and returns None if there are invalid bits or otherwise Self with
426 /// those bits set
427 pub const fn from_bits(bits:FeatureBits) -> Option<Self> {
428 let [$($lower_inner_name,)*] = bits.0;
429 // The ? operator does not work in a const context.
430 Some(Self {
431 $(
432 $lower_inner_name: match $inner_name::from_bits($lower_inner_name) {
433 Some(some) => some,
434 None => return None,
435 },
436 )*
437 })
438 }
439
440 /// Takes in [`FeatureBits`] and returns Self with only valid bits (all other bits removed)
441 pub const fn from_bits_truncate(bits:FeatureBits) -> Self {
442 let [$($lower_inner_name,)*] = bits.0;
443 Self { $($lower_inner_name: $inner_name::from_bits_truncate($lower_inner_name),)* }
444 }
445
446 /// Takes in [`FeatureBits`] and returns Self with all bits that were set without removing
447 /// invalid bits
448 pub const fn from_bits_retain(bits:FeatureBits) -> Self {
449 let [$($lower_inner_name,)*] = bits.0;
450 Self { $($lower_inner_name: $inner_name::from_bits_retain($lower_inner_name),)* }
451 }
452
453 /// Takes in a name and returns Self if it matches or none if the name does not match
454 /// the name of any of the flags. Name is capitalisation dependent.
455 pub fn from_name(name: &str) -> Option<Self> {
456 match name {
457 $(
458 $(
459 stringify!($Flag) => Some(Self::$Flag),
460 )*
461 )*
462 _ => None,
463 }
464 }
465
466 /// Combines the features from the internal flags into the entire features struct
467 pub fn from_internal_flags($($lower_inner_name: $inner_name,)*) -> Self {
468 Self {
469 $($lower_inner_name,)*
470 }
471 }
472
473 /// Returns an iterator over the set flags.
474 pub const fn iter(&self) -> bitflags::iter::Iter<$name> {
475 bitflags::iter::Iter::__private_const_new($name::FLAGS, *self, *self)
476 }
477
478 /// Returns an iterator over the set flags and their names.
479 pub const fn iter_names(&self) -> bitflags::iter::IterNames<$name> {
480 bitflags::iter::IterNames::__private_const_new($name::FLAGS, *self, *self)
481 }
482
483 $(
484 $(
485 $(#[$inner $($args)*])*
486 // We need this for structs with only a member.
487 #[allow(clippy::needless_update)]
488 pub const $Flag: Self = Self {
489 $lower_inner_name: $inner_name::from_bits_truncate($value),
490 ..Self::empty()
491 };
492 )*
493 )*
494 }
495
496 $(
497 impl From<$inner_name> for Features {
498 // We need this for structs with only a member.
499 #[allow(clippy::needless_update)]
500 fn from($lower_inner_name: $inner_name) -> Self {
501 Self {
502 $lower_inner_name,
503 ..Self::empty()
504 }
505 }
506 }
507 )*
508 };
509}
510
511impl From<FeatureBits> for Features {
512 fn from(value: FeatureBits) -> Self {
513 Self::from_bits_retain(value)
514 }
515}
516
517impl From<Features> for FeatureBits {
518 fn from(value: Features) -> Self {
519 value.bits()
520 }
521}
522
523bitflags_array! {
524 /// Features that are not guaranteed to be supported.
525 ///
526 /// These are either part of the webgpu standard, or are extension features supported by
527 /// wgpu when targeting native.
528 ///
529 /// If you want to use a feature, you need to first verify that the adapter supports
530 /// the feature. If the adapter does not support the feature, requesting a device with it enabled
531 /// will panic.
532 ///
533 /// Corresponds to [WebGPU `GPUFeatureName`](
534 /// https://gpuweb.github.io/gpuweb/#enumdef-gpufeaturename).
535 #[repr(C)]
536 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
537 pub struct Features: [u64; 2];
538
539 /// Features that are not guaranteed to be supported.
540 ///
541 /// Most of these are native-only extension features supported by wgpu only when targeting
542 /// native. A few are intended to align with a proposed WebGPU extension, and one
543 /// (`EXTERNAL_TEXTURE`) controls WebGPU-specified behavior that is not optional in the
544 /// standard, but that we don't want to make a [`crate::DownlevelFlags`] until the
545 /// implementation is more complete. For all features see [`Features`].
546 ///
547 /// If you want to use a feature, you need to first verify that the adapter supports
548 /// the feature. If the adapter does not support the feature, requesting a device with it enabled
549 /// will panic.
550 ///
551 /// Corresponds to [WebGPU `GPUFeatureName`](
552 /// https://gpuweb.github.io/gpuweb/#enumdef-gpufeaturename).
553 #[repr(transparent)]
554 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
555 #[cfg_attr(feature = "serde", serde(transparent))]
556 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
557 pub struct FeaturesWGPU features_wgpu {
558 /// Allows shaders to use f32 atomic load, store, add, sub, and exchange.
559 ///
560 /// Supported platforms:
561 /// - Metal (with MSL 3.0+ and Apple7+/Mac2)
562 /// - Vulkan (with [VK_EXT_shader_atomic_float])
563 ///
564 /// This is a native only feature.
565 ///
566 /// [VK_EXT_shader_atomic_float]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_atomic_float.html
567 const SHADER_FLOAT32_ATOMIC = 1 << 0;
568
569 // The features starting with a ? are features that might become part of the spec or
570 // at the very least we can implement as native features; since they should cover all
571 // possible formats and capabilities across backends.
572 //
573 // ? const FORMATS_TIER_1 = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3837)
574 // ? const RW_STORAGE_TEXTURE_TIER_1 = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3838)
575 // ? const NORM16_FILTERABLE = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3839)
576 // ? const NORM16_RESOLVE = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3839)
577 // ? const FLOAT32_BLENDABLE = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3556)
578 // ? const 32BIT_FORMAT_MULTISAMPLE = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3844)
579 // ? const 32BIT_FORMAT_RESOLVE = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3844)
580 // ? const TEXTURE_COMPRESSION_ASTC_HDR = 1 << ??; (https://github.com/gpuweb/gpuweb/issues/3856)
581 // TEXTURE_FORMAT_16BIT_NORM & TEXTURE_COMPRESSION_ASTC_HDR will most likely become web features as well
582 // TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES might not be necessary if we have all the texture features implemented
583
584 // Texture Formats:
585
586 /// Enables normalized `16-bit` texture formats.
587 ///
588 /// Supported platforms:
589 /// - Vulkan
590 /// - DX12
591 /// - Metal
592 ///
593 /// This is a native only feature.
594 const TEXTURE_FORMAT_16BIT_NORM = 1 << 1;
595 /// Enables ASTC HDR family of compressed textures.
596 ///
597 /// Compressed textures sacrifice some quality in exchange for significantly reduced
598 /// bandwidth usage.
599 ///
600 /// Support for this feature guarantees availability of [`TextureUsages::COPY_SRC | TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING`] for ASTC formats with the HDR channel type.
601 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] may enable additional usages.
602 ///
603 /// Supported Platforms:
604 /// - Metal
605 /// - Vulkan
606 /// - OpenGL
607 ///
608 /// This is a native only feature.
609 const TEXTURE_COMPRESSION_ASTC_HDR = 1 << 2;
610 /// Enables device specific texture format features.
611 ///
612 /// See `TextureFormatFeatures` for a listing of the features in question.
613 ///
614 /// By default only texture format properties as defined by the WebGPU specification are allowed.
615 /// Enabling this feature flag extends the features of each format to the ones supported by the current device.
616 /// Note that without this flag, read/write storage access is not allowed at all.
617 ///
618 /// This extension does not enable additional formats.
619 ///
620 /// This is a native only feature.
621 const TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES = 1 << 3;
622
623 // API:
624
625 /// Enables use of Pipeline Statistics Queries. These queries tell the count of various operations
626 /// performed between the start and stop call. Call [`RenderPass::begin_pipeline_statistics_query`] to start
627 /// a query, then call [`RenderPass::end_pipeline_statistics_query`] to stop one.
628 ///
629 /// They must be resolved using [`CommandEncoder::resolve_query_set`] into a buffer.
630 /// The rules on how these resolve into buffers are detailed in the documentation for [`PipelineStatisticsTypes`].
631 ///
632 /// Supported Platforms:
633 /// - Vulkan
634 /// - DX12
635 ///
636 /// This is a native only feature with a [proposal](https://github.com/gpuweb/gpuweb/blob/0008bd30da2366af88180b511a5d0d0c1dffbc36/proposals/pipeline-statistics-query.md) for the web.
637 ///
638 /// [`RenderPass::begin_pipeline_statistics_query`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.begin_pipeline_statistics_query
639 /// [`RenderPass::end_pipeline_statistics_query`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.end_pipeline_statistics_query
640 /// [`CommandEncoder::resolve_query_set`]: https://docs.rs/wgpu/latest/wgpu/struct.CommandEncoder.html#method.resolve_query_set
641 /// [`PipelineStatisticsTypes`]: super::PipelineStatisticsTypes
642 const PIPELINE_STATISTICS_QUERY = 1 << 4;
643 /// Allows for timestamp queries directly on command encoders.
644 ///
645 /// Implies [`Features::TIMESTAMP_QUERY`] is supported.
646 ///
647 /// Additionally allows for timestamp writes on command encoders
648 /// using [`CommandEncoder::write_timestamp`].
649 ///
650 /// Supported platforms:
651 /// - Vulkan
652 /// - DX12
653 /// - Metal
654 ///
655 /// This is a native only feature.
656 ///
657 /// [`CommandEncoder::write_timestamp`]: https://docs.rs/wgpu/latest/wgpu/struct.CommandEncoder.html#method.write_timestamp
658 const TIMESTAMP_QUERY_INSIDE_ENCODERS = 1 << 5;
659 /// Allows for timestamp queries directly on command encoders.
660 ///
661 /// Implies [`Features::TIMESTAMP_QUERY`] & [`Features::TIMESTAMP_QUERY_INSIDE_ENCODERS`] is supported.
662 ///
663 /// Additionally allows for timestamp queries to be used inside render & compute passes using:
664 /// - [`RenderPass::write_timestamp`]
665 /// - [`ComputePass::write_timestamp`]
666 ///
667 /// Supported platforms:
668 /// - Vulkan
669 /// - DX12
670 /// - Metal (AMD & Intel, not Apple GPUs)
671 ///
672 /// This is generally not available on tile-based rasterization GPUs.
673 ///
674 /// This is a native only feature with a [proposal](https://github.com/gpuweb/gpuweb/blob/0008bd30da2366af88180b511a5d0d0c1dffbc36/proposals/timestamp-query-inside-passes.md) for the web.
675 ///
676 /// [`RenderPass::write_timestamp`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPass.html#method.write_timestamp
677 /// [`ComputePass::write_timestamp`]: https://docs.rs/wgpu/latest/wgpu/struct.ComputePass.html#method.write_timestamp
678 const TIMESTAMP_QUERY_INSIDE_PASSES = 1 << 6;
679 /// Webgpu only allows the MAP_READ and MAP_WRITE buffer usage to be matched with
680 /// COPY_DST and COPY_SRC respectively. This removes this requirement.
681 ///
682 /// This is only beneficial on systems that share memory between CPU and GPU. If enabled
683 /// on a system that doesn't, this can severely hinder performance. Only use if you understand
684 /// the consequences.
685 ///
686 /// Supported platforms:
687 /// - Vulkan
688 /// - DX12
689 /// - Metal
690 ///
691 /// This is a native only feature.
692 const MAPPABLE_PRIMARY_BUFFERS = 1 << 7;
693 /// Allows the user to create uniform arrays of textures in shaders:
694 ///
695 /// ex.
696 /// - `var textures: binding_array<texture_2d<f32>, 10>` (WGSL)
697 /// - `uniform texture2D textures[10]` (GLSL)
698 ///
699 /// If [`Features::STORAGE_RESOURCE_BINDING_ARRAY`] is supported as well as this, the user
700 /// may also create uniform arrays of storage textures.
701 ///
702 /// ex.
703 /// - `var textures: array<texture_storage_2d<r32float, write>, 10>` (WGSL)
704 /// - `uniform image2D textures[10]` (GLSL)
705 ///
706 /// This capability allows them to exist and to be indexed by dynamically uniform
707 /// values.
708 ///
709 /// Supported platforms:
710 /// - DX12
711 /// - Metal (with MSL 2.0+ on macOS 10.13+)
712 /// - Vulkan
713 ///
714 /// This is a native only feature.
715 const TEXTURE_BINDING_ARRAY = 1 << 8;
716 /// Allows the user to create arrays of buffers in shaders:
717 ///
718 /// ex.
719 /// - `var<uniform> buffer_array: array<MyBuffer, 10>` (WGSL)
720 /// - `uniform myBuffer { ... } buffer_array[10]` (GLSL)
721 ///
722 /// This capability allows them to exist and to be indexed by dynamically uniform
723 /// values.
724 ///
725 /// If [`Features::STORAGE_RESOURCE_BINDING_ARRAY`] is supported as well as this, the user
726 /// may also create arrays of storage buffers.
727 ///
728 /// ex.
729 /// - `var<storage> buffer_array: array<MyBuffer, 10>` (WGSL)
730 /// - `buffer myBuffer { ... } buffer_array[10]` (GLSL)
731 ///
732 /// Supported platforms:
733 /// - Vulkan
734 ///
735 /// This is a native only feature.
736 const BUFFER_BINDING_ARRAY = 1 << 9;
737 /// Allows the user to create uniform arrays of storage buffers or textures in shaders,
738 /// if resp. [`Features::BUFFER_BINDING_ARRAY`] or [`Features::TEXTURE_BINDING_ARRAY`]
739 /// is supported.
740 ///
741 /// This capability allows them to exist and to be indexed by dynamically uniform
742 /// values.
743 ///
744 /// Supported platforms:
745 /// - Metal (with MSL 2.2+ on macOS 10.13+)
746 /// - Vulkan
747 ///
748 /// This is a native only feature.
749 const STORAGE_RESOURCE_BINDING_ARRAY = 1 << 10;
750 /// Allows shaders to index sampled texture and storage buffer resource arrays with dynamically non-uniform values:
751 ///
752 /// ex. `texture_array[vertex_data]`
753 ///
754 /// In order to use this capability, the corresponding GLSL extension must be enabled like so:
755 ///
756 /// `#extension GL_EXT_nonuniform_qualifier : require`
757 ///
758 /// and then used either as `nonuniformEXT` qualifier in variable declaration:
759 ///
760 /// ex. `layout(location = 0) nonuniformEXT flat in int vertex_data;`
761 ///
762 /// or as `nonuniformEXT` constructor:
763 ///
764 /// ex. `texture_array[nonuniformEXT(vertex_data)]`
765 ///
766 /// WGSL and HLSL do not need any extension.
767 ///
768 /// Supported platforms:
769 /// - DX12
770 /// - Metal (with MSL 2.0+ on macOS 10.13+)
771 /// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s shaderSampledImageArrayNonUniformIndexing & shaderStorageBufferArrayNonUniformIndexing feature)
772 ///
773 /// This is a native only feature.
774 const SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING = 1 << 11;
775 /// Allows shaders to index storage texture resource arrays with dynamically non-uniform values:
776 ///
777 /// ex. `texture_array[vertex_data]`
778 ///
779 /// Supported platforms:
780 /// - DX12
781 /// - Metal (with MSL 2.0+ on macOS 10.13+)
782 /// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s shaderStorageTextureArrayNonUniformIndexing feature)
783 ///
784 /// This is a native only feature.
785 const STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING = 1 << 12;
786 /// Allows the user to create bind groups containing arrays with less bindings than the BindGroupLayout.
787 ///
788 /// Supported platforms:
789 /// - Vulkan
790 /// - DX12
791 ///
792 /// This is a native only feature.
793 const PARTIALLY_BOUND_BINDING_ARRAY = 1 << 13;
794 /// Allows the user to call [`RenderPass::multi_draw_indirect_count`] and [`RenderPass::multi_draw_indexed_indirect_count`].
795 ///
796 /// This allows the use of a buffer containing the actual number of draw calls. This feature being present also implies
797 /// that all calls to [`RenderPass::multi_draw_indirect`] and [`RenderPass::multi_draw_indexed_indirect`] are not being emulated
798 /// with a series of `draw_indirect` calls.
799 ///
800 /// Supported platforms:
801 /// - DX12
802 /// - Vulkan 1.2+ (or VK_KHR_draw_indirect_count)
803 ///
804 /// This is a native only feature.
805 ///
806 #[doc = link_to_wgpu_docs!(["`RenderPass::multi_draw_indirect`"]: "struct.RenderPass.html#method.multi_draw_indirect")]
807 #[doc = link_to_wgpu_docs!(["`RenderPass::multi_draw_indexed_indirect`"]: "struct.RenderPass.html#method.multi_draw_indexed_indirect")]
808 #[doc = link_to_wgpu_docs!(["`RenderPass::multi_draw_indirect_count`"]: "struct.RenderPass.html#method.multi_draw_indirect_count")]
809 #[doc = link_to_wgpu_docs!(["`RenderPass::multi_draw_indexed_indirect_count`"]: "struct.RenderPass.html#method.multi_draw_indexed_indirect_count")]
810 const MULTI_DRAW_INDIRECT_COUNT = 1 << 15;
811 /// Allows the use of [`AddressMode::ClampToBorder`] with a border color
812 /// of [`SamplerBorderColor::Zero`].
813 ///
814 /// Supported platforms:
815 /// - DX12
816 /// - Vulkan
817 /// - Metal
818 /// - OpenGL
819 ///
820 /// This is a native only feature.
821 ///
822 /// [`AddressMode::ClampToBorder`]: super::AddressMode::ClampToBorder
823 /// [`SamplerBorderColor::Zero`]: super::SamplerBorderColor::Zero
824 const ADDRESS_MODE_CLAMP_TO_ZERO = 1 << 17;
825 /// Allows the use of [`AddressMode::ClampToBorder`] with a border color
826 /// other than [`SamplerBorderColor::Zero`].
827 ///
828 /// Supported platforms:
829 /// - DX12
830 /// - Vulkan
831 /// - Metal (macOS 10.12+ only)
832 /// - OpenGL
833 ///
834 /// This is a native only feature.
835 ///
836 /// [`AddressMode::ClampToBorder`]: super::AddressMode::ClampToBorder
837 /// [`SamplerBorderColor::Zero`]: super::SamplerBorderColor::Zero
838 const ADDRESS_MODE_CLAMP_TO_BORDER = 1 << 18;
839 /// Allows the user to set [`PolygonMode::Line`] in [`PrimitiveState::polygon_mode`]
840 ///
841 /// This allows drawing polygons/triangles as lines (wireframe) instead of filled
842 ///
843 /// Supported platforms:
844 /// - DX12
845 /// - Vulkan
846 /// - Metal
847 ///
848 /// This is a native only feature.
849 ///
850 /// [`PrimitiveState::polygon_mode`]: super::PrimitiveState
851 /// [`PolygonMode::Line`]: super::PolygonMode::Line
852 const POLYGON_MODE_LINE = 1 << 19;
853 /// Allows the user to set [`PolygonMode::Point`] in [`PrimitiveState::polygon_mode`]
854 ///
855 /// This allows only drawing the vertices of polygons/triangles instead of filled
856 ///
857 /// Supported platforms:
858 /// - Vulkan
859 ///
860 /// This is a native only feature.
861 ///
862 /// [`PrimitiveState::polygon_mode`]: super::PrimitiveState
863 /// [`PolygonMode::Point`]: super::PolygonMode::Point
864 const POLYGON_MODE_POINT = 1 << 20;
865 /// Allows the user to set a overestimation-conservative-rasterization in [`PrimitiveState::conservative`]
866 ///
867 /// Processing of degenerate triangles/lines is hardware specific.
868 /// Only triangles are supported.
869 ///
870 /// Supported platforms:
871 /// - Vulkan
872 ///
873 /// This is a native only feature.
874 ///
875 /// [`PrimitiveState::conservative`]: super::PrimitiveState::conservative
876 const CONSERVATIVE_RASTERIZATION = 1 << 21;
877 /// Enables bindings of writable storage buffers and textures visible to vertex shaders.
878 ///
879 /// Note: some (tiled-based) platforms do not support vertex shaders with any side-effects.
880 ///
881 /// Supported Platforms:
882 /// - All
883 ///
884 /// This is a native only feature.
885 const VERTEX_WRITABLE_STORAGE = 1 << 22;
886 /// Enables clear to zero for textures.
887 ///
888 /// Supported platforms:
889 /// - All
890 ///
891 /// This is a native only feature.
892 const CLEAR_TEXTURE = 1 << 23;
893 /// Enables multiview render passes and `builtin(view_index)` in vertex/mesh shaders.
894 ///
895 /// Supported platforms:
896 /// - Vulkan
897 /// - Metal
898 /// - DX12
899 /// - OpenGL (web only)
900 ///
901 /// This is a native only feature.
902 const MULTIVIEW = 1 << 26;
903 /// Enables using 64-bit types for vertex attributes.
904 ///
905 /// Requires SHADER_FLOAT64.
906 ///
907 /// Supported Platforms: N/A
908 ///
909 /// This is a native only feature.
910 const VERTEX_ATTRIBUTE_64BIT = 1 << 27;
911 /// Enables image atomic fetch add, and, xor, or, min, and max for R32Uint and R32Sint textures.
912 ///
913 /// Supported platforms:
914 /// - Vulkan
915 /// - DX12
916 /// - Metal (with MSL 3.1+)
917 ///
918 /// This is a native only feature.
919 const TEXTURE_ATOMIC = 1 << 28;
920 /// Allows for creation of textures of format [`TextureFormat::NV12`]
921 ///
922 /// Supported platforms:
923 /// - DX12
924 /// - Vulkan
925 ///
926 /// This is a native only feature.
927 ///
928 /// [`TextureFormat::NV12`]: super::TextureFormat::NV12
929 const TEXTURE_FORMAT_NV12 = 1 << 29;
930 /// Allows for creation of textures of format [`TextureFormat::P010`]
931 ///
932 /// Supported platforms:
933 /// - DX12
934 /// - Vulkan
935 ///
936 /// This is a native only feature.
937 ///
938 /// [`TextureFormat::P010`]: super::TextureFormat::P010
939 const TEXTURE_FORMAT_P010 = 1 << 30;
940
941 /// Allows for the creation and usage of `ExternalTexture`s, and bind
942 /// group layouts containing external texture `BindingType`s.
943 ///
944 /// Conceptually this should really be a [`crate::DownlevelFlags`] as
945 /// it corresponds to WebGPU's [`GPUExternalTexture`](
946 /// https://www.w3.org/TR/webgpu/#gpuexternaltexture).
947 /// However, the implementation is currently in-progress, and until it
948 /// is complete we do not want applications to ignore adapters due to
949 /// a missing downlevel flag, when they may not require this feature at
950 /// all.
951 ///
952 /// Supported platforms:
953 /// - DX12
954 /// - Metal
955 const EXTERNAL_TEXTURE = 1 << 31;
956
957 // Shader:
958
959 /// ***THIS IS EXPERIMENTAL:*** Features enabled by this may have
960 /// major bugs in it and are expected to be subject to breaking changes, suggestions
961 /// for the API exposed by this should be posted on [the ray-tracing issue](https://github.com/gfx-rs/wgpu/issues/1040)
962 ///
963 /// Allows for the creation of ray-tracing queries within shaders.
964 ///
965 /// Supported platforms:
966 /// - Vulkan
967 ///
968 /// This is a native-only feature.
969 const EXPERIMENTAL_RAY_QUERY = 1 << 32;
970 /// Enables 64-bit floating point types in SPIR-V shaders.
971 ///
972 /// Note: even when supported by GPU hardware, 64-bit floating point operations are
973 /// frequently between 16 and 64 _times_ slower than equivalent operations on 32-bit floats.
974 ///
975 /// Supported Platforms:
976 /// - Vulkan
977 ///
978 /// This is a native only feature.
979 const SHADER_F64 = 1 << 33;
980 /// Allows shaders to use i16. Not currently supported in `naga`, only available through `spirv-passthrough`.
981 ///
982 /// Supported platforms:
983 /// - Vulkan
984 ///
985 /// This is a native only feature.
986 const SHADER_I16 = 1 << 34;
987 /// Enables `builtin(primitive_index)` in fragment shaders.
988 ///
989 /// Note: enables geometry processing for pipelines using the builtin.
990 /// This may come with a significant performance impact on some hardware.
991 /// Other pipelines are not affected.
992 ///
993 /// Supported platforms:
994 /// - Vulkan
995 /// - DX12
996 /// - Metal (some)
997 /// - OpenGL (some)
998 ///
999 /// This is a native only feature.
1000 const SHADER_PRIMITIVE_INDEX = 1 << 35;
1001 /// Allows shaders to use the `early_depth_test` attribute.
1002 ///
1003 /// The attribute is applied to the fragment shader entry point. It can be used in two
1004 /// ways:
1005 ///
1006 /// 1. Force early depth/stencil tests:
1007 ///
1008 /// - `@early_depth_test(force)` (WGSL)
1009 ///
1010 /// - `layout(early_fragment_tests) in;` (GLSL)
1011 ///
1012 /// 2. Provide a conservative depth specifier that allows an additional early
1013 /// depth test under certain conditions:
1014 ///
1015 /// - `@early_depth_test(greater_equal/less_equal/unchanged)` (WGSL)
1016 ///
1017 /// - `layout(depth_<greater/less/unchanged>) out float gl_FragDepth;` (GLSL)
1018 ///
1019 /// See [`EarlyDepthTest`] for more details.
1020 ///
1021 /// Supported platforms:
1022 /// - Vulkan
1023 /// - GLES 3.1+
1024 ///
1025 /// This is a native only feature.
1026 ///
1027 /// [`EarlyDepthTest`]: https://docs.rs/naga/latest/naga/ir/enum.EarlyDepthTest.html
1028 const SHADER_EARLY_DEPTH_TEST = 1 << 36;
1029 /// Allows shaders to use i64 and u64.
1030 ///
1031 /// Supported platforms:
1032 /// - Vulkan
1033 /// - DX12 (DXC only)
1034 /// - Metal (with MSL 2.3+)
1035 ///
1036 /// This is a native only feature.
1037 const SHADER_INT64 = 1 << 37;
1038 /// Allows compute and fragment shaders to use the subgroup operation
1039 /// built-ins and perform subgroup operations (except barriers).
1040 ///
1041 /// Supported Platforms:
1042 /// - Vulkan
1043 /// - DX12
1044 /// - Metal
1045 ///
1046 /// This is a native only feature.
1047 const SUBGROUP = 1 << 38;
1048 /// Allows vertex shaders to use the subgroup operation built-ins and
1049 /// perform subgroup operations (except barriers).
1050 ///
1051 /// Supported Platforms:
1052 /// - Vulkan
1053 ///
1054 /// This is a native only feature.
1055 const SUBGROUP_VERTEX = 1 << 39;
1056 /// Allows compute shaders to use the subgroup barrier.
1057 ///
1058 /// Requires [`Features::SUBGROUP`]. Without it, enables nothing.
1059 ///
1060 /// Supported Platforms:
1061 /// - Vulkan
1062 /// - Metal
1063 ///
1064 /// This is a native only feature.
1065 const SUBGROUP_BARRIER = 1 << 40;
1066 /// Allows the use of pipeline cache objects
1067 ///
1068 /// Supported platforms:
1069 /// - Vulkan
1070 ///
1071 /// Unimplemented Platforms:
1072 /// - DX12
1073 /// - Metal
1074 const PIPELINE_CACHE = 1 << 41;
1075 /// Allows shaders to use i64 and u64 atomic min and max.
1076 ///
1077 /// Supported platforms:
1078 /// - Vulkan (with VK_KHR_shader_atomic_int64)
1079 /// - DX12 (with SM 6.6+)
1080 /// - Metal (with MSL 2.4+)
1081 ///
1082 /// This is a native only feature.
1083 const SHADER_INT64_ATOMIC_MIN_MAX = 1 << 42;
1084 /// Allows shaders to use all i64 and u64 atomic operations.
1085 ///
1086 /// Supported platforms:
1087 /// - Vulkan (with VK_KHR_shader_atomic_int64)
1088 /// - DX12 (with SM 6.6+)
1089 ///
1090 /// This is a native only feature.
1091 const SHADER_INT64_ATOMIC_ALL_OPS = 1 << 43;
1092 /// Allows using the [VK_GOOGLE_display_timing] Vulkan extension.
1093 ///
1094 /// This is used for frame pacing to reduce latency, and is generally only available on Android.
1095 ///
1096 /// This feature does not have a `wgpu`-level API, and so users of wgpu wishing
1097 /// to use this functionality must access it using various `as_hal` functions,
1098 /// primarily [`Surface::as_hal()`], to then use.
1099 ///
1100 /// Supported platforms:
1101 /// - Vulkan (with [VK_GOOGLE_display_timing])
1102 ///
1103 /// This is a native only feature.
1104 ///
1105 /// [VK_GOOGLE_display_timing]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html
1106 /// [`Surface::as_hal()`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html#method.as_hal
1107 const VULKAN_GOOGLE_DISPLAY_TIMING = 1 << 44;
1108
1109 /// Allows using the [VK_KHR_external_memory_win32] Vulkan extension.
1110 ///
1111 /// Supported platforms:
1112 /// - Vulkan (with [VK_KHR_external_memory_win32])
1113 ///
1114 /// This is a native only feature.
1115 ///
1116 /// [VK_KHR_external_memory_win32]: https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_external_memory_win32.html
1117 const VULKAN_EXTERNAL_MEMORY_WIN32 = 1 << 45;
1118
1119 /// Enables R64Uint image atomic min and max.
1120 ///
1121 /// Supported platforms:
1122 /// - Vulkan (with VK_EXT_shader_image_atomic_int64)
1123 /// - DX12 (with SM 6.6+)
1124 /// - Metal (with MSL 3.1+)
1125 ///
1126 /// This is a native only feature.
1127 const TEXTURE_INT64_ATOMIC = 1 << 46;
1128
1129 /// Allows uniform buffers to be bound as binding arrays.
1130 ///
1131 /// This allows:
1132 /// - Shaders to contain `var<uniform> buffer: binding_array<UniformBuffer>;`
1133 /// - The `count` field of `BindGroupLayoutEntry`s with `Uniform` buffers, to be set to `Some`.
1134 ///
1135 /// Supported platforms:
1136 /// - None (<https://github.com/gfx-rs/wgpu/issues/7149>)
1137 ///
1138 /// Potential Platforms:
1139 /// - DX12
1140 /// - Metal
1141 /// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s `shaderUniformBufferArrayNonUniformIndexing` feature)
1142 ///
1143 /// This is a native only feature.
1144 const UNIFORM_BUFFER_BINDING_ARRAYS = 1 << 47;
1145
1146 /// Enables mesh shaders and task shaders in mesh shader pipelines. This extension does NOT imply support for
1147 /// compiling mesh shaders at runtime. Rather, the user must use custom passthrough shaders.
1148 ///
1149 /// Supported platforms:
1150 /// - Vulkan (with [VK_EXT_mesh_shader](https://registry.khronos.org/vulkan/specs/latest/man/html/VK_EXT_mesh_shader.html))
1151 /// - DX12
1152 /// - Metal
1153 ///
1154 /// This is a native only feature.
1155 const EXPERIMENTAL_MESH_SHADER = 1 << 48;
1156
1157 /// ***THIS IS EXPERIMENTAL:*** Features enabled by this may have
1158 /// major bugs in them and are expected to be subject to breaking changes, suggestions
1159 /// for the API exposed by this should be posted on [the ray-tracing issue](https://github.com/gfx-rs/wgpu/issues/6762)
1160 ///
1161 /// Allows for returning of the hit triangle's vertex position when tracing with an
1162 /// acceleration structure marked with [`AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN`].
1163 ///
1164 /// Supported platforms:
1165 /// - Vulkan
1166 ///
1167 /// This is a native only feature
1168 ///
1169 /// [`AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN`]: super::AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN
1170 const EXPERIMENTAL_RAY_HIT_VERTEX_RETURN = 1 << 49;
1171
1172 /// Enables multiview in mesh shader pipelines
1173 ///
1174 /// Supported platforms:
1175 /// - Vulkan (with [VK_EXT_mesh_shader](https://registry.khronos.org/vulkan/specs/latest/man/html/VK_EXT_mesh_shader.html))
1176 ///
1177 /// Potential Platforms:
1178 /// - DX12
1179 /// - Metal
1180 ///
1181 /// This is a native only feature.
1182 const EXPERIMENTAL_MESH_SHADER_MULTIVIEW = 1 << 50;
1183
1184 /// Allows usage of additional vertex formats in [BlasTriangleGeometrySizeDescriptor::vertex_format]
1185 ///
1186 /// Supported platforms
1187 /// - Vulkan
1188 /// - DX12
1189 ///
1190 /// [BlasTriangleGeometrySizeDescriptor::vertex_format]: super::BlasTriangleGeometrySizeDescriptor
1191 const EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS = 1 << 51;
1192
1193 /// Enables creating shaders from passthrough with reflection info (unsafe)
1194 ///
1195 /// Allows using [`Device::create_shader_module_passthrough`].
1196 /// Shader code isn't parsed or interpreted in any way. It is the user's
1197 /// responsibility to ensure the code and reflection (if passed) are correct.
1198 ///
1199 /// Supported platforms
1200 /// - Vulkan
1201 /// - DX12
1202 /// - Metal
1203 /// - WebGPU
1204 ///
1205 /// Ideally, in the future, all platforms will be supported. For more info, see
1206 /// [this comment](https://github.com/gfx-rs/wgpu/issues/3103#issuecomment-2833058367).
1207 ///
1208 /// [`Device::create_shader_module_passthrough`]: https://docs.rs/wgpu/latest/wgpu/struct.Device.html#method.create_shader_module_passthrough
1209 const EXPERIMENTAL_PASSTHROUGH_SHADERS = 1 << 52;
1210
1211 /// Enables shader barycentric coordinates.
1212 ///
1213 /// Supported platforms:
1214 /// - Vulkan (with VK_KHR_fragment_shader_barycentric)
1215 /// - DX12 (with SM 6.1+)
1216 /// - Metal (with MSL 2.2+)
1217 ///
1218 /// This is a native only feature.
1219 const SHADER_BARYCENTRICS = 1 << 53;
1220
1221 /// Enables using multiview where not all texture array layers are rendered to in a single render pass/render pipeline. Making
1222 /// use of this feature also requires enabling `Features::MULTIVIEW`.
1223 ///
1224 /// Supported platforms
1225 /// - Vulkan
1226 /// - DX12
1227 ///
1228 ///
1229 /// While metal supports this in theory, the behavior of `view_index` differs from vulkan and dx12 so the feature isn't exposed.
1230 const SELECTIVE_MULTIVIEW = 1 << 54;
1231
1232 /// Enables the use of point-primitive outputs from mesh shaders. Making use of this feature also requires enabling
1233 /// `Features::EXPERIMENTAL_MESH_SHADER`.
1234 ///
1235 /// Supported platforms
1236 /// - Vulkan
1237 /// - Metal
1238 ///
1239 /// This is a native only feature.
1240 const EXPERIMENTAL_MESH_SHADER_POINTS = 1 << 55;
1241
1242 /// Enables creating texture arrays that are also multisampled.
1243 ///
1244 /// Without this feature, you cannot create a texture that has both a `sample_count` higher
1245 /// than 1, and a `depth_or_array_layers` higher than 1.
1246 ///
1247 /// Supported platforms:
1248 /// - Vulkan (except VK_KHR_portability_subset if multisampleArrayImage is not available)
1249 const MULTISAMPLE_ARRAY = 1 << 56;
1250 }
1251
1252 /// Features that are not guaranteed to be supported.
1253 ///
1254 /// These are part of the WebGPU standard. For all features, see [`Features`].
1255 ///
1256 /// If you want to use a feature, you need to first verify that the adapter supports
1257 /// the feature. If the adapter does not support the feature, requesting a device with it enabled
1258 /// will panic.
1259 ///
1260 /// Corresponds to [WebGPU `GPUFeatureName`](
1261 /// https://gpuweb.github.io/gpuweb/#enumdef-gpufeaturename).
1262 #[repr(transparent)]
1263 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1264 #[cfg_attr(feature = "serde", serde(transparent))]
1265 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
1266 pub struct FeaturesWebGPU features_webgpu {
1267 // API:
1268
1269 /// By default, polygon depth is clipped to 0-1 range before/during rasterization.
1270 /// Anything outside of that range is rejected, and respective fragments are not touched.
1271 ///
1272 /// With this extension, we can disabling clipping. That allows
1273 /// shadow map occluders to be rendered into a tighter depth range.
1274 ///
1275 /// Supported platforms:
1276 /// - desktops
1277 /// - some mobile chips
1278 ///
1279 /// This is a web and native feature.
1280 const DEPTH_CLIP_CONTROL = WEBGPU_FEATURE_DEPTH_CLIP_CONTROL;
1281
1282 /// Allows for explicit creation of textures of format [`TextureFormat::Depth32FloatStencil8`]
1283 ///
1284 /// Supported platforms:
1285 /// - Vulkan (mostly)
1286 /// - DX12
1287 /// - Metal
1288 /// - OpenGL
1289 ///
1290 /// This is a web and native feature.
1291 ///
1292 /// [`TextureFormat::Depth32FloatStencil8`]: super::TextureFormat::Depth32FloatStencil8
1293 const DEPTH32FLOAT_STENCIL8 = WEBGPU_FEATURE_DEPTH32FLOAT_STENCIL8;
1294
1295 /// Enables BCn family of compressed textures. All BCn textures use 4x4 pixel blocks
1296 /// with 8 or 16 bytes per block.
1297 ///
1298 /// Compressed textures sacrifice some quality in exchange for significantly reduced
1299 /// bandwidth usage.
1300 ///
1301 /// Support for this feature guarantees availability of [`TextureUsages::COPY_SRC | TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING`] for BCn formats.
1302 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] may enable additional usages.
1303 ///
1304 /// This feature guarantees availability of sliced-3d textures for BC formats when combined with TEXTURE_COMPRESSION_BC_SLICED_3D.
1305 ///
1306 /// Supported Platforms:
1307 /// - desktops
1308 /// - Mobile (All Apple9 and some Apple7 and Apple8 devices)
1309 ///
1310 /// This is a web and native feature.
1311 const TEXTURE_COMPRESSION_BC = WEBGPU_FEATURE_TEXTURE_COMPRESSION_BC;
1312
1313
1314 /// Allows the 3d dimension for textures with BC compressed formats.
1315 ///
1316 /// This feature must be used in combination with TEXTURE_COMPRESSION_BC to enable 3D textures with BC compression.
1317 /// It does not enable the BC formats by itself.
1318 ///
1319 /// Supported Platforms:
1320 /// - desktops
1321 /// - Mobile (All Apple9 and some Apple7 and Apple8 devices)
1322 ///
1323 /// This is a web and native feature.
1324 const TEXTURE_COMPRESSION_BC_SLICED_3D = WEBGPU_FEATURE_TEXTURE_COMPRESSION_BC_SLICED_3D;
1325
1326 /// Enables ETC family of compressed textures. All ETC textures use 4x4 pixel blocks.
1327 /// ETC2 RGB and RGBA1 are 8 bytes per block. RTC2 RGBA8 and EAC are 16 bytes per block.
1328 ///
1329 /// Compressed textures sacrifice some quality in exchange for significantly reduced
1330 /// bandwidth usage.
1331 ///
1332 /// Support for this feature guarantees availability of [`TextureUsages::COPY_SRC | TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING`] for ETC2 formats.
1333 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] may enable additional usages.
1334 ///
1335 /// Supported Platforms:
1336 /// - Vulkan on Intel
1337 /// - Mobile (some)
1338 ///
1339 /// This is a web and native feature.
1340 const TEXTURE_COMPRESSION_ETC2 = WEBGPU_FEATURE_TEXTURE_COMPRESSION_ETC2;
1341
1342 /// Enables ASTC family of compressed textures. ASTC textures use pixel blocks varying from 4x4 to 12x12.
1343 /// Blocks are always 16 bytes.
1344 ///
1345 /// Compressed textures sacrifice some quality in exchange for significantly reduced
1346 /// bandwidth usage.
1347 ///
1348 /// Support for this feature guarantees availability of [`TextureUsages::COPY_SRC | TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING`] for ASTC formats with Unorm/UnormSrgb channel type.
1349 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] may enable additional usages.
1350 ///
1351 /// This feature does not guarantee availability of sliced 3d textures for ASTC formats.
1352 /// If available, 3d support can be enabled by TEXTURE_COMPRESSION_ASTC_SLICED_3D feature.
1353 ///
1354 /// Supported Platforms:
1355 /// - Vulkan on Intel
1356 /// - Mobile (some)
1357 ///
1358 /// This is a web and native feature.
1359 const TEXTURE_COMPRESSION_ASTC = WEBGPU_FEATURE_TEXTURE_COMPRESSION_ASTC;
1360
1361
1362 /// Allows the 3d dimension for textures with ASTC compressed formats.
1363 ///
1364 /// This feature must be used in combination with TEXTURE_COMPRESSION_ASTC to enable 3D textures with ASTC compression.
1365 /// It does not enable the ASTC formats by itself.
1366 ///
1367 /// Supported Platforms:
1368 /// - Vulkan (some)
1369 /// - Metal on Apple3+
1370 /// - OpenGL/WebGL (some)
1371 ///
1372 /// Not Supported:
1373 /// - DX12
1374 ///
1375 /// This is a web and native feature.
1376 const TEXTURE_COMPRESSION_ASTC_SLICED_3D = WEBGPU_FEATURE_TEXTURE_COMPRESSION_ASTC_SLICED_3D;
1377
1378 /// Enables use of Timestamp Queries. These queries tell the current gpu timestamp when
1379 /// all work before the query is finished.
1380 ///
1381 /// This feature allows the use of
1382 /// - [`RenderPassDescriptor::timestamp_writes`]
1383 /// - [`ComputePassDescriptor::timestamp_writes`]
1384 /// to write out timestamps.
1385 ///
1386 /// For arbitrary timestamp write commands on encoders refer to [`Features::TIMESTAMP_QUERY_INSIDE_ENCODERS`].
1387 /// For arbitrary timestamp write commands on passes refer to [`Features::TIMESTAMP_QUERY_INSIDE_PASSES`].
1388 ///
1389 /// They must be resolved using [`CommandEncoder::resolve_query_set`] into a buffer,
1390 /// then the result must be multiplied by the timestamp period [`Queue::get_timestamp_period`]
1391 /// to get the timestamp in nanoseconds. Multiple timestamps can then be diffed to get the
1392 /// time for operations between them to finish.
1393 ///
1394 /// Supported Platforms:
1395 /// - Vulkan
1396 /// - DX12
1397 /// - Metal
1398 ///
1399 /// This is a web and native feature.
1400 ///
1401 /// [`RenderPassDescriptor::timestamp_writes`]: https://docs.rs/wgpu/latest/wgpu/struct.RenderPassDescriptor.html#structfield.timestamp_writes
1402 /// [`ComputePassDescriptor::timestamp_writes`]: https://docs.rs/wgpu/latest/wgpu/struct.ComputePassDescriptor.html#structfield.timestamp_writes
1403 /// [`CommandEncoder::resolve_query_set`]: https://docs.rs/wgpu/latest/wgpu/struct.CommandEncoder.html#method.resolve_query_set
1404 /// [`Queue::get_timestamp_period`]: https://docs.rs/wgpu/latest/wgpu/struct.Queue.html#method.get_timestamp_period
1405 const TIMESTAMP_QUERY = WEBGPU_FEATURE_TIMESTAMP_QUERY;
1406
1407 /// Allows non-zero value for the `first_instance` member in indirect draw calls.
1408 ///
1409 /// If this feature is not enabled, and the `first_instance` member is non-zero, the behavior may be:
1410 /// - The draw call is ignored.
1411 /// - The draw call is executed as if the `first_instance` is zero.
1412 /// - The draw call is executed with the correct `first_instance` value.
1413 ///
1414 /// Supported Platforms:
1415 /// - Vulkan (mostly)
1416 /// - DX12
1417 /// - Metal on Apple3+ or Mac1+
1418 /// - OpenGL (Desktop 4.2+ with ARB_shader_draw_parameters only)
1419 ///
1420 /// Not Supported:
1421 /// - OpenGL ES / WebGL
1422 ///
1423 /// This is a web and native feature.
1424 const INDIRECT_FIRST_INSTANCE = WEBGPU_FEATURE_INDIRECT_FIRST_INSTANCE;
1425
1426 /// Allows shaders to use 16-bit floating point types. You may use them uniform buffers,
1427 /// storage buffers, and local variables. You may not use them in immediates.
1428 ///
1429 /// In order to use this in WGSL shaders, you must add `enable f16;` to the top of your shader,
1430 /// before any global items.
1431 ///
1432 /// Supported Platforms:
1433 /// - Vulkan
1434 /// - Metal
1435 /// - DX12
1436 ///
1437 /// This is a web and native feature.
1438 const SHADER_F16 = WEBGPU_FEATURE_SHADER_F16;
1439
1440 /// Allows for usage of textures of format [`TextureFormat::Rg11b10Ufloat`] as a render target
1441 ///
1442 /// Supported platforms:
1443 /// - Vulkan
1444 /// - DX12
1445 /// - Metal
1446 ///
1447 /// This is a web and native feature.
1448 ///
1449 /// [`TextureFormat::Rg11b10Ufloat`]: super::TextureFormat::Rg11b10Ufloat
1450 const RG11B10UFLOAT_RENDERABLE = WEBGPU_FEATURE_RG11B10UFLOAT_RENDERABLE;
1451
1452 /// Allows the [`TextureUsages::STORAGE_BINDING`] usage on textures with format [`TextureFormat::Bgra8Unorm`]
1453 ///
1454 /// Supported Platforms:
1455 /// - Vulkan
1456 /// - DX12
1457 /// - Metal
1458 ///
1459 /// This is a web and native feature.
1460 ///
1461 /// [`TextureFormat::Bgra8Unorm`]: super::TextureFormat::Bgra8Unorm
1462 /// [`TextureUsages::STORAGE_BINDING`]: super::TextureUsages::STORAGE_BINDING
1463 const BGRA8UNORM_STORAGE = WEBGPU_FEATURE_BGRA8UNORM_STORAGE;
1464
1465
1466 /// Allows textures with formats "r32float", "rg32float", and "rgba32float" to be filterable.
1467 ///
1468 /// Supported Platforms:
1469 /// - Vulkan (mainly on Desktop GPUs)
1470 /// - DX12
1471 /// - Metal on macOS or Apple9+ GPUs, optional on iOS/iPadOS with Apple7/8 GPUs
1472 /// - GL with one of `GL_ARB_color_buffer_float`/`GL_EXT_color_buffer_float`/`OES_texture_float_linear`
1473 ///
1474 /// This is a web and native feature.
1475 const FLOAT32_FILTERABLE = WEBGPU_FEATURE_FLOAT32_FILTERABLE;
1476
1477 /// Allows two outputs from a shader to be used for blending.
1478 /// Note that dual-source blending doesn't support multiple render targets.
1479 ///
1480 /// For more info see the OpenGL ES extension GL_EXT_blend_func_extended.
1481 ///
1482 /// Supported platforms:
1483 /// - OpenGL ES (with GL_EXT_blend_func_extended)
1484 /// - Metal (with MSL 1.2+)
1485 /// - Vulkan (with dualSrcBlend)
1486 /// - DX12
1487 ///
1488 /// This is a web and native feature.
1489 const DUAL_SOURCE_BLENDING = WEBGPU_FEATURE_DUAL_SOURCE_BLENDING;
1490
1491 /// Allows the use of `@builtin(clip_distances)` in WGSL.
1492 ///
1493 /// Supported platforms:
1494 /// - Vulkan (mainly on Desktop GPUs)
1495 /// - GL (Desktop or `GL_EXT_clip_cull_distance`)
1496 ///
1497 /// This is a web and native feature.
1498 const CLIP_DISTANCES = WEBGPU_FEATURE_CLIP_DISTANCES;
1499
1500 /// Allows the use of immediate data: small, fast bits of memory that can be updated
1501 /// inside a [`RenderPass`].
1502 ///
1503 /// Allows the user to call [`RenderPass::set_immediates`], provide a non-zero immediate data size
1504 /// to [`PipelineLayoutDescriptor`], and provide a non-zero limit to [`Limits::max_immediate_size`].
1505 ///
1506 /// A block of immediate data can be declared in WGSL with `var<immediate>`:
1507 ///
1508 /// ```rust,ignore
1509 /// struct Immediates { example: f32, }
1510 /// var<immediate> c: Immediates;
1511 /// ```
1512 ///
1513 /// In GLSL, this corresponds to `layout(immediates) uniform Name {..}`.
1514 ///
1515 /// Supported platforms:
1516 /// - DX12
1517 /// - Vulkan
1518 /// - Metal
1519 /// - OpenGL (emulated with uniforms)
1520 ///
1521 /// WebGPU support is currently a proposal and will be available in browsers in the future.
1522 ///
1523 /// This is a web and native feature.
1524 ///
1525 #[doc = link_to_wgpu_item!(struct RenderPass)]
1526 #[doc = link_to_wgpu_item!(struct PipelineLayoutDescriptor)]
1527 #[doc = link_to_wgpu_docs!(["`RenderPass::set_immediates`"]: "struct.RenderPass.html#method.set_immediates")]
1528 /// [`Limits::max_immediate_size`]: super::Limits
1529 const IMMEDIATES = WEBGPU_FEATURE_IMMEDIATES;
1530 }
1531}
1532
1533impl Features {
1534 /// Mask of all features which are part of the upstream WebGPU standard.
1535 #[must_use]
1536 pub const fn all_webgpu_mask() -> Self {
1537 Self::from_bits_truncate(FeatureBits([
1538 FeaturesWGPU::empty().bits(),
1539 FeaturesWebGPU::all().bits(),
1540 ]))
1541 }
1542
1543 /// Mask of all features that are only available when targeting native (not web).
1544 #[must_use]
1545 pub const fn all_native_mask() -> Self {
1546 Self::from_bits_truncate(FeatureBits([
1547 FeaturesWGPU::all().bits(),
1548 FeaturesWebGPU::empty().bits(),
1549 ]))
1550 }
1551
1552 /// Mask of all features which are experimental.
1553 #[must_use]
1554 pub const fn all_experimental_mask() -> Self {
1555 Self::from_bits_truncate(FeatureBits([
1556 FeaturesWGPU::EXPERIMENTAL_MESH_SHADER.bits()
1557 | FeaturesWGPU::EXPERIMENTAL_MESH_SHADER_MULTIVIEW.bits()
1558 | FeaturesWGPU::EXPERIMENTAL_MESH_SHADER_POINTS.bits()
1559 | FeaturesWGPU::EXPERIMENTAL_RAY_QUERY.bits()
1560 | FeaturesWGPU::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN.bits()
1561 | FeaturesWGPU::EXPERIMENTAL_PASSTHROUGH_SHADERS.bits(),
1562 FeaturesWebGPU::empty().bits(),
1563 ]))
1564 }
1565
1566 /// Vertex formats allowed for creating and building BLASes
1567 #[must_use]
1568 pub fn allowed_vertex_formats_for_blas(&self) -> Vec<VertexFormat> {
1569 let mut formats = Vec::new();
1570 if self.intersects(Self::EXPERIMENTAL_RAY_QUERY) {
1571 formats.push(VertexFormat::Float32x3);
1572 }
1573 if self.contains(Self::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS) {
1574 formats.push(VertexFormat::Float32x2);
1575 formats.push(VertexFormat::Float16x2);
1576 formats.push(VertexFormat::Float16x4);
1577 formats.push(VertexFormat::Snorm16x2);
1578 formats.push(VertexFormat::Snorm16x4);
1579 }
1580 formats
1581 }
1582}
1583
1584#[cfg(test)]
1585mod tests {
1586 use crate::{Features, FeaturesWGPU, FeaturesWebGPU};
1587
1588 #[cfg(feature = "serde")]
1589 #[test]
1590 fn check_hex() {
1591 use crate::FeatureBits;
1592
1593 use bitflags::{
1594 parser::{ParseHex as _, WriteHex as _},
1595 Bits as _,
1596 };
1597
1598 let mut hex = alloc::string::String::new();
1599 FeatureBits::ALL.write_hex(&mut hex).unwrap();
1600 assert_eq!(
1601 FeatureBits::parse_hex(hex.as_str()).unwrap(),
1602 FeatureBits::ALL
1603 );
1604
1605 hex.clear();
1606 FeatureBits::EMPTY.write_hex(&mut hex).unwrap();
1607 assert_eq!(
1608 FeatureBits::parse_hex(hex.as_str()).unwrap(),
1609 FeatureBits::EMPTY
1610 );
1611
1612 for feature in Features::FLAGS {
1613 hex.clear();
1614 feature.value().bits().write_hex(&mut hex).unwrap();
1615 assert_eq!(
1616 FeatureBits::parse_hex(hex.as_str()).unwrap(),
1617 feature.value().bits(),
1618 "{hex}"
1619 );
1620 }
1621 }
1622
1623 #[test]
1624 fn check_features_display() {
1625 use alloc::format;
1626
1627 let feature = Features::CLEAR_TEXTURE;
1628 assert_eq!(format!("{feature}"), "CLEAR_TEXTURE");
1629
1630 let feature = Features::CLEAR_TEXTURE | Features::BGRA8UNORM_STORAGE;
1631 assert_eq!(format!("{feature}"), "CLEAR_TEXTURE | BGRA8UNORM_STORAGE");
1632 }
1633
1634 #[test]
1635 fn check_features_bits() {
1636 let bits = Features::all().bits();
1637 assert_eq!(Features::from_bits_retain(bits), Features::all());
1638
1639 let bits = Features::empty().bits();
1640 assert_eq!(Features::from_bits_retain(bits), Features::empty());
1641
1642 for feature in Features::FLAGS {
1643 let bits = feature.value().bits();
1644 assert_eq!(Features::from_bits_retain(bits), *feature.value());
1645 }
1646
1647 let bits = Features::all().bits();
1648 assert_eq!(Features::from_bits_truncate(bits), Features::all());
1649
1650 let bits = Features::empty().bits();
1651 assert_eq!(Features::from_bits_truncate(bits), Features::empty());
1652
1653 for feature in Features::FLAGS {
1654 let bits = feature.value().bits();
1655 assert_eq!(Features::from_bits_truncate(bits), *feature.value());
1656 }
1657
1658 let bits = Features::all().bits();
1659 assert_eq!(Features::from_bits(bits).unwrap(), Features::all());
1660
1661 let bits = Features::empty().bits();
1662 assert_eq!(Features::from_bits(bits).unwrap(), Features::empty());
1663
1664 for feature in Features::FLAGS {
1665 let bits = feature.value().bits();
1666 assert_eq!(Features::from_bits(bits).unwrap(), *feature.value());
1667 }
1668 }
1669
1670 #[test]
1671 fn create_features_from_parts() {
1672 let features: Features = FeaturesWGPU::TEXTURE_ATOMIC.into();
1673 assert_eq!(features, Features::TEXTURE_ATOMIC);
1674
1675 let features: Features = FeaturesWebGPU::TIMESTAMP_QUERY.into();
1676 assert_eq!(features, Features::TIMESTAMP_QUERY);
1677
1678 let features: Features = Features::from(FeaturesWGPU::TEXTURE_ATOMIC)
1679 | Features::from(FeaturesWebGPU::TIMESTAMP_QUERY);
1680 assert_eq!(
1681 features,
1682 Features::TEXTURE_ATOMIC | Features::TIMESTAMP_QUERY
1683 );
1684 assert_eq!(
1685 features,
1686 Features::from_internal_flags(
1687 FeaturesWGPU::TEXTURE_ATOMIC,
1688 FeaturesWebGPU::TIMESTAMP_QUERY
1689 )
1690 );
1691 }
1692
1693 #[test]
1694 fn experimental_features_part_of_experimental_mask() {
1695 for (name, feature) in Features::all().iter_names() {
1696 let prefixed_with_experimental = name.starts_with("EXPERIMENTAL_");
1697 let in_experimental_mask = Features::all_experimental_mask().contains(feature);
1698 assert_eq!(in_experimental_mask, prefixed_with_experimental);
1699 }
1700 }
1701}