wgpu_types/
limits.rs

1//! [`Limits`] and downlevel-related types.
2
3use core::cmp::Ordering;
4
5#[cfg(any(feature = "serde", test))]
6use serde::{Deserialize, Serialize};
7
8#[cfg(doc)]
9use crate::{Features, TextureFormat};
10
11/// Invoke a macro for each of the limits.
12///
13/// The supplied macro should take two arguments. The first is a limit name, as
14/// an identifier, typically used to access a member of `struct Limits`. The
15/// second is `Ordering::Less` if valid values are less than the limit (the
16/// common case), or `Ordering::Greater` if valid values are more than the limit
17/// (for limits like alignments, which are minima instead of maxima).
18macro_rules! with_limits {
19    ($macro_name:ident) => {
20        $macro_name!(max_texture_dimension_1d, Ordering::Less);
21        $macro_name!(max_texture_dimension_1d, Ordering::Less);
22        $macro_name!(max_texture_dimension_2d, Ordering::Less);
23        $macro_name!(max_texture_dimension_3d, Ordering::Less);
24        $macro_name!(max_texture_array_layers, Ordering::Less);
25        $macro_name!(max_bind_groups, Ordering::Less);
26        $macro_name!(max_bindings_per_bind_group, Ordering::Less);
27        $macro_name!(
28            max_dynamic_uniform_buffers_per_pipeline_layout,
29            Ordering::Less
30        );
31        $macro_name!(
32            max_dynamic_storage_buffers_per_pipeline_layout,
33            Ordering::Less
34        );
35        $macro_name!(max_sampled_textures_per_shader_stage, Ordering::Less);
36        $macro_name!(max_samplers_per_shader_stage, Ordering::Less);
37        $macro_name!(max_storage_buffers_per_shader_stage, Ordering::Less);
38        $macro_name!(max_storage_textures_per_shader_stage, Ordering::Less);
39        $macro_name!(max_uniform_buffers_per_shader_stage, Ordering::Less);
40        $macro_name!(max_binding_array_elements_per_shader_stage, Ordering::Less);
41        $macro_name!(
42            max_binding_array_acceleration_structure_elements_per_shader_stage,
43            Ordering::Less
44        );
45        $macro_name!(
46            max_binding_array_sampler_elements_per_shader_stage,
47            Ordering::Less
48        );
49
50        $macro_name!(max_uniform_buffer_binding_size, Ordering::Less);
51        $macro_name!(max_storage_buffer_binding_size, Ordering::Less);
52        $macro_name!(max_vertex_buffers, Ordering::Less);
53        $macro_name!(max_buffer_size, Ordering::Less);
54        $macro_name!(max_vertex_attributes, Ordering::Less);
55        $macro_name!(max_vertex_buffer_array_stride, Ordering::Less);
56        $macro_name!(max_inter_stage_shader_variables, Ordering::Less);
57        $macro_name!(min_uniform_buffer_offset_alignment, Ordering::Greater);
58        $macro_name!(min_storage_buffer_offset_alignment, Ordering::Greater);
59        $macro_name!(max_color_attachments, Ordering::Less);
60        $macro_name!(max_color_attachment_bytes_per_sample, Ordering::Less);
61        $macro_name!(max_compute_workgroup_storage_size, Ordering::Less);
62        $macro_name!(max_compute_invocations_per_workgroup, Ordering::Less);
63        $macro_name!(max_compute_workgroup_size_x, Ordering::Less);
64        $macro_name!(max_compute_workgroup_size_y, Ordering::Less);
65        $macro_name!(max_compute_workgroup_size_z, Ordering::Less);
66        $macro_name!(max_compute_workgroups_per_dimension, Ordering::Less);
67
68        $macro_name!(max_immediate_size, Ordering::Less);
69        $macro_name!(max_non_sampler_bindings, Ordering::Less);
70
71        $macro_name!(max_task_mesh_workgroup_total_count, Ordering::Less);
72        $macro_name!(max_task_mesh_workgroups_per_dimension, Ordering::Less);
73        $macro_name!(max_task_invocations_per_workgroup, Ordering::Less);
74        $macro_name!(max_task_invocations_per_dimension, Ordering::Less);
75        $macro_name!(max_mesh_invocations_per_workgroup, Ordering::Less);
76        $macro_name!(max_mesh_invocations_per_dimension, Ordering::Less);
77
78        $macro_name!(max_task_payload_size, Ordering::Less);
79        $macro_name!(max_mesh_output_vertices, Ordering::Less);
80        $macro_name!(max_mesh_output_primitives, Ordering::Less);
81        $macro_name!(max_mesh_output_layers, Ordering::Less);
82        $macro_name!(max_mesh_multiview_view_count, Ordering::Less);
83
84        $macro_name!(max_blas_primitive_count, Ordering::Less);
85        $macro_name!(max_blas_geometry_count, Ordering::Less);
86        $macro_name!(max_tlas_instance_count, Ordering::Less);
87        $macro_name!(max_acceleration_structures_per_shader_stage, Ordering::Less);
88
89        $macro_name!(max_multiview_view_count, Ordering::Less);
90    };
91}
92
93/// Represents the sets of limits an adapter/device supports.
94///
95/// We provide three different defaults.
96/// - [`Limits::downlevel_defaults()`]. This is a set of limits that is guaranteed to work on almost
97///   all backends, including "downlevel" backends such as OpenGL and D3D11, other than WebGL. For
98///   most applications we recommend using these limits, assuming they are high enough for your
99///   application, and you do not intend to support WebGL.
100/// - [`Limits::downlevel_webgl2_defaults()`] This is a set of limits that is lower even than the
101///   [`downlevel_defaults()`], configured to be low enough to support running in the browser using
102///   WebGL2.
103/// - [`Limits::default()`]. This is the set of limits that is guaranteed to work on all modern
104///   backends and is guaranteed to be supported by WebGPU. Applications needing more modern
105///   features can use this as a reasonable set of limits if they are targeting only desktop and
106///   modern mobile devices.
107///
108/// We recommend starting with the most restrictive limits you can and manually increasing the
109/// limits you need boosted. This will let you stay running on all hardware that supports the limits
110/// you need.
111///
112/// Limits "better" than the default must be supported by the adapter and requested when requesting
113/// a device. If limits "better" than the adapter supports are requested, requesting a device will
114/// panic. Once a device is requested, you may only use resources up to the limits requested _even_
115/// if the adapter supports "better" limits.
116///
117/// Requesting limits that are "better" than you need may cause performance to decrease because the
118/// implementation needs to support more than is needed. You should ideally only request exactly
119/// what you need.
120///
121/// Corresponds to [WebGPU `GPUSupportedLimits`](
122/// https://gpuweb.github.io/gpuweb/#gpusupportedlimits).
123///
124/// [`downlevel_defaults()`]: Limits::downlevel_defaults
125#[repr(C)]
126#[derive(Clone, Debug, PartialEq, Eq, Hash)]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128#[cfg_attr(feature = "serde", serde(rename_all = "camelCase", default))]
129pub struct Limits {
130    /// Maximum allowed value for the `size.width` of a texture created with `TextureDimension::D1`.
131    /// Defaults to 8192. Higher is "better".
132    #[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension1D"))]
133    pub max_texture_dimension_1d: u32,
134    /// Maximum allowed value for the `size.width` and `size.height` of a texture created with `TextureDimension::D2`.
135    /// Defaults to 8192. Higher is "better".
136    #[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension2D"))]
137    pub max_texture_dimension_2d: u32,
138    /// Maximum allowed value for the `size.width`, `size.height`, and `size.depth_or_array_layers`
139    /// of a texture created with `TextureDimension::D3`.
140    /// Defaults to 2048. Higher is "better".
141    #[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension3D"))]
142    pub max_texture_dimension_3d: u32,
143    /// Maximum allowed value for the `size.depth_or_array_layers` of a texture created with `TextureDimension::D2`.
144    /// Defaults to 256. Higher is "better".
145    pub max_texture_array_layers: u32,
146    /// Amount of bind groups that can be attached to a pipeline at the same time. Defaults to 4. Higher is "better".
147    pub max_bind_groups: u32,
148    /// Maximum binding index allowed in `create_bind_group_layout`. Defaults to 1000. Higher is "better".
149    pub max_bindings_per_bind_group: u32,
150    /// Amount of uniform buffer bindings that can be dynamic in a single pipeline. Defaults to 8. Higher is "better".
151    pub max_dynamic_uniform_buffers_per_pipeline_layout: u32,
152    /// Amount of storage buffer bindings that can be dynamic in a single pipeline. Defaults to 4. Higher is "better".
153    pub max_dynamic_storage_buffers_per_pipeline_layout: u32,
154    /// Amount of sampled textures visible in a single shader stage. Defaults to 16. Higher is "better".
155    pub max_sampled_textures_per_shader_stage: u32,
156    /// Amount of samplers visible in a single shader stage. Defaults to 16. Higher is "better".
157    pub max_samplers_per_shader_stage: u32,
158    /// Amount of storage buffers visible in a single shader stage. Defaults to 8. Higher is "better".
159    pub max_storage_buffers_per_shader_stage: u32,
160    /// Amount of storage textures visible in a single shader stage. Defaults to 4. Higher is "better".
161    pub max_storage_textures_per_shader_stage: u32,
162    /// Amount of uniform buffers visible in a single shader stage. Defaults to 12. Higher is "better".
163    pub max_uniform_buffers_per_shader_stage: u32,
164    /// Amount of individual resources within binding arrays that can be accessed in a single shader stage. Applies
165    /// to all types of bindings except samplers.
166    ///
167    /// This "defaults" to 0. However if binding arrays are supported, all devices can support 500,000. Higher is "better".
168    pub max_binding_array_elements_per_shader_stage: u32,
169    /// Amount of individual acceleration structures within binding arrays that can be accessed in a single shader stage.
170    ///
171    /// This "defaults" to 0. Higher is "better".
172    pub max_binding_array_acceleration_structure_elements_per_shader_stage: u32,
173    /// Amount of individual samplers within binding arrays that can be accessed in a single shader stage.
174    ///
175    /// This "defaults" to 0. However if binding arrays are supported, all devices can support 1,000. Higher is "better".
176    pub max_binding_array_sampler_elements_per_shader_stage: u32,
177    /// Maximum size in bytes of a binding to a uniform buffer. Defaults to 64 KiB. Higher is "better".
178    pub max_uniform_buffer_binding_size: u64,
179    /// Maximum size in bytes of a binding to a storage buffer. Defaults to 128 MiB. Higher is "better".
180    pub max_storage_buffer_binding_size: u64,
181    /// Maximum length of `VertexState::buffers` when creating a `RenderPipeline`.
182    /// Defaults to 8. Higher is "better".
183    pub max_vertex_buffers: u32,
184    /// A limit above which buffer allocations are guaranteed to fail.
185    /// Defaults to 256 MiB. Higher is "better".
186    ///
187    /// Buffer allocations below the maximum buffer size may not succeed depending on available memory,
188    /// fragmentation and other factors.
189    pub max_buffer_size: u64,
190    /// Maximum length of `VertexBufferLayout::attributes`, summed over all `VertexState::buffers`,
191    /// when creating a `RenderPipeline`.
192    /// Defaults to 16. Higher is "better".
193    pub max_vertex_attributes: u32,
194    /// Maximum value for `VertexBufferLayout::array_stride` when creating a `RenderPipeline`.
195    /// Defaults to 2048. Higher is "better".
196    pub max_vertex_buffer_array_stride: u32,
197    /// Maximum value for the number of input or output variables for inter-stage communication
198    /// (like vertex outputs or fragment inputs) `@location(…)`s (in WGSL parlance)
199    /// when creating a `RenderPipeline`.
200    /// Defaults to 16. Higher is "better".
201    pub max_inter_stage_shader_variables: u32,
202    /// Required `BufferBindingType::Uniform` alignment for `BufferBinding::offset`
203    /// when creating a `BindGroup`, or for `set_bind_group` `dynamicOffsets`.
204    /// Defaults to 256. Lower is "better".
205    pub min_uniform_buffer_offset_alignment: u32,
206    /// Required `BufferBindingType::Storage` alignment for `BufferBinding::offset`
207    /// when creating a `BindGroup`, or for `set_bind_group` `dynamicOffsets`.
208    /// Defaults to 256. Lower is "better".
209    pub min_storage_buffer_offset_alignment: u32,
210    /// The maximum allowed number of color attachments.
211    pub max_color_attachments: u32,
212    /// The maximum number of bytes necessary to hold one sample (pixel or subpixel) of render
213    /// pipeline output data, across all color attachments as described by [`TextureFormat::target_pixel_byte_cost`]
214    /// and [`TextureFormat::target_component_alignment`]. Defaults to 32. Higher is "better".
215    ///
216    /// ⚠️ `Rgba8Unorm`/`Rgba8Snorm`/`Bgra8Unorm`/`Bgra8Snorm` are deceptively 8 bytes per sample. ⚠️
217    pub max_color_attachment_bytes_per_sample: u32,
218    /// Maximum number of bytes used for workgroup memory in a compute entry point. Defaults to
219    /// 16384. Higher is "better".
220    pub max_compute_workgroup_storage_size: u32,
221    /// Maximum value of the product of the `workgroup_size` dimensions for a compute entry-point.
222    /// Defaults to 256. Higher is "better".
223    pub max_compute_invocations_per_workgroup: u32,
224    /// The maximum value of the `workgroup_size` X dimension for a compute stage `ShaderModule` entry-point.
225    /// Defaults to 256. Higher is "better".
226    pub max_compute_workgroup_size_x: u32,
227    /// The maximum value of the `workgroup_size` Y dimension for a compute stage `ShaderModule` entry-point.
228    /// Defaults to 256. Higher is "better".
229    pub max_compute_workgroup_size_y: u32,
230    /// The maximum value of the `workgroup_size` Z dimension for a compute stage `ShaderModule` entry-point.
231    /// Defaults to 64. Higher is "better".
232    pub max_compute_workgroup_size_z: u32,
233    /// The maximum value for each dimension of a `ComputePass::dispatch(x, y, z)` operation.
234    /// Defaults to 65535. Higher is "better".
235    pub max_compute_workgroups_per_dimension: u32,
236
237    /// Amount of storage available for immediates in bytes. Defaults to 0. Higher is "better".
238    /// Requesting more than 0 during device creation requires [`Features::IMMEDIATES`] to be enabled.
239    ///
240    /// Expect the size to be:
241    /// - Vulkan: 128-256 bytes
242    /// - DX12: 128 bytes
243    /// - Metal: 4096 bytes
244    /// - OpenGL doesn't natively support immediates, and are emulated with uniforms,
245    ///   so this number is less useful but likely 256.
246    pub max_immediate_size: u32,
247    /// Maximum number of live non-sampler bindings.
248    ///
249    /// <div class="warning">
250    /// The default value is **1_000_000**, On systems with integrated GPUs (iGPUs)—particularly on Windows using the D3D12
251    /// backend—this can lead to significant system RAM consumption since iGPUs share system memory directly with the CPU.
252    /// </div>
253    ///
254    /// This limit only affects the d3d12 backend. Using a large number will allow the device
255    /// to create many bind groups at the cost of a large up-front allocation at device creation.
256    pub max_non_sampler_bindings: u32,
257
258    /// The maximum total value for a `RenderPass::draw_mesh_tasks(x, y, z)` operation or the
259    /// `@builtin(mesh_task_size)` returned from a task shader.  Higher is "better".
260    pub max_task_mesh_workgroup_total_count: u32,
261    /// The maximum value for each dimension of a `RenderPass::draw_mesh_tasks(x, y, z)` operation.
262    /// Also for task shader outputs. Higher is "better".
263    pub max_task_mesh_workgroups_per_dimension: u32,
264    // These are fundamentally different. It is very common for limits on mesh shaders to be much lower.
265    /// Maximum total number of invocations, or threads, per task shader workgroup. Higher is "better".
266    pub max_task_invocations_per_workgroup: u32,
267    /// The maximum value for each dimension of a task shader's workgroup size. Higher is "better".
268    pub max_task_invocations_per_dimension: u32,
269    /// Maximum total number of invocations, or threads, per mesh shader workgroup. Higher is "better".
270    pub max_mesh_invocations_per_workgroup: u32,
271    /// The maximum value for each dimension of a mesh shader's workgroup size. Higher is "better".
272    pub max_mesh_invocations_per_dimension: u32,
273
274    /// The maximum size of the payload passed from task to mesh shader. Higher is "better".
275    pub max_task_payload_size: u32,
276    /// The maximum number of vertices that a mesh shader may output. Higher is "better".
277    pub max_mesh_output_vertices: u32,
278    /// The maximum number of primitives that a mesh shader may output. Higher is "better".
279    pub max_mesh_output_primitives: u32,
280    /// The maximum number of layers that can be output from a mesh shader. Higher is "better".
281    /// See [#8509](https://github.com/gfx-rs/wgpu/issues/8509).
282    pub max_mesh_output_layers: u32,
283    /// The maximum number of views that can be used by a mesh shader in multiview rendering.
284    /// Higher is "better".
285    pub max_mesh_multiview_view_count: u32,
286
287    /// The maximum number of primitive (ex: triangles, aabbs) a BLAS is allowed to have. Requesting
288    /// more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
289    /// is enabled.
290    pub max_blas_primitive_count: u32,
291    /// The maximum number of geometry descriptors a BLAS is allowed to have. Requesting
292    /// more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
293    /// is enabled.
294    pub max_blas_geometry_count: u32,
295    /// The maximum number of instances a TLAS is allowed to have. Requesting more than 0 during
296    /// device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
297    /// is enabled.
298    pub max_tlas_instance_count: u32,
299    /// The maximum number of acceleration structures allowed to be used in a shader stage.
300    /// Requesting more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
301    /// is enabled.
302    pub max_acceleration_structures_per_shader_stage: u32,
303
304    /// The maximum number of views that can be used in multiview rendering
305    pub max_multiview_view_count: u32,
306}
307
308impl Default for Limits {
309    fn default() -> Self {
310        Self::defaults()
311    }
312}
313
314impl Limits {
315    /// These default limits are guaranteed to to work on all modern
316    /// backends and guaranteed to be supported by WebGPU
317    ///
318    /// Those limits are as follows:
319    /// ```rust
320    /// # use wgpu_types::Limits;
321    /// assert_eq!(Limits::defaults(), Limits {
322    ///     max_texture_dimension_1d: 8192,
323    ///     max_texture_dimension_2d: 8192,
324    ///     max_texture_dimension_3d: 2048,
325    ///     max_texture_array_layers: 256,
326    ///     max_bind_groups: 4,
327    ///     max_bindings_per_bind_group: 1000,
328    ///     max_dynamic_uniform_buffers_per_pipeline_layout: 8,
329    ///     max_dynamic_storage_buffers_per_pipeline_layout: 4,
330    ///     max_sampled_textures_per_shader_stage: 16,
331    ///     max_samplers_per_shader_stage: 16,
332    ///     max_storage_buffers_per_shader_stage: 8,
333    ///     max_storage_textures_per_shader_stage: 4,
334    ///     max_uniform_buffers_per_shader_stage: 12,
335    ///     max_binding_array_elements_per_shader_stage: 0,
336    ///     max_binding_array_acceleration_structure_elements_per_shader_stage: 0,
337    ///     max_binding_array_sampler_elements_per_shader_stage: 0,
338    ///     max_uniform_buffer_binding_size: 64 << 10, // (64 KiB)
339    ///     max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
340    ///     max_vertex_buffers: 8,
341    ///     max_buffer_size: 256 << 20, // (256 MiB)
342    ///     max_vertex_attributes: 16,
343    ///     max_vertex_buffer_array_stride: 2048,
344    ///     max_inter_stage_shader_variables: 16,
345    ///     min_uniform_buffer_offset_alignment: 256,
346    ///     min_storage_buffer_offset_alignment: 256,
347    ///     max_color_attachments: 8,
348    ///     max_color_attachment_bytes_per_sample: 32,
349    ///     max_compute_workgroup_storage_size: 16384,
350    ///     max_compute_invocations_per_workgroup: 256,
351    ///     max_compute_workgroup_size_x: 256,
352    ///     max_compute_workgroup_size_y: 256,
353    ///     max_compute_workgroup_size_z: 64,
354    ///     max_compute_workgroups_per_dimension: 65535,
355    ///     max_immediate_size: 0,
356    ///     max_non_sampler_bindings: 1_000_000,
357    ///     max_task_mesh_workgroup_total_count: 0,
358    ///     max_task_mesh_workgroups_per_dimension: 0,
359    ///     max_task_invocations_per_workgroup: 0,
360    ///     max_task_invocations_per_dimension: 0,
361    ///     max_mesh_invocations_per_workgroup: 0,
362    ///     max_mesh_invocations_per_dimension: 0,
363    ///     max_task_payload_size: 0,
364    ///     max_mesh_output_vertices: 0,
365    ///     max_mesh_output_primitives: 0,
366    ///     max_mesh_output_layers: 0,
367    ///     max_mesh_multiview_view_count: 0,
368    ///     max_blas_primitive_count: 0,
369    ///     max_blas_geometry_count: 0,
370    ///     max_tlas_instance_count: 0,
371    ///     max_acceleration_structures_per_shader_stage: 0,
372    ///     max_multiview_view_count: 0,
373    /// });
374    /// ```
375    ///
376    /// Rust doesn't allow const in trait implementations, so we break this out
377    /// to allow reusing these defaults in const contexts
378    #[must_use]
379    pub const fn defaults() -> Self {
380        Self {
381            max_texture_dimension_1d: 8192,
382            max_texture_dimension_2d: 8192,
383            max_texture_dimension_3d: 2048,
384            max_texture_array_layers: 256,
385            max_bind_groups: 4,
386            max_bindings_per_bind_group: 1000,
387            max_dynamic_uniform_buffers_per_pipeline_layout: 8,
388            max_dynamic_storage_buffers_per_pipeline_layout: 4,
389            max_sampled_textures_per_shader_stage: 16,
390            max_samplers_per_shader_stage: 16,
391            max_storage_buffers_per_shader_stage: 8,
392            max_storage_textures_per_shader_stage: 4,
393            max_uniform_buffers_per_shader_stage: 12,
394            max_binding_array_elements_per_shader_stage: 0,
395            max_binding_array_acceleration_structure_elements_per_shader_stage: 0,
396            max_binding_array_sampler_elements_per_shader_stage: 0,
397            max_uniform_buffer_binding_size: 64 << 10, // (64 KiB)
398            max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
399            max_vertex_buffers: 8,
400            max_buffer_size: 256 << 20, // (256 MiB)
401            max_vertex_attributes: 16,
402            max_vertex_buffer_array_stride: 2048,
403            max_inter_stage_shader_variables: 16,
404            min_uniform_buffer_offset_alignment: 256,
405            min_storage_buffer_offset_alignment: 256,
406            max_color_attachments: 8,
407            max_color_attachment_bytes_per_sample: 32,
408            max_compute_workgroup_storage_size: 16384,
409            max_compute_invocations_per_workgroup: 256,
410            max_compute_workgroup_size_x: 256,
411            max_compute_workgroup_size_y: 256,
412            max_compute_workgroup_size_z: 64,
413            max_compute_workgroups_per_dimension: 65535,
414            max_immediate_size: 0,
415            max_non_sampler_bindings: 1_000_000,
416
417            max_task_mesh_workgroup_total_count: 0,
418            max_task_mesh_workgroups_per_dimension: 0,
419            max_task_invocations_per_workgroup: 0,
420            max_task_invocations_per_dimension: 0,
421            max_mesh_invocations_per_workgroup: 0,
422            max_mesh_invocations_per_dimension: 0,
423            max_task_payload_size: 0,
424            max_mesh_output_vertices: 0,
425            max_mesh_output_primitives: 0,
426            max_mesh_output_layers: 0,
427            max_mesh_multiview_view_count: 0,
428
429            max_blas_primitive_count: 0,
430            max_blas_geometry_count: 0,
431            max_tlas_instance_count: 0,
432            max_acceleration_structures_per_shader_stage: 0,
433
434            max_multiview_view_count: 0,
435        }
436    }
437
438    /// These default limits are guaranteed to be compatible with GLES-3.1, and D3D11
439    ///
440    /// Those limits are as follows (different from default are marked with *):
441    /// ```rust
442    /// # use wgpu_types::Limits;
443    /// assert_eq!(Limits::downlevel_defaults(), Limits {
444    ///     max_texture_dimension_1d: 2048, // *
445    ///     max_texture_dimension_2d: 2048, // *
446    ///     max_texture_dimension_3d: 256, // *
447    ///     max_texture_array_layers: 256,
448    ///     max_bind_groups: 4,
449    ///     max_bindings_per_bind_group: 1000,
450    ///     max_dynamic_uniform_buffers_per_pipeline_layout: 8,
451    ///     max_dynamic_storage_buffers_per_pipeline_layout: 4,
452    ///     max_sampled_textures_per_shader_stage: 16,
453    ///     max_samplers_per_shader_stage: 16,
454    ///     max_storage_buffers_per_shader_stage: 4, // *
455    ///     max_storage_textures_per_shader_stage: 4,
456    ///     max_uniform_buffers_per_shader_stage: 12,
457    ///     max_binding_array_elements_per_shader_stage: 0,
458    ///     max_binding_array_acceleration_structure_elements_per_shader_stage: 0,
459    ///     max_binding_array_sampler_elements_per_shader_stage: 0,
460    ///     max_uniform_buffer_binding_size: 16 << 10, // * (16 KiB)
461    ///     max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
462    ///     max_vertex_buffers: 8,
463    ///     max_vertex_attributes: 16,
464    ///     max_vertex_buffer_array_stride: 2048,
465    ///     max_immediate_size: 0,
466    ///     min_uniform_buffer_offset_alignment: 256,
467    ///     min_storage_buffer_offset_alignment: 256,
468    ///     max_inter_stage_shader_variables: 15,
469    ///     max_color_attachments: 4,
470    ///     max_color_attachment_bytes_per_sample: 32,
471    ///     max_compute_workgroup_storage_size: 16352, // *
472    ///     max_compute_invocations_per_workgroup: 256,
473    ///     max_compute_workgroup_size_x: 256,
474    ///     max_compute_workgroup_size_y: 256,
475    ///     max_compute_workgroup_size_z: 64,
476    ///     max_compute_workgroups_per_dimension: 65535,
477    ///     max_buffer_size: 256 << 20, // (256 MiB)
478    ///     max_non_sampler_bindings: 1_000_000,
479    ///
480    ///     max_task_mesh_workgroup_total_count: 0,
481    ///     max_task_mesh_workgroups_per_dimension: 0,
482    ///     max_task_invocations_per_workgroup: 0,
483    ///     max_task_invocations_per_dimension: 0,
484    ///     max_mesh_invocations_per_workgroup: 0,
485    ///     max_mesh_invocations_per_dimension: 0,
486    ///     max_task_payload_size: 0,
487    ///     max_mesh_output_vertices: 0,
488    ///     max_mesh_output_primitives: 0,
489    ///     max_mesh_output_layers: 0,
490    ///     max_mesh_multiview_view_count: 0,
491    ///
492    ///     max_blas_primitive_count: 0,
493    ///     max_blas_geometry_count: 0,
494    ///     max_tlas_instance_count: 0,
495    ///     max_acceleration_structures_per_shader_stage: 0,
496    ///
497    ///     max_multiview_view_count: 0,
498    /// });
499    /// ```
500    #[must_use]
501    pub const fn downlevel_defaults() -> Self {
502        Self {
503            max_texture_dimension_1d: 2048,
504            max_texture_dimension_2d: 2048,
505            max_texture_dimension_3d: 256,
506            max_storage_buffers_per_shader_stage: 4,
507            max_uniform_buffer_binding_size: 16 << 10, // (16 KiB)
508            max_inter_stage_shader_variables: 15,
509            max_color_attachments: 4,
510            // see: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=7
511            max_compute_workgroup_storage_size: 16352,
512            ..Self::defaults()
513        }
514    }
515
516    /// These default limits are guaranteed to be compatible with GLES-3.0, and D3D11, and WebGL2
517    ///
518    /// Those limits are as follows (different from `downlevel_defaults` are marked with +,
519    /// *'s from `downlevel_defaults` shown as well.):
520    /// ```rust
521    /// # use wgpu_types::Limits;
522    /// assert_eq!(Limits::downlevel_webgl2_defaults(), Limits {
523    ///     max_texture_dimension_1d: 2048, // *
524    ///     max_texture_dimension_2d: 2048, // *
525    ///     max_texture_dimension_3d: 256, // *
526    ///     max_texture_array_layers: 256,
527    ///     max_bind_groups: 4,
528    ///     max_bindings_per_bind_group: 1000,
529    ///     max_dynamic_uniform_buffers_per_pipeline_layout: 8,
530    ///     max_dynamic_storage_buffers_per_pipeline_layout: 0, // +
531    ///     max_sampled_textures_per_shader_stage: 16,
532    ///     max_samplers_per_shader_stage: 16,
533    ///     max_storage_buffers_per_shader_stage: 0, // * +
534    ///     max_storage_textures_per_shader_stage: 0, // +
535    ///     max_uniform_buffers_per_shader_stage: 11, // +
536    ///     max_binding_array_elements_per_shader_stage: 0,
537    ///     max_binding_array_acceleration_structure_elements_per_shader_stage: 0,
538    ///     max_binding_array_sampler_elements_per_shader_stage: 0,
539    ///     max_uniform_buffer_binding_size: 16 << 10, // * (16 KiB)
540    ///     max_storage_buffer_binding_size: 0, // * +
541    ///     max_vertex_buffers: 8,
542    ///     max_vertex_attributes: 16,
543    ///     max_vertex_buffer_array_stride: 255, // +
544    ///     max_immediate_size: 0,
545    ///     min_uniform_buffer_offset_alignment: 256,
546    ///     min_storage_buffer_offset_alignment: 256,
547    ///     max_inter_stage_shader_variables: 15,
548    ///     max_color_attachments: 4,
549    ///     max_color_attachment_bytes_per_sample: 32,
550    ///     max_compute_workgroup_storage_size: 0, // +
551    ///     max_compute_invocations_per_workgroup: 0, // +
552    ///     max_compute_workgroup_size_x: 0, // +
553    ///     max_compute_workgroup_size_y: 0, // +
554    ///     max_compute_workgroup_size_z: 0, // +
555    ///     max_compute_workgroups_per_dimension: 0, // +
556    ///     max_buffer_size: 256 << 20, // (256 MiB),
557    ///     max_non_sampler_bindings: 1_000_000,
558    ///
559    ///     max_task_mesh_workgroup_total_count: 0,
560    ///     max_task_mesh_workgroups_per_dimension: 0,
561    ///     max_task_invocations_per_workgroup: 0,
562    ///     max_task_invocations_per_dimension: 0,
563    ///     max_mesh_invocations_per_workgroup: 0,
564    ///     max_mesh_invocations_per_dimension: 0,
565    ///     max_task_payload_size: 0,
566    ///     max_mesh_output_vertices: 0,
567    ///     max_mesh_output_primitives: 0,
568    ///     max_mesh_output_layers: 0,
569    ///     max_mesh_multiview_view_count: 0,
570    ///
571    ///     max_blas_primitive_count: 0,
572    ///     max_blas_geometry_count: 0,
573    ///     max_tlas_instance_count: 0,
574    ///     max_acceleration_structures_per_shader_stage: 0,
575    ///
576    ///     max_multiview_view_count: 0,
577    /// });
578    /// ```
579    #[must_use]
580    pub const fn downlevel_webgl2_defaults() -> Self {
581        Self {
582            max_uniform_buffers_per_shader_stage: 11,
583            max_storage_buffers_per_shader_stage: 0,
584            max_storage_textures_per_shader_stage: 0,
585            max_dynamic_storage_buffers_per_pipeline_layout: 0,
586            max_storage_buffer_binding_size: 0,
587            max_vertex_buffer_array_stride: 255,
588            max_compute_workgroup_storage_size: 0,
589            max_compute_invocations_per_workgroup: 0,
590            max_compute_workgroup_size_x: 0,
591            max_compute_workgroup_size_y: 0,
592            max_compute_workgroup_size_z: 0,
593            max_compute_workgroups_per_dimension: 0,
594
595            // Value supported by Intel Celeron B830 on Windows (OpenGL 3.1)
596            max_inter_stage_shader_variables: 15,
597
598            // Most of the values should be the same as the downlevel defaults
599            ..Self::downlevel_defaults()
600        }
601    }
602
603    /// Sets each limit to `i32::MAX` (or 1, in the case of lower-is-better limits).
604    ///
605    /// These values do not reflect the capabilities of any actual device. They are
606    /// used by the noop backend, and by the test that makes sure `with_limits!` is
607    /// exhaustive.
608    #[must_use]
609    pub const fn unlimited() -> Self {
610        /// Guaranteed to be no bigger than isize::MAX which is the maximum size of an allocation,
611        /// except on 16-bit platforms which we certainly don’t fit in.
612        const ALLOC_MAX_U32: u32 = i32::MAX as u32;
613        /// Guaranteed to be no bigger than isize::MAX which is the maximum size of an allocation,
614        /// except on 16-bit platforms which we certainly don’t fit in.
615        const ALLOC_MAX_U64: u64 = i32::MAX as u64;
616
617        Self {
618            max_texture_dimension_1d: ALLOC_MAX_U32,
619            max_texture_dimension_2d: ALLOC_MAX_U32,
620            max_texture_dimension_3d: ALLOC_MAX_U32,
621            max_texture_array_layers: ALLOC_MAX_U32,
622            max_bind_groups: ALLOC_MAX_U32,
623            max_bindings_per_bind_group: ALLOC_MAX_U32,
624            max_dynamic_uniform_buffers_per_pipeline_layout: ALLOC_MAX_U32,
625            max_dynamic_storage_buffers_per_pipeline_layout: ALLOC_MAX_U32,
626            max_sampled_textures_per_shader_stage: ALLOC_MAX_U32,
627            max_samplers_per_shader_stage: ALLOC_MAX_U32,
628            max_storage_buffers_per_shader_stage: ALLOC_MAX_U32,
629            max_storage_textures_per_shader_stage: ALLOC_MAX_U32,
630            max_uniform_buffers_per_shader_stage: ALLOC_MAX_U32,
631            max_binding_array_elements_per_shader_stage: ALLOC_MAX_U32,
632            max_binding_array_sampler_elements_per_shader_stage: ALLOC_MAX_U32,
633            max_binding_array_acceleration_structure_elements_per_shader_stage: ALLOC_MAX_U32,
634            max_uniform_buffer_binding_size: ALLOC_MAX_U64,
635            max_storage_buffer_binding_size: ALLOC_MAX_U64,
636            max_vertex_buffers: ALLOC_MAX_U32,
637            max_buffer_size: ALLOC_MAX_U64,
638            max_vertex_attributes: ALLOC_MAX_U32,
639            max_vertex_buffer_array_stride: ALLOC_MAX_U32,
640            max_inter_stage_shader_variables: ALLOC_MAX_U32,
641            min_uniform_buffer_offset_alignment: 1,
642            min_storage_buffer_offset_alignment: 1,
643            max_color_attachments: ALLOC_MAX_U32,
644            max_color_attachment_bytes_per_sample: ALLOC_MAX_U32,
645            max_compute_workgroup_storage_size: ALLOC_MAX_U32,
646            max_compute_invocations_per_workgroup: ALLOC_MAX_U32,
647            max_compute_workgroup_size_x: ALLOC_MAX_U32,
648            max_compute_workgroup_size_y: ALLOC_MAX_U32,
649            max_compute_workgroup_size_z: ALLOC_MAX_U32,
650            max_compute_workgroups_per_dimension: ALLOC_MAX_U32,
651            max_immediate_size: ALLOC_MAX_U32,
652            max_non_sampler_bindings: ALLOC_MAX_U32,
653
654            max_task_mesh_workgroup_total_count: ALLOC_MAX_U32,
655            max_task_mesh_workgroups_per_dimension: ALLOC_MAX_U32,
656            max_task_invocations_per_workgroup: ALLOC_MAX_U32,
657            max_task_invocations_per_dimension: ALLOC_MAX_U32,
658            max_mesh_invocations_per_workgroup: ALLOC_MAX_U32,
659            max_mesh_invocations_per_dimension: ALLOC_MAX_U32,
660            max_task_payload_size: ALLOC_MAX_U32,
661            max_mesh_output_vertices: ALLOC_MAX_U32,
662            max_mesh_output_primitives: ALLOC_MAX_U32,
663            max_mesh_output_layers: ALLOC_MAX_U32,
664            max_mesh_multiview_view_count: ALLOC_MAX_U32,
665
666            max_blas_primitive_count: ALLOC_MAX_U32,
667            max_blas_geometry_count: ALLOC_MAX_U32,
668            max_tlas_instance_count: ALLOC_MAX_U32,
669            max_acceleration_structures_per_shader_stage: ALLOC_MAX_U32,
670
671            max_multiview_view_count: ALLOC_MAX_U32,
672        }
673    }
674
675    /// Modify the current limits to use the resolution limits of the other.
676    ///
677    /// This is useful because the swapchain might need to be larger than any other image in the application.
678    ///
679    /// If your application only needs 512x512, you might be running on a 4k display and need extremely high resolution limits.
680    #[must_use]
681    pub const fn using_resolution(self, other: Self) -> Self {
682        Self {
683            max_texture_dimension_1d: other.max_texture_dimension_1d,
684            max_texture_dimension_2d: other.max_texture_dimension_2d,
685            max_texture_dimension_3d: other.max_texture_dimension_3d,
686            ..self
687        }
688    }
689
690    /// Modify the current limits to use the buffer alignment limits of the adapter.
691    ///
692    /// This is useful for when you'd like to dynamically use the "best" supported buffer alignments.
693    #[must_use]
694    pub const fn using_alignment(self, other: Self) -> Self {
695        Self {
696            min_uniform_buffer_offset_alignment: other.min_uniform_buffer_offset_alignment,
697            min_storage_buffer_offset_alignment: other.min_storage_buffer_offset_alignment,
698            ..self
699        }
700    }
701
702    /// The minimum guaranteed limits for acceleration structures if you enable [`Features::EXPERIMENTAL_RAY_QUERY`]
703    #[must_use]
704    pub const fn using_minimum_supported_acceleration_structure_values(self) -> Self {
705        Self {
706            max_blas_geometry_count: (1 << 24) - 1, // 2^24 - 1: Vulkan's minimum
707            max_tlas_instance_count: (1 << 24) - 1, // 2^24 - 1: Vulkan's minimum
708            max_blas_primitive_count: 1 << 28,      // 2^28: Metal's minimum
709            max_acceleration_structures_per_shader_stage: 16, // Vulkan's minimum
710            ..self
711        }
712    }
713
714    /// Modify the current limits to use the acceleration structure limits of `other` (`other` could
715    /// be the limits of the adapter).
716    #[must_use]
717    pub const fn using_acceleration_structure_values(self, other: Self) -> Self {
718        Self {
719            max_blas_geometry_count: other.max_blas_geometry_count,
720            max_tlas_instance_count: other.max_tlas_instance_count,
721            max_blas_primitive_count: other.max_blas_primitive_count,
722            max_acceleration_structures_per_shader_stage: other
723                .max_acceleration_structures_per_shader_stage,
724            ..self
725        }
726    }
727
728    /// The recommended minimum limits for mesh shaders if you enable [`Features::EXPERIMENTAL_MESH_SHADER`]
729    ///
730    /// These are chosen somewhat arbitrarily. They are small enough that they should cover all physical devices,
731    /// but not necessarily all use cases.
732    #[must_use]
733    pub const fn using_recommended_minimum_mesh_shader_values(self) -> Self {
734        Self {
735            // This limitation comes from metal
736            max_task_mesh_workgroup_total_count: 1024,
737            // This is a DirectX limitation
738            max_task_mesh_workgroups_per_dimension: 256,
739            // Nvidia limit on vulkan
740            max_task_invocations_per_workgroup: 128,
741            max_task_invocations_per_dimension: 64,
742
743            // DX12 limitation, revisit for vulkan
744            max_mesh_invocations_per_workgroup: 128,
745            max_mesh_invocations_per_dimension: 128,
746
747            // Metal specifies this as its max
748            max_task_payload_size: 16384 - 32,
749            // DX12 limitation, revisit for vulkan
750            max_mesh_output_vertices: 256,
751            max_mesh_output_primitives: 256,
752            // llvmpipe once again requires this to be 8. An RTX 3060 supports well over 1024.
753            // Also DX12 vaguely suggests going over this is illegal in some cases.
754            max_mesh_output_layers: 8,
755            // llvmpipe reports 0 multiview count, which just means no multiview is allowed
756            max_mesh_multiview_view_count: 0,
757            ..self
758        }
759    }
760
761    /// Compares every limits within self is within the limits given in `allowed`.
762    ///
763    /// If you need detailed information on failures, look at [`Limits::check_limits_with_fail_fn`].
764    #[must_use]
765    pub fn check_limits(&self, allowed: &Self) -> bool {
766        let mut within = true;
767        self.check_limits_with_fail_fn(allowed, true, |_, _, _| within = false);
768        within
769    }
770
771    /// Compares every limits within self is within the limits given in `allowed`.
772    /// For an easy to use binary choice, use [`Limits::check_limits`].
773    ///
774    /// If a value is not within the allowed limit, this function calls the `fail_fn`
775    /// with the:
776    ///  - limit name
777    ///  - self's limit
778    ///  - allowed's limit.
779    ///
780    /// If fatal is true, a single failure bails out the comparison after a single failure.
781    pub fn check_limits_with_fail_fn(
782        &self,
783        allowed: &Self,
784        fatal: bool,
785        mut fail_fn: impl FnMut(&'static str, u64, u64),
786    ) {
787        macro_rules! check_with_fail_fn {
788            ($name:ident, $ordering:expr) => {
789                let invalid_ord = $ordering.reverse();
790                if self.$name.cmp(&allowed.$name) == invalid_ord {
791                    fail_fn(stringify!($name), self.$name as u64, allowed.$name as u64);
792                    if fatal {
793                        return;
794                    }
795                }
796            };
797        }
798
799        with_limits!(check_with_fail_fn);
800    }
801
802    /// For each limit in `other` that is better than the value in `self`,
803    /// replace the value in `self` with the value from `other`.
804    ///
805    /// A request for a limit value less than the WebGPU-specified default must
806    /// be ignored. This function is used to clamp such requests to the default
807    /// value.
808    ///
809    /// This function is not for clamping requests for values beyond the
810    /// supported limits. For that purpose the desired function would be
811    /// `or_worse_values_from`.
812    #[must_use]
813    pub fn or_better_values_from(mut self, other: &Self) -> Self {
814        macro_rules! or_better_value_from {
815            ($name:ident, $ordering:expr) => {
816                match $ordering {
817                    // Limits that are maximum values (most of them)
818                    Ordering::Less => self.$name = self.$name.max(other.$name),
819                    // Limits that are minimum values
820                    Ordering::Greater => self.$name = self.$name.min(other.$name),
821                    Ordering::Equal => unreachable!(),
822                }
823            };
824        }
825
826        with_limits!(or_better_value_from);
827
828        self
829    }
830
831    /// For each limit in `other` that is worse than the value in `self`,
832    /// replace the value in `self` with the value from `other`.
833    ///
834    /// This function is for clamping requests for values beyond the
835    /// supported limits.
836    #[must_use]
837    pub fn or_worse_values_from(mut self, other: &Self) -> Self {
838        macro_rules! or_worse_value_from {
839            ($name:ident, $ordering:expr) => {
840                match $ordering {
841                    // Limits that are maximum values (most of them)
842                    Ordering::Less => self.$name = self.$name.min(other.$name),
843                    // Limits that are minimum values
844                    Ordering::Greater => self.$name = self.$name.max(other.$name),
845                    Ordering::Equal => unreachable!(),
846                }
847            };
848        }
849
850        with_limits!(or_worse_value_from);
851
852        self
853    }
854}
855
856/// Represents the sets of additional limits on an adapter,
857/// which take place when running on downlevel backends.
858#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
859#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
860pub struct DownlevelLimits {}
861
862#[allow(clippy::derivable_impls)]
863impl Default for DownlevelLimits {
864    fn default() -> Self {
865        DownlevelLimits {}
866    }
867}
868
869/// Lists various ways the underlying platform does not conform to the WebGPU standard.
870#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
871#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
872pub struct DownlevelCapabilities {
873    /// Combined boolean flags.
874    pub flags: DownlevelFlags,
875    /// Additional limits
876    pub limits: DownlevelLimits,
877    /// Which collections of features shaders support. Defined in terms of D3D's shader models.
878    pub shader_model: ShaderModel,
879}
880
881impl Default for DownlevelCapabilities {
882    fn default() -> Self {
883        Self {
884            flags: DownlevelFlags::all(),
885            limits: DownlevelLimits::default(),
886            shader_model: ShaderModel::Sm5,
887        }
888    }
889}
890
891impl DownlevelCapabilities {
892    /// Returns true if the underlying platform offers complete support of the baseline WebGPU standard.
893    ///
894    /// If this returns false, some parts of the API will result in validation errors where they would not normally.
895    /// These parts can be determined by the values in this structure.
896    #[must_use]
897    pub fn is_webgpu_compliant(&self) -> bool {
898        self.flags.contains(DownlevelFlags::compliant())
899            && self.limits == DownlevelLimits::default()
900            && self.shader_model >= ShaderModel::Sm5
901    }
902}
903
904bitflags::bitflags! {
905    /// Binary flags listing features that may or may not be present on downlevel adapters.
906    ///
907    /// A downlevel adapter is a GPU adapter that wgpu supports, but with potentially limited
908    /// features, due to the lack of hardware feature support.
909    ///
910    /// Flags that are **not** present for a downlevel adapter or device usually indicates
911    /// non-compliance with the WebGPU specification, but not always.
912    ///
913    /// You can check whether a set of flags is compliant through the
914    /// [`DownlevelCapabilities::is_webgpu_compliant()`] function.
915    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
916    #[cfg_attr(feature = "serde", serde(transparent))]
917    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
918    pub struct DownlevelFlags: u32 {
919        /// The device supports compiling and using compute shaders.
920        ///
921        /// WebGL2, and GLES3.0 devices do not support compute.
922        const COMPUTE_SHADERS = 1 << 0;
923        /// Supports binding storage buffers and textures to fragment shaders.
924        const FRAGMENT_WRITABLE_STORAGE = 1 << 1;
925        /// Supports indirect drawing and dispatching.
926        ///
927        /// [`Self::COMPUTE_SHADERS`] must be present for this flag.
928        ///
929        /// WebGL2, GLES 3.0, and Metal on Apple1/Apple2 GPUs do not support indirect.
930        const INDIRECT_EXECUTION = 1 << 2;
931        /// Supports non-zero `base_vertex` parameter to direct indexed draw calls.
932        ///
933        /// Indirect calls, if supported, always support non-zero `base_vertex`.
934        ///
935        /// Supported by:
936        /// - Vulkan
937        /// - DX12
938        /// - Metal on Apple3+ or Mac1+
939        /// - OpenGL 3.2+
940        /// - OpenGL ES 3.2
941        const BASE_VERTEX = 1 << 3;
942        /// Supports reading from a depth/stencil texture while using it as a read-only
943        /// depth/stencil attachment.
944        ///
945        /// The WebGL2 and GLES backends do not support RODS.
946        const READ_ONLY_DEPTH_STENCIL = 1 << 4;
947        /// Supports textures with mipmaps which have a non power of two size.
948        const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 1 << 5;
949        /// Supports textures that are cube arrays.
950        const CUBE_ARRAY_TEXTURES = 1 << 6;
951        /// Supports comparison samplers.
952        const COMPARISON_SAMPLERS = 1 << 7;
953        /// Supports different blend operations per color attachment.
954        const INDEPENDENT_BLEND = 1 << 8;
955        /// Supports storage buffers in vertex shaders.
956        const VERTEX_STORAGE = 1 << 9;
957
958        /// Supports samplers with anisotropic filtering. Note this isn't actually required by
959        /// WebGPU, the implementation is allowed to completely ignore aniso clamp. This flag is
960        /// here for native backends so they can communicate to the user of aniso is enabled.
961        ///
962        /// All backends and all devices support anisotropic filtering.
963        const ANISOTROPIC_FILTERING = 1 << 10;
964
965        /// Supports storage buffers in fragment shaders.
966        const FRAGMENT_STORAGE = 1 << 11;
967
968        /// Supports sample-rate shading.
969        const MULTISAMPLED_SHADING = 1 << 12;
970
971        /// Supports copies between depth textures and buffers.
972        ///
973        /// GLES/WebGL don't support this.
974        const DEPTH_TEXTURE_AND_BUFFER_COPIES = 1 << 13;
975
976        /// Supports all the texture usages described in WebGPU. If this isn't supported, you
977        /// should call `get_texture_format_features` to get how you can use textures of a given format
978        const WEBGPU_TEXTURE_FORMAT_SUPPORT = 1 << 14;
979
980        /// Supports buffer bindings with sizes that aren't a multiple of 16.
981        ///
982        /// WebGL doesn't support this.
983        const BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED = 1 << 15;
984
985        /// Supports buffers to combine [`BufferUsages::INDEX`] with usages other than [`BufferUsages::COPY_DST`] and [`BufferUsages::COPY_SRC`].
986        /// Furthermore, in absence of this feature it is not allowed to copy index buffers from/to buffers with a set of usage flags containing
987        /// [`BufferUsages::VERTEX`]/[`BufferUsages::UNIFORM`]/[`BufferUsages::STORAGE`] or [`BufferUsages::INDIRECT`].
988        ///
989        /// WebGL doesn't support this.
990        const UNRESTRICTED_INDEX_BUFFER = 1 << 16;
991
992        /// Supports full 32-bit range indices (2^32-1 as opposed to 2^24-1 without this flag)
993        ///
994        /// Corresponds to Vulkan's `VkPhysicalDeviceFeatures.fullDrawIndexUint32`
995        const FULL_DRAW_INDEX_UINT32 = 1 << 17;
996
997        /// Supports depth bias clamping
998        ///
999        /// Corresponds to Vulkan's `VkPhysicalDeviceFeatures.depthBiasClamp`
1000        const DEPTH_BIAS_CLAMP = 1 << 18;
1001
1002        /// Supports specifying which view format values are allowed when create_view() is called on a texture.
1003        ///
1004        /// The WebGL and GLES backends doesn't support this.
1005        const VIEW_FORMATS = 1 << 19;
1006
1007        /// With this feature not present, there are the following restrictions on `Queue::copy_external_image_to_texture`:
1008        /// - The source must not be [`web_sys::OffscreenCanvas`]
1009        /// - [`CopyExternalImageSourceInfo::origin`] must be zero.
1010        /// - [`CopyExternalImageDestInfo::color_space`] must be srgb.
1011        /// - If the source is an [`web_sys::ImageBitmap`]:
1012        ///   - [`CopyExternalImageSourceInfo::flip_y`] must be false.
1013        ///   - [`CopyExternalImageDestInfo::premultiplied_alpha`] must be false.
1014        ///
1015        /// WebGL doesn't support this. WebGPU does.
1016        const UNRESTRICTED_EXTERNAL_TEXTURE_COPIES = 1 << 20;
1017
1018        /// Supports specifying which view formats are allowed when calling create_view on the texture returned by
1019        /// `Surface::get_current_texture`.
1020        ///
1021        /// The GLES/WebGL and Vulkan on Android doesn't support this.
1022        const SURFACE_VIEW_FORMATS = 1 << 21;
1023
1024        /// If this is true, calls to `CommandEncoder::resolve_query_set` will be performed on the queue timeline.
1025        ///
1026        /// If this is false, calls to `CommandEncoder::resolve_query_set` will be performed on the device (i.e. cpu) timeline
1027        /// and will block that timeline until the query has data. You may work around this limitation by waiting until the submit
1028        /// whose queries you are resolving is fully finished (through use of `queue.on_submitted_work_done`) and only
1029        /// then submitting the resolve_query_set command. The queries will be guaranteed finished, so will not block.
1030        ///
1031        /// Supported by:
1032        /// - Vulkan,
1033        /// - DX12
1034        /// - Metal
1035        /// - OpenGL 4.4+
1036        ///
1037        /// Not Supported by:
1038        /// - GL ES / WebGL
1039        const NONBLOCKING_QUERY_RESOLVE = 1 << 22;
1040
1041        /// Allows shaders to use `quantizeToF16`, `pack2x16float`, and `unpack2x16float`, which
1042        /// operate on `f16`-precision values stored in `f32`s.
1043        ///
1044        /// Not supported by Vulkan on Mesa when [`Features::SHADER_F16`] is absent.
1045        const SHADER_F16_IN_F32 = 1 << 23;
1046    }
1047}
1048
1049impl DownlevelFlags {
1050    /// All flags that indicate if the backend is WebGPU compliant
1051    #[must_use]
1052    pub const fn compliant() -> Self {
1053        // We use manual bit twiddling to make this a const fn as `Sub` and `.remove` aren't const
1054
1055        // WebGPU doesn't actually require aniso
1056        Self::from_bits_truncate(Self::all().bits() & !Self::ANISOTROPIC_FILTERING.bits())
1057    }
1058}
1059
1060/// Collections of shader features a device supports if they support less than WebGPU normally allows.
1061// TODO: Fill out the differences between shader models more completely
1062#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1063#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1064pub enum ShaderModel {
1065    /// Extremely limited shaders, including a total instruction limit.
1066    Sm2,
1067    /// Missing minor features and storage images.
1068    Sm4,
1069    /// WebGPU supports shader module 5.
1070    Sm5,
1071}
1072
1073#[cfg(test)]
1074mod tests {
1075    use super::*;
1076    use alloc::{format, string::String, vec::Vec};
1077
1078    fn side_by_side(left: &str, right: &str) -> String {
1079        let left_lines: Vec<&str> = left.lines().map(str::trim).collect();
1080        let right_lines: Vec<&str> = right.lines().map(str::trim).collect();
1081        let max_lines = left_lines.len().max(right_lines.len());
1082        let diffs: Vec<(&str, &str)> = (0..max_lines)
1083            .map(|i| {
1084                let l = *left_lines.get(i).unwrap_or(&"");
1085                let r = *right_lines.get(i).unwrap_or(&"");
1086                (l, r)
1087            })
1088            .filter(|(l, r)| l != r)
1089            .collect();
1090        let left_width = diffs.iter().map(|(l, _)| l.len()).max().unwrap_or(0);
1091        let mut out = String::new();
1092        for (l, r) in &diffs {
1093            out += &format!("{:<width$}  |  {}\n", l, r, width = left_width);
1094        }
1095        out
1096    }
1097
1098    #[test]
1099    fn with_limits_exhaustive() {
1100        // Check that all limits are included in `with_limits!`, by using it to
1101        // replicate `Limits::unlimited()`.
1102        let mut limits = Limits::default();
1103
1104        macro_rules! set_to_max {
1105            ($name:ident, $ordering:expr) => {
1106                if $ordering == Ordering::Less {
1107                    limits.$name = i32::MAX as _;
1108                } else {
1109                    limits.$name = 1;
1110                }
1111            };
1112        }
1113
1114        with_limits!(set_to_max);
1115
1116        assert_eq!(
1117            limits,
1118            Limits::unlimited(),
1119            "with_limits! did not replicate Limits::unlimited():\n{}",
1120            side_by_side(
1121                &format!("with_limits!\n------------\n{:#?}", limits),
1122                &format!(
1123                    "Limits::unlimited()\n-------------------\n{:#?}",
1124                    Limits::unlimited()
1125                ),
1126            )
1127        );
1128    }
1129}