/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; use num_traits::bounds::UpperBounded; use webgpu::wgt::Limits; use GPUSupportedLimits_Binding::GPUSupportedLimitsMethods; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUSupportedLimits_Binding; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; #[dom_struct] pub(crate) struct GPUSupportedLimits { reflector_: Reflector, #[ignore_malloc_size_of = "defined in wgpu-types"] #[no_trace] limits: Limits, } impl GPUSupportedLimits { fn new_inherited(limits: Limits) -> Self { Self { reflector_: Reflector::new(), limits, } } pub(crate) fn new(global: &GlobalScope, limits: Limits, can_gc: CanGc) -> DomRoot { reflect_dom_object(Box::new(Self::new_inherited(limits)), global, can_gc) } } impl GPUSupportedLimitsMethods for GPUSupportedLimits { /// fn MaxTextureDimension1D(&self) -> u32 { self.limits.max_texture_dimension_1d } /// fn MaxTextureDimension2D(&self) -> u32 { self.limits.max_texture_dimension_2d } /// fn MaxTextureDimension3D(&self) -> u32 { self.limits.max_texture_dimension_3d } /// fn MaxTextureArrayLayers(&self) -> u32 { self.limits.max_texture_array_layers } /// fn MaxBindGroups(&self) -> u32 { self.limits.max_bind_groups } /// fn MaxBindingsPerBindGroup(&self) -> u32 { self.limits.max_bindings_per_bind_group } /// fn MaxDynamicUniformBuffersPerPipelineLayout(&self) -> u32 { self.limits.max_dynamic_uniform_buffers_per_pipeline_layout } /// fn MaxDynamicStorageBuffersPerPipelineLayout(&self) -> u32 { self.limits.max_dynamic_storage_buffers_per_pipeline_layout } /// fn MaxSampledTexturesPerShaderStage(&self) -> u32 { self.limits.max_sampled_textures_per_shader_stage } /// fn MaxSamplersPerShaderStage(&self) -> u32 { self.limits.max_samplers_per_shader_stage } /// fn MaxStorageBuffersPerShaderStage(&self) -> u32 { self.limits.max_storage_buffers_per_shader_stage } /// fn MaxStorageTexturesPerShaderStage(&self) -> u32 { self.limits.max_storage_textures_per_shader_stage } /// fn MaxUniformBuffersPerShaderStage(&self) -> u32 { self.limits.max_uniform_buffers_per_shader_stage } /// fn MaxUniformBufferBindingSize(&self) -> u64 { self.limits.max_uniform_buffer_binding_size as u64 } /// fn MaxStorageBufferBindingSize(&self) -> u64 { self.limits.max_storage_buffer_binding_size as u64 } /// fn MinUniformBufferOffsetAlignment(&self) -> u32 { self.limits.min_uniform_buffer_offset_alignment } /// fn MinStorageBufferOffsetAlignment(&self) -> u32 { self.limits.min_storage_buffer_offset_alignment } /// fn MaxVertexBuffers(&self) -> u32 { self.limits.max_vertex_buffers } /// fn MaxBufferSize(&self) -> u64 { self.limits.max_buffer_size } /// fn MaxVertexAttributes(&self) -> u32 { self.limits.max_vertex_attributes } /// fn MaxVertexBufferArrayStride(&self) -> u32 { self.limits.max_vertex_buffer_array_stride } /// fn MaxInterStageShaderComponents(&self) -> u32 { self.limits.max_inter_stage_shader_components } /// fn MaxComputeWorkgroupStorageSize(&self) -> u32 { self.limits.max_compute_workgroup_storage_size } /// fn MaxComputeInvocationsPerWorkgroup(&self) -> u32 { self.limits.max_compute_invocations_per_workgroup } /// fn MaxComputeWorkgroupSizeX(&self) -> u32 { self.limits.max_compute_workgroup_size_x } /// fn MaxComputeWorkgroupSizeY(&self) -> u32 { self.limits.max_compute_workgroup_size_y } /// fn MaxComputeWorkgroupSizeZ(&self) -> u32 { self.limits.max_compute_workgroup_size_z } /// fn MaxComputeWorkgroupsPerDimension(&self) -> u32 { self.limits.max_compute_workgroups_per_dimension } /// fn MaxBindGroupsPlusVertexBuffers(&self) -> u32 { // Not on wgpu yet, so we craft it manually self.limits.max_bind_groups + self.limits.max_vertex_buffers } /// fn MaxInterStageShaderVariables(&self) -> u32 { // Not in wgpu yet, so we use default value from spec 16 } /// fn MaxColorAttachments(&self) -> u32 { self.limits.max_color_attachments } /// fn MaxColorAttachmentBytesPerSample(&self) -> u32 { self.limits.max_color_attachment_bytes_per_sample } } /// Returns false if unknown limit or other value error pub(crate) fn set_limit(limits: &mut Limits, limit: &str, value: u64) -> bool { /// per spec defaults are lower bounds for values /// /// fn set_maximum(limit: &mut T, value: u64) -> bool where T: Ord + Copy + TryFrom + UpperBounded, { if let Ok(value) = T::try_from(value) { *limit = value.max(*limit); true } else { false } } /// per spec defaults are higher bounds for values /// /// fn set_alignment(limit: &mut T, value: u64) -> bool where T: Ord + Copy + TryFrom + UpperBounded, { if !value.is_power_of_two() { return false; } if let Ok(value) = T::try_from(value) { *limit = value.min(*limit); true } else { false } } match limit { "maxTextureDimension1D" => set_maximum(&mut limits.max_texture_dimension_1d, value), "maxTextureDimension2D" => set_maximum(&mut limits.max_texture_dimension_2d, value), "maxTextureDimension3D" => set_maximum(&mut limits.max_texture_dimension_3d, value), "maxTextureArrayLayers" => set_maximum(&mut limits.max_texture_array_layers, value), "maxBindGroups" => set_maximum(&mut limits.max_bind_groups, value), "maxBindGroupsPlusVertexBuffers" => { // not in wgpu but we're allowed to give back better limits than requested. // we use dummy value to still produce value verification let mut v: u32 = 0; set_maximum(&mut v, value) }, "maxBindingsPerBindGroup" => set_maximum(&mut limits.max_bindings_per_bind_group, value), "maxDynamicUniformBuffersPerPipelineLayout" => set_maximum( &mut limits.max_dynamic_uniform_buffers_per_pipeline_layout, value, ), "maxDynamicStorageBuffersPerPipelineLayout" => set_maximum( &mut limits.max_dynamic_storage_buffers_per_pipeline_layout, value, ), "maxSampledTexturesPerShaderStage" => { set_maximum(&mut limits.max_sampled_textures_per_shader_stage, value) }, "maxSamplersPerShaderStage" => { set_maximum(&mut limits.max_samplers_per_shader_stage, value) }, "maxStorageBuffersPerShaderStage" => { set_maximum(&mut limits.max_storage_buffers_per_shader_stage, value) }, "maxStorageTexturesPerShaderStage" => { set_maximum(&mut limits.max_storage_textures_per_shader_stage, value) }, "maxUniformBuffersPerShaderStage" => { set_maximum(&mut limits.max_uniform_buffers_per_shader_stage, value) }, "maxUniformBufferBindingSize" => { set_maximum(&mut limits.max_uniform_buffer_binding_size, value) }, "maxStorageBufferBindingSize" => { set_maximum(&mut limits.max_storage_buffer_binding_size, value) }, "minUniformBufferOffsetAlignment" => { set_alignment(&mut limits.min_uniform_buffer_offset_alignment, value) }, "minStorageBufferOffsetAlignment" => { set_alignment(&mut limits.min_storage_buffer_offset_alignment, value) }, "maxVertexBuffers" => set_maximum(&mut limits.max_vertex_buffers, value), "maxBufferSize" => set_maximum(&mut limits.max_buffer_size, value), "maxVertexAttributes" => set_maximum(&mut limits.max_vertex_attributes, value), "maxVertexBufferArrayStride" => { set_maximum(&mut limits.max_vertex_buffer_array_stride, value) }, "maxInterStageShaderComponents" => { set_maximum(&mut limits.max_inter_stage_shader_components, value) }, "maxInterStageShaderVariables" => { // not in wgpu but we're allowed to give back better limits than requested. // we use dummy value to still produce value verification let mut v: u32 = 0; set_maximum(&mut v, value) }, "maxColorAttachments" => set_maximum(&mut limits.max_color_attachments, value), "maxColorAttachmentBytesPerSample" => { set_maximum(&mut limits.max_color_attachment_bytes_per_sample, value) }, "maxComputeWorkgroupStorageSize" => { set_maximum(&mut limits.max_compute_workgroup_storage_size, value) }, "maxComputeInvocationsPerWorkgroup" => { set_maximum(&mut limits.max_compute_invocations_per_workgroup, value) }, "maxComputeWorkgroupSizeX" => set_maximum(&mut limits.max_compute_workgroup_size_x, value), "maxComputeWorkgroupSizeY" => set_maximum(&mut limits.max_compute_workgroup_size_y, value), "maxComputeWorkgroupSizeZ" => set_maximum(&mut limits.max_compute_workgroup_size_z, value), "maxComputeWorkgroupsPerDimension" => { set_maximum(&mut limits.max_compute_workgroups_per_dimension, value) }, _ => false, } }