wgpu_types/
limits.rs

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