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