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