Skip to main content

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