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}