Skip to main content

script_webgpu/
gpusupportedlimits.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::marker::PhantomData;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use malloc_size_of_derive::MallocSizeOf;
10use num_traits::bounds::UpperBounded;
11use script_bindings::DomTypes;
12use script_bindings::codegen::GenericBindings::WebGPUBinding::{
13    GPUSupportedLimitsMethods, GPUSupportedLimitsWrap,
14};
15use script_bindings::reflector::{Reflector, reflect_dom_object_with_wrap};
16use wgpu_types::Limits;
17
18use crate::JSTraceable;
19use crate::dom::bindings::root::DomRoot;
20use crate::traits::Equivalence;
21
22/// <https://gpuweb.github.io/gpuweb/#gpusupportedlimits>
23#[dom_struct]
24pub struct GPUSupportedLimits<D: DomTypes> {
25    reflector_: Reflector,
26    #[ignore_malloc_size_of = "defined in wgpu-types"]
27    #[no_trace]
28    limits: Limits,
29    #[no_trace = "PhantomData does not exist"]
30    phantom: PhantomData<D>,
31}
32
33impl<D: Equivalence> GPUSupportedLimits<D> {
34    fn new_inherited(limits: Limits) -> Self {
35        Self {
36            reflector_: Reflector::new(),
37            limits,
38            phantom: PhantomData,
39        }
40    }
41
42    pub fn new(cx: &mut JSContext, global: &D::GlobalScope, limits: Limits) -> DomRoot<Self> {
43        reflect_dom_object_with_wrap::<D, _, _>(
44            Box::new(Self::new_inherited(limits)),
45            global,
46            cx,
47            GPUSupportedLimitsWrap::<D>,
48        )
49    }
50}
51
52// Limits are ordered by their declaration in the spec.
53impl<D: DomTypes> GPUSupportedLimitsMethods<D> for GPUSupportedLimits<D> {
54    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturedimension1d>
55    fn MaxTextureDimension1D(&self) -> u32 {
56        self.limits.max_texture_dimension_1d
57    }
58
59    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturedimension2d>
60    fn MaxTextureDimension2D(&self) -> u32 {
61        self.limits.max_texture_dimension_2d
62    }
63
64    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturedimension3d>
65    fn MaxTextureDimension3D(&self) -> u32 {
66        self.limits.max_texture_dimension_3d
67    }
68
69    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturearraylayers>
70    fn MaxTextureArrayLayers(&self) -> u32 {
71        self.limits.max_texture_array_layers
72    }
73
74    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbindgroups>
75    fn MaxBindGroups(&self) -> u32 {
76        self.limits.max_bind_groups
77    }
78
79    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbindgroupsplusvertexbuffers>
80    fn MaxBindGroupsPlusVertexBuffers(&self) -> u32 {
81        self.limits.max_bind_groups_plus_vertex_buffers
82    }
83
84    /*
85    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maximmediatesize>
86    fn MaxImmediateSize(&self) -> u32 {
87        self.limits.max_immediate_size
88    }
89    */
90
91    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbindingsperbindgroup>
92    fn MaxBindingsPerBindGroup(&self) -> u32 {
93        self.limits.max_bindings_per_bind_group
94    }
95
96    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxdynamicuniformbuffersperpipelinelayout>
97    fn MaxDynamicUniformBuffersPerPipelineLayout(&self) -> u32 {
98        self.limits.max_dynamic_uniform_buffers_per_pipeline_layout
99    }
100
101    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxdynamicstoragebuffersperpipelinelayout>
102    fn MaxDynamicStorageBuffersPerPipelineLayout(&self) -> u32 {
103        self.limits.max_dynamic_storage_buffers_per_pipeline_layout
104    }
105
106    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxsampledtexturespershaderstage>
107    fn MaxSampledTexturesPerShaderStage(&self) -> u32 {
108        self.limits.max_sampled_textures_per_shader_stage
109    }
110
111    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxsamplerspershaderstage>
112    fn MaxSamplersPerShaderStage(&self) -> u32 {
113        self.limits.max_samplers_per_shader_stage
114    }
115
116    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragebufferspershaderstage>
117    fn MaxStorageBuffersPerShaderStage(&self) -> u32 {
118        self.limits.max_storage_buffers_per_shader_stage
119    }
120
121    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragebuffersinvertexstage>
122    fn MaxStorageBuffersInVertexStage(&self) -> u32 {
123        // Not in wgpu yet (https://github.com/gfx-rs/wgpu/issues/8748), report per stage limit instead
124        self.limits.max_storage_buffers_per_shader_stage
125    }
126
127    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragebuffersinfragmentstage>
128    fn MaxStorageBuffersInFragmentStage(&self) -> u32 {
129        // Not in wgpu yet (https://github.com/gfx-rs/wgpu/issues/8748), report per stage limit instead
130        self.limits.max_storage_buffers_per_shader_stage
131    }
132
133    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragetexturespershaderstage>
134    fn MaxStorageTexturesPerShaderStage(&self) -> u32 {
135        self.limits.max_storage_textures_per_shader_stage
136    }
137
138    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragetexturesinvertexstage>
139    fn MaxStorageTexturesInVertexStage(&self) -> u32 {
140        // Not in wgpu yet (https://github.com/gfx-rs/wgpu/issues/8748), report per stage limit instead
141        self.limits.max_storage_textures_per_shader_stage
142    }
143
144    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragetexturesinfragmentstage>
145    fn MaxStorageTexturesInFragmentStage(&self) -> u32 {
146        // Not in wgpu yet (https://github.com/gfx-rs/wgpu/issues/8748), report per stage limit instead
147        self.limits.max_storage_textures_per_shader_stage
148    }
149
150    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxuniformbufferspershaderstage>
151    fn MaxUniformBuffersPerShaderStage(&self) -> u32 {
152        self.limits.max_uniform_buffers_per_shader_stage
153    }
154
155    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxuniformbufferbindingsize>
156    fn MaxUniformBufferBindingSize(&self) -> u64 {
157        self.limits.max_uniform_buffer_binding_size
158    }
159
160    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragebufferbindingsize>
161    fn MaxStorageBufferBindingSize(&self) -> u64 {
162        self.limits.max_storage_buffer_binding_size
163    }
164
165    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-minuniformbufferoffsetalignment>
166    fn MinUniformBufferOffsetAlignment(&self) -> u32 {
167        self.limits.min_uniform_buffer_offset_alignment
168    }
169
170    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-minstoragebufferoffsetalignment>
171    fn MinStorageBufferOffsetAlignment(&self) -> u32 {
172        self.limits.min_storage_buffer_offset_alignment
173    }
174
175    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxvertexbuffers>
176    fn MaxVertexBuffers(&self) -> u32 {
177        self.limits.max_vertex_buffers
178    }
179
180    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbuffersize>
181    fn MaxBufferSize(&self) -> u64 {
182        self.limits.max_buffer_size
183    }
184
185    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxvertexattributes>
186    fn MaxVertexAttributes(&self) -> u32 {
187        self.limits.max_vertex_attributes
188    }
189
190    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxvertexbufferarraystride>
191    fn MaxVertexBufferArrayStride(&self) -> u32 {
192        self.limits.max_vertex_buffer_array_stride
193    }
194
195    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxinterstageshadervariables>
196    fn MaxInterStageShaderVariables(&self) -> u32 {
197        self.limits.max_inter_stage_shader_variables
198    }
199
200    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcolorattachments>
201    fn MaxColorAttachments(&self) -> u32 {
202        self.limits.max_color_attachments
203    }
204
205    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcolorattachmentbytespersample>
206    fn MaxColorAttachmentBytesPerSample(&self) -> u32 {
207        self.limits.max_color_attachment_bytes_per_sample
208    }
209
210    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupstoragesize>
211    fn MaxComputeWorkgroupStorageSize(&self) -> u32 {
212        self.limits.max_compute_workgroup_storage_size
213    }
214
215    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeinvocationsperworkgroup>
216    fn MaxComputeInvocationsPerWorkgroup(&self) -> u32 {
217        self.limits.max_compute_invocations_per_workgroup
218    }
219
220    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsizex>
221    fn MaxComputeWorkgroupSizeX(&self) -> u32 {
222        self.limits.max_compute_workgroup_size_x
223    }
224
225    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsizey>
226    fn MaxComputeWorkgroupSizeY(&self) -> u32 {
227        self.limits.max_compute_workgroup_size_y
228    }
229
230    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsizez>
231    fn MaxComputeWorkgroupSizeZ(&self) -> u32 {
232        self.limits.max_compute_workgroup_size_z
233    }
234
235    /// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsperdimension>
236    fn MaxComputeWorkgroupsPerDimension(&self) -> u32 {
237        self.limits.max_compute_workgroups_per_dimension
238    }
239}
240
241/// Returns false if unknown limit or other value error
242pub(crate) fn set_limit(limits: &mut Limits, limit: &str, value: u64) -> bool {
243    /// per spec defaults are lower bounds for values
244    ///
245    /// <https://www.w3.org/TR/webgpu/#limit-class-maximum>
246    fn set_maximum<T>(limit: &mut T, value: u64) -> bool
247    where
248        T: Ord + Copy + TryFrom<u64> + UpperBounded,
249    {
250        if let Ok(value) = T::try_from(value) {
251            *limit = value.max(*limit);
252            true
253        } else {
254            false
255        }
256    }
257
258    /// per spec defaults are higher bounds for values
259    ///
260    /// <https://www.w3.org/TR/webgpu/#limit-class-alignment>
261    fn set_alignment<T>(limit: &mut T, value: u64) -> bool
262    where
263        T: Ord + Copy + TryFrom<u64> + UpperBounded,
264    {
265        if !value.is_power_of_two() {
266            return false;
267        }
268        if let Ok(value) = T::try_from(value) {
269            *limit = value.min(*limit);
270            true
271        } else {
272            false
273        }
274    }
275
276    // Limits are ordered by their declaration in the spec.
277    match limit {
278        "maxTextureDimension1D" => set_maximum(&mut limits.max_texture_dimension_1d, value),
279        "maxTextureDimension2D" => set_maximum(&mut limits.max_texture_dimension_2d, value),
280        "maxTextureDimension3D" => set_maximum(&mut limits.max_texture_dimension_3d, value),
281        "maxTextureArrayLayers" => set_maximum(&mut limits.max_texture_array_layers, value),
282        "maxBindGroups" => set_maximum(&mut limits.max_bind_groups, value),
283        "maxBindGroupsPlusVertexBuffers" => {
284            set_maximum(&mut limits.max_bind_groups_plus_vertex_buffers, value)
285        },
286        "maxImmediateSize" => set_maximum(&mut limits.max_immediate_size, value),
287        "maxBindingsPerBindGroup" => set_maximum(&mut limits.max_bindings_per_bind_group, value),
288        "maxDynamicUniformBuffersPerPipelineLayout" => set_maximum(
289            &mut limits.max_dynamic_uniform_buffers_per_pipeline_layout,
290            value,
291        ),
292        "maxDynamicStorageBuffersPerPipelineLayout" => set_maximum(
293            &mut limits.max_dynamic_storage_buffers_per_pipeline_layout,
294            value,
295        ),
296        "maxSampledTexturesPerShaderStage" => {
297            set_maximum(&mut limits.max_sampled_textures_per_shader_stage, value)
298        },
299        "maxSamplersPerShaderStage" => {
300            set_maximum(&mut limits.max_samplers_per_shader_stage, value)
301        },
302        "maxStorageBuffersPerShaderStage" => {
303            set_maximum(&mut limits.max_storage_buffers_per_shader_stage, value)
304        },
305        "maxStorageBuffersInVertexStage" => {
306            // not in wgpu (https://github.com/gfx-rs/wgpu/issues/8748)
307            // but we're allowed to give back better limits than requested.
308            // we use dummy value to still produce value verification
309            let mut v: u32 = 0;
310            set_maximum(&mut v, value)
311        },
312        "maxStorageBuffersInFragmentStage" => {
313            // not in wgpu (https://github.com/gfx-rs/wgpu/issues/8748)
314            // but we're allowed to give back better limits than requested.
315            // we use dummy value to still produce value verification
316            let mut v: u32 = 0;
317            set_maximum(&mut v, value)
318        },
319        "maxStorageTexturesPerShaderStage" => {
320            set_maximum(&mut limits.max_storage_textures_per_shader_stage, value)
321        },
322        "maxStorageTexturesInVertexStage" => {
323            // not in wgpu (https://github.com/gfx-rs/wgpu/issues/8748)
324            // but we're allowed to give back better limits than requested.
325            // we use dummy value to still produce value verification
326            let mut v: u32 = 0;
327            set_maximum(&mut v, value)
328        },
329        "maxStorageTexturesInFragmentStage" => {
330            // not in wgpu (https://github.com/gfx-rs/wgpu/issues/8748)
331            // but we're allowed to give back better limits than requested.
332            // we use dummy value to still produce value verification
333            let mut v: u32 = 0;
334            set_maximum(&mut v, value)
335        },
336        "maxUniformBuffersPerShaderStage" => {
337            set_maximum(&mut limits.max_uniform_buffers_per_shader_stage, value)
338        },
339        "maxUniformBufferBindingSize" => {
340            set_maximum(&mut limits.max_uniform_buffer_binding_size, value)
341        },
342        "maxStorageBufferBindingSize" => {
343            set_maximum(&mut limits.max_storage_buffer_binding_size, value)
344        },
345        "minUniformBufferOffsetAlignment" => {
346            set_alignment(&mut limits.min_uniform_buffer_offset_alignment, value)
347        },
348        "minStorageBufferOffsetAlignment" => {
349            set_alignment(&mut limits.min_storage_buffer_offset_alignment, value)
350        },
351        "maxVertexBuffers" => set_maximum(&mut limits.max_vertex_buffers, value),
352        "maxBufferSize" => set_maximum(&mut limits.max_buffer_size, value),
353        "maxVertexAttributes" => set_maximum(&mut limits.max_vertex_attributes, value),
354        "maxVertexBufferArrayStride" => {
355            set_maximum(&mut limits.max_vertex_buffer_array_stride, value)
356        },
357        "maxInterStageShaderVariables" => {
358            set_maximum(&mut limits.max_inter_stage_shader_variables, value)
359        },
360        "maxColorAttachments" => set_maximum(&mut limits.max_color_attachments, value),
361        "maxColorAttachmentBytesPerSample" => {
362            set_maximum(&mut limits.max_color_attachment_bytes_per_sample, value)
363        },
364        "maxComputeWorkgroupStorageSize" => {
365            set_maximum(&mut limits.max_compute_workgroup_storage_size, value)
366        },
367        "maxComputeInvocationsPerWorkgroup" => {
368            set_maximum(&mut limits.max_compute_invocations_per_workgroup, value)
369        },
370        "maxComputeWorkgroupSizeX" => set_maximum(&mut limits.max_compute_workgroup_size_x, value),
371        "maxComputeWorkgroupSizeY" => set_maximum(&mut limits.max_compute_workgroup_size_y, value),
372        "maxComputeWorkgroupSizeZ" => set_maximum(&mut limits.max_compute_workgroup_size_z, value),
373        "maxComputeWorkgroupsPerDimension" => {
374            set_maximum(&mut limits.max_compute_workgroups_per_dimension, value)
375        },
376        _ => false,
377    }
378}