Skip to main content

pebble/graphics/types/
flags.rs

1/// Generates a bitflags-style wrapper struct around a `wgpu` flags type, so
2/// no `wgpu` type leaks into the public API.
3macro_rules! bitflags_mirror {
4    (
5        $(#[$doc:meta])*
6        pub struct $Name:ident => $Wgpu:ty {
7            $(const $Flag:ident = $val:expr;)*
8        }
9    ) => {
10        $(#[$doc])*
11        #[derive(Copy, Clone, PartialEq, Eq, Hash)]
12        pub struct $Name(u32);
13
14        impl $Name {
15            $(pub const $Flag: Self = Self($val);)*
16
17            pub const fn empty() -> Self {
18                Self(0)
19            }
20
21            pub const fn bits(self) -> u32 {
22                self.0
23            }
24
25            pub const fn contains(self, other: Self) -> bool {
26                (self.0 & other.0) == other.0
27            }
28
29            pub const fn intersects(self, other: Self) -> bool {
30                (self.0 & other.0) != 0
31            }
32        }
33
34        impl core::ops::BitOr for $Name {
35            type Output = Self;
36            fn bitor(self, rhs: Self) -> Self {
37                Self(self.0 | rhs.0)
38            }
39        }
40
41        impl core::ops::BitOrAssign for $Name {
42            fn bitor_assign(&mut self, rhs: Self) {
43                self.0 |= rhs.0;
44            }
45        }
46
47        impl From<$Name> for $Wgpu {
48            fn from(value: $Name) -> Self {
49                <$Wgpu>::from_bits_truncate(value.0)
50            }
51        }
52    };
53}
54
55bitflags_mirror! {
56    /// Which shader stages a bind group entry is visible to.
57    pub struct ShaderStages => wgpu::ShaderStages {
58        const NONE = 0;
59        const VERTEX = 1 << 0;
60        const FRAGMENT = 1 << 1;
61        const COMPUTE = 1 << 2;
62        const VERTEX_FRAGMENT = (1 << 0) | (1 << 1);
63        const TASK = 1 << 3;
64        const MESH = 1 << 4;
65        const RAY_GENERATION = 1 << 5;
66        const ANY_HIT = 1 << 6;
67        const CLOSEST_HIT = 1 << 7;
68        const MISS = 1 << 8;
69    }
70}
71
72bitflags_mirror! {
73    /// What a GPU buffer can be used for — passed to [`BufferBuilder::with_usage`](crate::graphics::pipeline::buffers::BufferBuilder::with_usage).
74    pub struct BufferUsages => wgpu::BufferUsages {
75        const MAP_READ = 1 << 0;
76        const MAP_WRITE = 1 << 1;
77        const COPY_SRC = 1 << 2;
78        const COPY_DST = 1 << 3;
79        const INDEX = 1 << 4;
80        const VERTEX = 1 << 5;
81        const UNIFORM = 1 << 6;
82        const STORAGE = 1 << 7;
83        const INDIRECT = 1 << 8;
84        const QUERY_RESOLVE = 1 << 9;
85        const BLAS_INPUT = 1 << 10;
86        const TLAS_INPUT = 1 << 11;
87    }
88}
89
90bitflags_mirror! {
91    /// What a GPU texture can be used for — passed to [`Texture::with_extra_usage`](crate::graphics::pipeline::textures::Texture::with_extra_usage).
92    pub struct TextureUsages => wgpu::TextureUsages {
93        const COPY_SRC = 1 << 0;
94        const COPY_DST = 1 << 1;
95        const TEXTURE_BINDING = 1 << 2;
96        const STORAGE_BINDING = 1 << 3;
97        const RENDER_ATTACHMENT = 1 << 4;
98        const STORAGE_ATOMIC = 1 << 16;
99        const TRANSIENT = 1 << 17;
100    }
101}
102
103bitflags_mirror! {
104    /// Which color channels a render pipeline writes — see [`ColorTargetState`](super::pipeline_state::ColorTargetState).
105    pub struct ColorWrites => wgpu::ColorWrites {
106        const RED = 1 << 0;
107        const GREEN = 1 << 1;
108        const BLUE = 1 << 2;
109        const ALPHA = 1 << 3;
110        const COLOR = (1 << 0) | (1 << 1) | (1 << 2);
111        const ALL = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3);
112    }
113}
114
115impl Default for ColorWrites {
116    fn default() -> Self {
117        Self::ALL
118    }
119}
120
121/// Optional GPU capabilities that can be requested when the graphics backend is
122/// initialized — see [`Backend::features`](super::render::Backend::features).
123///
124/// Support varies by platform and driver; requesting a feature the adapter
125/// doesn't support is safe — it is dropped rather than failing device
126/// creation. Query [`Backend::features`] to see what was actually granted.
127///
128/// This mirrors a curated subset of `wgpu::Features` — unlike the other flag
129/// types in this module it isn't a 1:1 bit-for-bit copy, since `wgpu::Features`
130/// is backed by a 128-bit value. Each flag is translated individually in the
131/// `From` impl below instead.
132#[derive(Copy, Clone, PartialEq, Eq, Hash)]
133pub struct DeviceFeatures(u32);
134
135impl DeviceFeatures {
136    pub const ADDRESS_MODE_CLAMP_TO_BORDER: Self = Self(1 << 0);
137    pub const TIMESTAMP_QUERY: Self = Self(1 << 1);
138    pub const PIPELINE_STATISTICS_QUERY: Self = Self(1 << 2);
139    pub const INDIRECT_FIRST_INSTANCE: Self = Self(1 << 3);
140    pub const TEXTURE_COMPRESSION_BC: Self = Self(1 << 4);
141    pub const TEXTURE_COMPRESSION_ETC2: Self = Self(1 << 5);
142    pub const TEXTURE_COMPRESSION_ASTC: Self = Self(1 << 6);
143    pub const POLYGON_MODE_LINE: Self = Self(1 << 7);
144    pub const FLOAT32_FILTERABLE: Self = Self(1 << 8);
145    pub const SHADER_F16: Self = Self(1 << 9);
146    pub const SUBGROUP: Self = Self(1 << 10);
147    pub const RAY_QUERY: Self = Self(1 << 11);
148    pub const MESH_SHADER: Self = Self(1 << 12);
149
150    pub const fn empty() -> Self {
151        Self(0)
152    }
153
154    pub const fn bits(self) -> u32 {
155        self.0
156    }
157
158    pub const fn contains(self, other: Self) -> bool {
159        (self.0 & other.0) == other.0
160    }
161
162    pub const fn intersects(self, other: Self) -> bool {
163        (self.0 & other.0) != 0
164    }
165}
166
167impl core::ops::BitOr for DeviceFeatures {
168    type Output = Self;
169    fn bitor(self, rhs: Self) -> Self {
170        Self(self.0 | rhs.0)
171    }
172}
173
174impl core::ops::BitOrAssign for DeviceFeatures {
175    fn bitor_assign(&mut self, rhs: Self) {
176        self.0 |= rhs.0;
177    }
178}
179
180impl From<DeviceFeatures> for wgpu::Features {
181    fn from(value: DeviceFeatures) -> Self {
182        let mut features = wgpu::Features::empty();
183        let checks: &[(DeviceFeatures, wgpu::Features)] = &[
184            (
185                DeviceFeatures::ADDRESS_MODE_CLAMP_TO_BORDER,
186                wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
187            ),
188            (DeviceFeatures::TIMESTAMP_QUERY, wgpu::Features::TIMESTAMP_QUERY),
189            (
190                DeviceFeatures::PIPELINE_STATISTICS_QUERY,
191                wgpu::Features::PIPELINE_STATISTICS_QUERY,
192            ),
193            (
194                DeviceFeatures::INDIRECT_FIRST_INSTANCE,
195                wgpu::Features::INDIRECT_FIRST_INSTANCE,
196            ),
197            (
198                DeviceFeatures::TEXTURE_COMPRESSION_BC,
199                wgpu::Features::TEXTURE_COMPRESSION_BC,
200            ),
201            (
202                DeviceFeatures::TEXTURE_COMPRESSION_ETC2,
203                wgpu::Features::TEXTURE_COMPRESSION_ETC2,
204            ),
205            (
206                DeviceFeatures::TEXTURE_COMPRESSION_ASTC,
207                wgpu::Features::TEXTURE_COMPRESSION_ASTC,
208            ),
209            (DeviceFeatures::POLYGON_MODE_LINE, wgpu::Features::POLYGON_MODE_LINE),
210            (DeviceFeatures::FLOAT32_FILTERABLE, wgpu::Features::FLOAT32_FILTERABLE),
211            (DeviceFeatures::SHADER_F16, wgpu::Features::SHADER_F16),
212            (DeviceFeatures::SUBGROUP, wgpu::Features::SUBGROUP),
213            (DeviceFeatures::RAY_QUERY, wgpu::Features::EXPERIMENTAL_RAY_QUERY),
214            (DeviceFeatures::MESH_SHADER, wgpu::Features::EXPERIMENTAL_MESH_SHADER),
215        ];
216        for (flag, wgpu_flag) in checks {
217            if value.contains(*flag) {
218                features |= *wgpu_flag;
219            }
220        }
221        features
222    }
223}
224
225impl From<wgpu::Features> for DeviceFeatures {
226    fn from(value: wgpu::Features) -> Self {
227        let mut result = DeviceFeatures::empty();
228        let checks: &[(wgpu::Features, DeviceFeatures)] = &[
229            (
230                wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
231                DeviceFeatures::ADDRESS_MODE_CLAMP_TO_BORDER,
232            ),
233            (wgpu::Features::TIMESTAMP_QUERY, DeviceFeatures::TIMESTAMP_QUERY),
234            (
235                wgpu::Features::PIPELINE_STATISTICS_QUERY,
236                DeviceFeatures::PIPELINE_STATISTICS_QUERY,
237            ),
238            (
239                wgpu::Features::INDIRECT_FIRST_INSTANCE,
240                DeviceFeatures::INDIRECT_FIRST_INSTANCE,
241            ),
242            (
243                wgpu::Features::TEXTURE_COMPRESSION_BC,
244                DeviceFeatures::TEXTURE_COMPRESSION_BC,
245            ),
246            (
247                wgpu::Features::TEXTURE_COMPRESSION_ETC2,
248                DeviceFeatures::TEXTURE_COMPRESSION_ETC2,
249            ),
250            (
251                wgpu::Features::TEXTURE_COMPRESSION_ASTC,
252                DeviceFeatures::TEXTURE_COMPRESSION_ASTC,
253            ),
254            (wgpu::Features::POLYGON_MODE_LINE, DeviceFeatures::POLYGON_MODE_LINE),
255            (wgpu::Features::FLOAT32_FILTERABLE, DeviceFeatures::FLOAT32_FILTERABLE),
256            (wgpu::Features::SHADER_F16, DeviceFeatures::SHADER_F16),
257            (wgpu::Features::SUBGROUP, DeviceFeatures::SUBGROUP),
258            (wgpu::Features::EXPERIMENTAL_RAY_QUERY, DeviceFeatures::RAY_QUERY),
259            (wgpu::Features::EXPERIMENTAL_MESH_SHADER, DeviceFeatures::MESH_SHADER),
260        ];
261        for (wgpu_flag, flag) in checks {
262            if value.contains(*wgpu_flag) {
263                result |= *flag;
264            }
265        }
266        result
267    }
268}