diff --git a/wgpu-hal/src/auxil/mod.rs b/wgpu-hal/src/auxil/mod.rs index f0aa6a4a892..0ad026247bf 100644 --- a/wgpu-hal/src/auxil/mod.rs +++ b/wgpu-hal/src/auxil/mod.rs @@ -46,6 +46,14 @@ pub mod db { /// offset at some intermediate point, internally, as i32. pub const MAX_I32_BINDING_SIZE: u32 = 1 << 31; +/// Per the [WebGPU spec.]: +/// +/// > **_max shader stages per pipeline_** is `2`, because a `GPURenderPipeline` supports both +/// > a vertex and fragment shader. +/// +/// [WebGPU spec.]: https://gpuweb.github.io/gpuweb/#max-shader-stages-per-pipeline +pub(crate) const MAX_SHADER_STAGES_PER_PIPELINE: u32 = 2; + pub fn map_naga_stage(stage: naga::ShaderStage) -> wgt::ShaderStages { match stage { naga::ShaderStage::Vertex => wgt::ShaderStages::VERTEX, diff --git a/wgpu-hal/src/dx11/adapter.rs b/wgpu-hal/src/dx11/adapter.rs index a28106a9bbf..821ce94ff8f 100644 --- a/wgpu-hal/src/dx11/adapter.rs +++ b/wgpu-hal/src/dx11/adapter.rs @@ -2,6 +2,8 @@ use std::num::NonZeroU64; use winapi::um::{d3d11, d3dcommon}; +use crate::auxil::MAX_SHADER_STAGES_PER_PIPELINE; + impl crate::Adapter for super::Adapter { unsafe fn open( &self, @@ -203,6 +205,19 @@ impl super::Adapter { let max_compute_workgroups_per_dimension = d3d11::D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + let max_sampled_textures_per_shader_stage = max_sampled_textures; + let max_samplers_per_shader_stage = max_samplers; + let max_storage_buffers_per_shader_stage = max_uavs; + let max_storage_textures_per_shader_stage = max_uavs; + let max_uniform_buffers_per_shader_stage = max_constant_buffers; + + let max_bindings_per_bind_group = (max_sampled_textures_per_shader_stage + + max_samplers_per_shader_stage + + max_storage_buffers_per_shader_stage + + max_storage_textures_per_shader_stage + + max_uniform_buffers_per_shader_stage) + * MAX_SHADER_STAGES_PER_PIPELINE; + let limits = wgt::Limits { max_texture_dimension_1d: max_texture_dimension_2d, max_texture_dimension_2d, @@ -212,11 +227,11 @@ impl super::Adapter { max_bindings_per_bind_group: 65535, max_dynamic_uniform_buffers_per_pipeline_layout: max_constant_buffers, max_dynamic_storage_buffers_per_pipeline_layout: 0, - max_sampled_textures_per_shader_stage: max_sampled_textures, - max_samplers_per_shader_stage: max_samplers, - max_storage_buffers_per_shader_stage: max_uavs, - max_storage_textures_per_shader_stage: max_uavs, - max_uniform_buffers_per_shader_stage: max_constant_buffers, + max_sampled_textures_per_shader_stage, + max_samplers_per_shader_stage, + max_storage_buffers_per_shader_stage, + max_storage_textures_per_shader_stage, + max_uniform_buffers_per_shader_stage, max_uniform_buffer_binding_size: 1 << 16, max_storage_buffer_binding_size: u32::MAX, max_vertex_buffers, diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 27e8e8e05f8..155b3358504 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -1,5 +1,5 @@ use crate::{ - auxil::{self, dxgi::result::HResult as _}, + auxil::{self, dxgi::result::HResult as _, MAX_SHADER_STAGES_PER_PIPELINE}, dx12::SurfaceTarget, }; use std::{mem, ptr, sync::Arc, thread}; @@ -277,6 +277,28 @@ impl super::Adapter { let base = wgt::Limits::default(); + let max_sampled_textures_per_shader_stage = match options.ResourceBindingTier { + d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 128, + _ => full_heap_count, + }; + let max_samplers_per_shader_stage = match options.ResourceBindingTier { + d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 16, + _ => d3d12_ty::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE, + }; + // these both account towards `uav_count`, but we can't express the limit as as sum + // of the two, so we divide it by 4 to account for the worst case scenario + // (2 shader stages, with both using 16 storage textures and 16 storage buffers) + let max_storage_buffers_per_shader_stage = uav_count / 4; + let max_storage_textures_per_shader_stage = uav_count / 4; + let max_uniform_buffers_per_shader_stage = full_heap_count; + + let max_bindings_per_bind_group = (max_sampled_textures_per_shader_stage + + max_samplers_per_shader_stage + + max_storage_buffers_per_shader_stage + + max_storage_textures_per_shader_stage + + max_uniform_buffers_per_shader_stage) + * MAX_SHADER_STAGES_PER_PIPELINE; + Some(crate::ExposedAdapter { adapter: super::Adapter { raw: adapter, @@ -297,26 +319,17 @@ impl super::Adapter { max_texture_dimension_3d: d3d12_ty::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION, max_texture_array_layers: d3d12_ty::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION, max_bind_groups: crate::MAX_BIND_GROUPS as u32, - max_bindings_per_bind_group: 65535, + max_bindings_per_bind_group, // dynamic offsets take a root constant, so we expose the minimum here max_dynamic_uniform_buffers_per_pipeline_layout: base .max_dynamic_uniform_buffers_per_pipeline_layout, max_dynamic_storage_buffers_per_pipeline_layout: base .max_dynamic_storage_buffers_per_pipeline_layout, - max_sampled_textures_per_shader_stage: match options.ResourceBindingTier { - d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 128, - _ => full_heap_count, - }, - max_samplers_per_shader_stage: match options.ResourceBindingTier { - d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 16, - _ => d3d12_ty::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE, - }, - // these both account towards `uav_count`, but we can't express the limit as as sum - // of the two, so we divide it by 4 to account for the worst case scenario - // (2 shader stages, with both using 16 storage textures and 16 storage buffers) - max_storage_buffers_per_shader_stage: uav_count / 4, - max_storage_textures_per_shader_stage: uav_count / 4, - max_uniform_buffers_per_shader_stage: full_heap_count, + max_sampled_textures_per_shader_stage, + max_samplers_per_shader_stage, + max_storage_buffers_per_shader_stage, + max_storage_textures_per_shader_stage, + max_uniform_buffers_per_shader_stage, max_uniform_buffer_binding_size: d3d12_ty::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16, max_storage_buffer_binding_size: crate::auxil::MAX_I32_BINDING_SIZE, diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 5594dfa237b..e6d076c7ec7 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -499,6 +499,16 @@ impl super::Adapter { 0 }; + let max_sampled_textures_per_shader_stage = super::MAX_TEXTURE_SLOTS as u32; + let max_samplers_per_shader_stage = super::MAX_SAMPLERS as u32; + + let max_bindings_per_bind_group = (max_sampled_textures_per_shader_stage + + max_samplers_per_shader_stage + + max_storage_buffers_per_shader_stage + + max_storage_textures_per_shader_stage + + max_uniform_buffers_per_shader_stage) + * crate::auxil::MAX_SHADER_STAGES_PER_PIPELINE; + let limits = wgt::Limits { max_texture_dimension_1d: max_texture_size, max_texture_dimension_2d: max_texture_size, @@ -507,11 +517,11 @@ impl super::Adapter { gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS) } as u32, max_bind_groups: crate::MAX_BIND_GROUPS as u32, - max_bindings_per_bind_group: 65535, + max_bindings_per_bind_group, max_dynamic_uniform_buffers_per_pipeline_layout: max_uniform_buffers_per_shader_stage, max_dynamic_storage_buffers_per_pipeline_layout: max_storage_buffers_per_shader_stage, - max_sampled_textures_per_shader_stage: super::MAX_TEXTURE_SLOTS as u32, - max_samplers_per_shader_stage: super::MAX_SAMPLERS as u32, + max_sampled_textures_per_shader_stage, + max_samplers_per_shader_stage, max_storage_buffers_per_shader_stage, max_storage_textures_per_shader_stage, max_uniform_buffers_per_shader_stage, diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index c5e6316c195..dddf03e4d5a 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -1,3 +1,4 @@ +use crate::auxil::MAX_SHADER_STAGES_PER_PIPELINE; use metal::{MTLFeatureSet, MTLGPUFamily, MTLLanguageVersion, MTLReadWriteTextureTier}; use objc::{class, msg_send, sel, sel_impl}; use parking_lot::Mutex; @@ -829,6 +830,19 @@ impl super::PrivateCapabilities { .flags .set(wgt::DownlevelFlags::ANISOTROPIC_FILTERING, true); + let max_sampled_textures_per_shader_stage = self.max_textures_per_stage; + let max_samplers_per_shader_stage = self.max_samplers_per_stage; + let max_storage_buffers_per_shader_stage = self.max_buffers_per_stage; + let max_storage_textures_per_shader_stage = self.max_textures_per_stage; + let max_uniform_buffers_per_shader_stage = self.max_buffers_per_stage; + + let max_bindings_per_bind_group = (max_sampled_textures_per_shader_stage + + max_samplers_per_shader_stage + + max_storage_buffers_per_shader_stage + + max_storage_textures_per_shader_stage + + max_uniform_buffers_per_shader_stage) + * MAX_SHADER_STAGES_PER_PIPELINE; + let base = wgt::Limits::default(); crate::Capabilities { limits: wgt::Limits { @@ -837,16 +851,16 @@ impl super::PrivateCapabilities { max_texture_dimension_3d: self.max_texture_3d_size as u32, max_texture_array_layers: self.max_texture_layers as u32, max_bind_groups: 8, - max_bindings_per_bind_group: 65535, + max_bindings_per_bind_group, max_dynamic_uniform_buffers_per_pipeline_layout: base .max_dynamic_uniform_buffers_per_pipeline_layout, max_dynamic_storage_buffers_per_pipeline_layout: base .max_dynamic_storage_buffers_per_pipeline_layout, - max_sampled_textures_per_shader_stage: self.max_textures_per_stage, - max_samplers_per_shader_stage: self.max_samplers_per_stage, - max_storage_buffers_per_shader_stage: self.max_buffers_per_stage, - max_storage_textures_per_shader_stage: self.max_textures_per_stage, - max_uniform_buffers_per_shader_stage: self.max_buffers_per_stage, + max_sampled_textures_per_shader_stage, + max_samplers_per_shader_stage, + max_storage_buffers_per_shader_stage, + max_storage_textures_per_shader_stage, + max_uniform_buffers_per_shader_stage, max_uniform_buffer_binding_size: self.max_buffer_size.min(!0u32 as u64) as u32, max_storage_buffer_binding_size: self.max_buffer_size.min(!0u32 as u64) as u32, max_vertex_buffers: self.max_vertex_buffers, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index ed0bbbda8a5..27335750766 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1,3 +1,5 @@ +use crate::auxil::MAX_SHADER_STAGES_PER_PIPELINE; + use super::conv; use ash::{extensions::khr, vk}; @@ -712,6 +714,19 @@ impl PhysicalDeviceCapabilities { u64::MAX }; + let max_sampled_textures_per_shader_stage = limits.max_per_stage_descriptor_sampled_images; + let max_samplers_per_shader_stage = limits.max_per_stage_descriptor_samplers; + let max_storage_buffers_per_shader_stage = limits.max_per_stage_descriptor_storage_buffers; + let max_storage_textures_per_shader_stage = limits.max_per_stage_descriptor_storage_images; + let max_uniform_buffers_per_shader_stage = limits.max_per_stage_descriptor_uniform_buffers; + + let max_bindings_per_bind_group = (max_sampled_textures_per_shader_stage + + max_samplers_per_shader_stage + + max_storage_buffers_per_shader_stage + + max_storage_textures_per_shader_stage + + max_uniform_buffers_per_shader_stage) + * MAX_SHADER_STAGES_PER_PIPELINE; + wgt::Limits { max_texture_dimension_1d: limits.max_image_dimension1_d, max_texture_dimension_2d: limits.max_image_dimension2_d, @@ -720,16 +735,16 @@ impl PhysicalDeviceCapabilities { max_bind_groups: limits .max_bound_descriptor_sets .min(crate::MAX_BIND_GROUPS as u32), - max_bindings_per_bind_group: 640, + max_bindings_per_bind_group, max_dynamic_uniform_buffers_per_pipeline_layout: limits .max_descriptor_set_uniform_buffers_dynamic, max_dynamic_storage_buffers_per_pipeline_layout: limits .max_descriptor_set_storage_buffers_dynamic, - max_sampled_textures_per_shader_stage: limits.max_per_stage_descriptor_sampled_images, - max_samplers_per_shader_stage: limits.max_per_stage_descriptor_samplers, - max_storage_buffers_per_shader_stage: limits.max_per_stage_descriptor_storage_buffers, - max_storage_textures_per_shader_stage: limits.max_per_stage_descriptor_storage_images, - max_uniform_buffers_per_shader_stage: limits.max_per_stage_descriptor_uniform_buffers, + max_sampled_textures_per_shader_stage, + max_samplers_per_shader_stage, + max_storage_buffers_per_shader_stage, + max_storage_textures_per_shader_stage, + max_uniform_buffers_per_shader_stage, max_uniform_buffer_binding_size: limits .max_uniform_buffer_range .min(crate::auxil::MAX_I32_BINDING_SIZE),