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