New Binding Array Limit (#6952)

This commit is contained in:
Connor Fitzgerald 2025-02-17 09:22:24 -05:00 committed by GitHub
parent 9da04c2b0b
commit 194d4b1f36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 260 additions and 158 deletions

View File

@ -512,7 +512,11 @@ impl<E: Example + wgpu::WasmNotSendSync> From<ExampleTestParams<E>>
let features = E::required_features() | params.optional_features;
params.base_test_parameters.clone().features(features)
params
.base_test_parameters
.clone()
.features(features)
.limits(E::required_limits())
})
.run_async(move |ctx| async move {
let format = if E::SRGB {

View File

@ -78,6 +78,13 @@ impl crate::framework::Example for Example {
fn required_features() -> wgpu::Features {
wgpu::Features::TEXTURE_BINDING_ARRAY
}
fn required_limits() -> wgpu::Limits {
wgpu::Limits {
max_binding_array_elements_per_shader_stage: 6,
max_binding_array_sampler_elements_per_shader_stage: 2,
..wgpu::Limits::downlevel_defaults()
}
}
fn init(
config: &wgpu::SurfaceConfiguration,
_adapter: &wgpu::Adapter,

View File

@ -9,7 +9,7 @@ static BINDING_ARRAY_UNIFORM_BUFFERS: GpuTestConfiguration = GpuTestConfiguratio
TestParameters::default()
.features(Features::BUFFER_BINDING_ARRAY | Features::UNIFORM_BUFFER_BINDING_ARRAYS)
.limits(Limits {
max_uniform_buffers_per_shader_stage: 16,
max_binding_array_elements_per_shader_stage: 16,
..Limits::default()
})
// Naga bug on vulkan: https://github.com/gfx-rs/wgpu/issues/6733
@ -31,7 +31,7 @@ static PARTIAL_BINDING_ARRAY_UNIFORM_BUFFERS: GpuTestConfiguration = GpuTestConf
| Features::UNIFORM_BUFFER_BINDING_ARRAYS,
)
.limits(Limits {
max_uniform_buffers_per_shader_stage: 32,
max_binding_array_elements_per_shader_stage: 32,
..Limits::default()
})
// Naga bug on vulkan: https://github.com/gfx-rs/wgpu/issues/6733
@ -53,7 +53,7 @@ static BINDING_ARRAY_STORAGE_BUFFERS: GpuTestConfiguration = GpuTestConfiguratio
| Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
)
.limits(Limits {
max_storage_buffers_per_shader_stage: 17,
max_binding_array_elements_per_shader_stage: 17,
..Limits::default()
})
// See https://github.com/gfx-rs/wgpu/issues/6745.
@ -72,7 +72,7 @@ static PARTIAL_BINDING_ARRAY_STORAGE_BUFFERS: GpuTestConfiguration = GpuTestConf
| Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
)
.limits(Limits {
max_storage_buffers_per_shader_stage: 33,
max_binding_array_elements_per_shader_stage: 33,
..Limits::default()
})
// See https://github.com/gfx-rs/wgpu/issues/6745.

View File

@ -14,7 +14,7 @@ static BINDING_ARRAY_SAMPLED_TEXTURES: GpuTestConfiguration = GpuTestConfigurati
| Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
)
.limits(Limits {
max_sampled_textures_per_shader_stage: 16,
max_binding_array_elements_per_shader_stage: 16,
..Limits::default()
}),
)
@ -30,7 +30,7 @@ static PARTIAL_BINDING_ARRAY_SAMPLED_TEXTURES: GpuTestConfiguration = GpuTestCon
| Features::PARTIALLY_BOUND_BINDING_ARRAY,
)
.limits(Limits {
max_sampled_textures_per_shader_stage: 32,
max_binding_array_elements_per_shader_stage: 32,
..Limits::default()
}),
)

View File

@ -12,7 +12,8 @@ static BINDING_ARRAY_SAMPLERS: GpuTestConfiguration = GpuTestConfiguration::new(
| Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
)
.limits(Limits {
max_samplers_per_shader_stage: 2,
max_binding_array_elements_per_shader_stage: 2,
max_binding_array_sampler_elements_per_shader_stage: 2,
..Limits::default()
}),
)
@ -28,7 +29,8 @@ static PARTIAL_BINDING_ARRAY_SAMPLERS: GpuTestConfiguration = GpuTestConfigurati
| Features::PARTIALLY_BOUND_BINDING_ARRAY,
)
.limits(Limits {
max_samplers_per_shader_stage: 4,
max_binding_array_elements_per_shader_stage: 4,
max_binding_array_sampler_elements_per_shader_stage: 4,
..Limits::default()
}),
)

View File

@ -17,7 +17,7 @@ static BINDING_ARRAY_STORAGE_TEXTURES: GpuTestConfiguration = GpuTestConfigurati
| Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
)
.limits(Limits {
max_storage_textures_per_shader_stage: 17,
max_binding_array_elements_per_shader_stage: 17,
..Limits::default()
})
.expect_fail(FailureCase::backend(Backends::METAL)),
@ -36,7 +36,7 @@ static PARTIAL_BINDING_ARRAY_STORAGE_TEXTURES: GpuTestConfiguration = GpuTestCon
| Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
)
.limits(Limits {
max_storage_textures_per_shader_stage: 33,
max_binding_array_elements_per_shader_stage: 33,
..Limits::default()
})
.expect_fail(FailureCase::backend(Backends::METAL)),

View File

@ -1,9 +1,7 @@
use std::num::NonZeroU32;
use wgpu::*;
use wgpu_test::{
fail, gpu_test, FailureCase, GpuTestConfiguration, TestParameters, TestingContext,
};
use wgpu_test::{fail, gpu_test, GpuTestConfiguration, TestParameters, TestingContext};
#[gpu_test]
static VALIDATION: GpuTestConfiguration = GpuTestConfiguration::new()
@ -12,12 +10,9 @@ static VALIDATION: GpuTestConfiguration = GpuTestConfiguration::new()
.features(Features::TEXTURE_BINDING_ARRAY)
.limits(Limits {
max_dynamic_storage_buffers_per_pipeline_layout: 1,
max_binding_array_elements_per_shader_stage: 4,
..Limits::downlevel_defaults()
})
.expect_fail(
// https://github.com/gfx-rs/wgpu/issues/6950
FailureCase::backend(Backends::VULKAN).validation_error("has not been destroyed"),
),
}),
)
.run_async(validation);

View File

@ -229,6 +229,8 @@ pub enum BindingTypeMaxCountErrorKind {
StorageBuffers,
StorageTextures,
UniformBuffers,
BindingArrayElements,
BindingArraySamplerElements,
}
impl BindingTypeMaxCountErrorKind {
@ -249,6 +251,12 @@ impl BindingTypeMaxCountErrorKind {
"max_storage_textures_per_shader_stage"
}
BindingTypeMaxCountErrorKind::UniformBuffers => "max_uniform_buffers_per_shader_stage",
BindingTypeMaxCountErrorKind::BindingArrayElements => {
"max_binding_array_elements_per_shader_stage"
}
BindingTypeMaxCountErrorKind::BindingArraySamplerElements => {
"max_binding_array_elements_per_shader_stage"
}
}
}
}
@ -323,48 +331,58 @@ pub(crate) struct BindingTypeMaxCountValidator {
storage_textures: PerStageBindingTypeCounter,
uniform_buffers: PerStageBindingTypeCounter,
acceleration_structures: PerStageBindingTypeCounter,
binding_array_elements: PerStageBindingTypeCounter,
binding_array_sampler_elements: PerStageBindingTypeCounter,
has_bindless_array: bool,
}
impl BindingTypeMaxCountValidator {
pub(crate) fn add_binding(&mut self, binding: &wgt::BindGroupLayoutEntry) {
let count = binding.count.map_or(1, |count| count.get());
match binding.ty {
wgt::BindingType::Buffer {
ty: wgt::BufferBindingType::Uniform,
has_dynamic_offset,
..
} => {
self.uniform_buffers.add(binding.visibility, count);
if has_dynamic_offset {
self.dynamic_uniform_buffers += count;
}
}
wgt::BindingType::Buffer {
ty: wgt::BufferBindingType::Storage { .. },
has_dynamic_offset,
..
} => {
self.storage_buffers.add(binding.visibility, count);
if has_dynamic_offset {
self.dynamic_storage_buffers += count;
}
}
wgt::BindingType::Sampler { .. } => {
self.samplers.add(binding.visibility, count);
}
wgt::BindingType::Texture { .. } => {
self.sampled_textures.add(binding.visibility, count);
}
wgt::BindingType::StorageTexture { .. } => {
self.storage_textures.add(binding.visibility, count);
}
wgt::BindingType::AccelerationStructure => {
self.acceleration_structures.add(binding.visibility, count);
}
}
if binding.count.is_some() {
self.binding_array_elements.add(binding.visibility, count);
self.has_bindless_array = true;
if let wgt::BindingType::Sampler(_) = binding.ty {
self.binding_array_sampler_elements
.add(binding.visibility, count);
}
} else {
match binding.ty {
wgt::BindingType::Buffer {
ty: wgt::BufferBindingType::Uniform,
has_dynamic_offset,
..
} => {
self.uniform_buffers.add(binding.visibility, count);
if has_dynamic_offset {
self.dynamic_uniform_buffers += count;
}
}
wgt::BindingType::Buffer {
ty: wgt::BufferBindingType::Storage { .. },
has_dynamic_offset,
..
} => {
self.storage_buffers.add(binding.visibility, count);
if has_dynamic_offset {
self.dynamic_storage_buffers += count;
}
}
wgt::BindingType::Sampler { .. } => {
self.samplers.add(binding.visibility, count);
}
wgt::BindingType::Texture { .. } => {
self.sampled_textures.add(binding.visibility, count);
}
wgt::BindingType::StorageTexture { .. } => {
self.storage_textures.add(binding.visibility, count);
}
wgt::BindingType::AccelerationStructure => {
self.acceleration_structures.add(binding.visibility, count);
}
}
}
}
@ -376,6 +394,12 @@ impl BindingTypeMaxCountValidator {
self.storage_buffers.merge(&other.storage_buffers);
self.storage_textures.merge(&other.storage_textures);
self.uniform_buffers.merge(&other.uniform_buffers);
self.acceleration_structures
.merge(&other.acceleration_structures);
self.binding_array_elements
.merge(&other.binding_array_elements);
self.binding_array_sampler_elements
.merge(&other.binding_array_sampler_elements);
}
pub(crate) fn validate(&self, limits: &wgt::Limits) -> Result<(), BindingTypeMaxCountError> {
@ -415,6 +439,14 @@ impl BindingTypeMaxCountValidator {
limits.max_uniform_buffers_per_shader_stage,
BindingTypeMaxCountErrorKind::UniformBuffers,
)?;
self.binding_array_elements.validate(
limits.max_binding_array_elements_per_shader_stage,
BindingTypeMaxCountErrorKind::BindingArrayElements,
)?;
self.binding_array_sampler_elements.validate(
limits.max_binding_array_sampler_elements_per_shader_stage,
BindingTypeMaxCountErrorKind::BindingArraySamplerElements,
)?;
Ok(())
}

View File

@ -1956,9 +1956,6 @@ impl Device {
entries: &hal_bindings,
};
let raw = unsafe { self.raw().create_bind_group_layout(&hal_desc) }
.map_err(|e| self.handle_hal_error(e))?;
let mut count_validator = binding_model::BindingTypeMaxCountValidator::default();
for entry in entry_map.values() {
count_validator.add_binding(entry);
@ -1972,6 +1969,9 @@ impl Device {
// Validate that binding arrays don't conflict with dynamic offsets.
count_validator.validate_binding_arrays()?;
let raw = unsafe { self.raw().create_bind_group_layout(&hal_desc) }
.map_err(|e| self.handle_hal_error(e))?;
let bgl = BindGroupLayout {
raw: ManuallyDrop::new(raw),
device: self.clone(),

View File

@ -373,14 +373,11 @@ impl super::Adapter {
wgt::Features::TEXTURE_BINDING_ARRAY
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
| wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
shader_model >= naga::back::hlsl::ShaderModel::V5_1,
);
// See note below the table https://learn.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
features.set(
wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY,
options.ResourceBindingTier.0 >= Direct3D12::D3D12_RESOURCE_BINDING_TIER_3.0,
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
// See note below the table https://learn.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
| wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY,
shader_model >= naga::back::hlsl::ShaderModel::V5_1
&& options.ResourceBindingTier.0 >= Direct3D12::D3D12_RESOURCE_BINDING_TIER_3.0,
);
let bgra8unorm_storage_supported = {
@ -529,6 +526,8 @@ impl super::Adapter {
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_binding_array_elements_per_shader_stage: full_heap_count,
max_binding_array_sampler_elements_per_shader_stage: full_heap_count,
max_uniform_buffer_binding_size:
Direct3D12::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16,
max_storage_buffer_binding_size: auxil::MAX_I32_BINDING_SIZE,

View File

@ -685,6 +685,8 @@ impl super::Adapter {
max_storage_buffers_per_shader_stage,
max_storage_textures_per_shader_stage,
max_uniform_buffers_per_shader_stage,
max_binding_array_elements_per_shader_stage: 0,
max_binding_array_sampler_elements_per_shader_stage: 0,
max_uniform_buffer_binding_size: unsafe {
gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE)
} as u32,

View File

@ -592,6 +592,8 @@ impl super::PrivateCapabilities {
// `TimestampQuerySupport::INSIDE_WGPU_PASSES` emerges from the other flags.
}
let argument_buffers = device.argument_buffers_support();
Self {
family_check,
msl_version: if os_is_xr || version.at_least((14, 0), (17, 0), os_is_mac) {
@ -626,7 +628,7 @@ impl super::PrivateCapabilities {
},
msaa_apple7: family_check && device.supports_family(MTLGPUFamily::Apple7),
resource_heaps: Self::supports_any(device, RESOURCE_HEAP_SUPPORT),
argument_buffers: device.argument_buffers_support(),
argument_buffers,
shared_textures: !os_is_mac,
mutable_comparison_samplers: Self::supports_any(
device,
@ -725,6 +727,28 @@ impl super::PrivateCapabilities {
31
},
max_samplers_per_stage: 16,
max_binding_array_elements: if argument_buffers == metal::MTLArgumentBuffersTier::Tier2
{
1_000_000
} else if family_check && device.supports_family(MTLGPUFamily::Apple4) {
96
} else {
31
},
max_sampler_binding_array_elements: if family_check
&& device.supports_family(MTLGPUFamily::Apple9)
{
500_000
} else if family_check
&& (device.supports_family(MTLGPUFamily::Apple7)
|| device.supports_family(MTLGPUFamily::Mac2))
{
1000
} else if family_check && device.supports_family(MTLGPUFamily::Apple6) {
128
} else {
16
},
buffer_alignment: if os_is_mac || os_is_xr { 256 } else { 64 },
max_buffer_size: if version.at_least((10, 14), (12, 0), os_is_mac) {
// maxBufferLength available on macOS 10.14+ and iOS 12.0+
@ -1013,6 +1037,9 @@ impl super::PrivateCapabilities {
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_binding_array_elements_per_shader_stage: self.max_binding_array_elements,
max_binding_array_sampler_elements_per_shader_stage: self
.max_sampler_binding_array_elements,
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,

View File

@ -262,6 +262,8 @@ struct PrivateCapabilities {
max_vertex_buffers: ResourceIndex,
max_textures_per_stage: ResourceIndex,
max_samplers_per_stage: ResourceIndex,
max_binding_array_elements: ResourceIndex,
max_sampler_binding_array_elements: ResourceIndex,
buffer_alignment: u64,
max_buffer_size: u64,
max_texture_size: u64,

View File

@ -147,6 +147,8 @@ const CAPABILITIES: crate::Capabilities = {
max_storage_buffers_per_shader_stage: ALLOC_MAX_U32,
max_storage_textures_per_shader_stage: ALLOC_MAX_U32,
max_uniform_buffers_per_shader_stage: ALLOC_MAX_U32,
max_binding_array_elements_per_shader_stage: ALLOC_MAX_U32,
max_binding_array_sampler_elements_per_shader_stage: ALLOC_MAX_U32,
max_uniform_buffer_binding_size: ALLOC_MAX_U32,
max_storage_buffer_binding_size: ALLOC_MAX_U32,
max_vertex_buffers: ALLOC_MAX_U32,

View File

@ -9,13 +9,13 @@ fn depth_stencil_required_flags() -> vk::FormatFeatureFlags {
vk::FormatFeatureFlags::SAMPLED_IMAGE | vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT
}
//TODO: const fn?
fn indexing_features() -> wgt::Features {
wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
| wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
| wgt::Features::UNIFORM_BUFFER_BINDING_ARRAYS
| wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY
}
const INDEXING_FEATURES: wgt::Features = wgt::Features::TEXTURE_BINDING_ARRAY
.union(wgt::Features::BUFFER_BINDING_ARRAY)
.union(wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY)
.union(wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING)
.union(wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING)
.union(wgt::Features::UNIFORM_BUFFER_BINDING_ARRAYS)
.union(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY);
/// Features supported by a [`vk::PhysicalDevice`] and its extensions.
///
@ -209,22 +209,13 @@ impl PhysicalDeviceFeatures {
downlevel_flags: wgt::DownlevelFlags,
private_caps: &super::PrivateCapabilities,
) -> Self {
let needs_sampled_image_non_uniform = requested_features.contains(
let needs_bindless = requested_features.intersects(
wgt::Features::TEXTURE_BINDING_ARRAY
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
);
let needs_storage_buffer_non_uniform = requested_features.contains(
wgt::Features::BUFFER_BINDING_ARRAY
| wgt::Features::BUFFER_BINDING_ARRAY
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
| wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
);
let needs_uniform_buffer_non_uniform =
requested_features.contains(wgt::Features::UNIFORM_BUFFER_BINDING_ARRAYS);
let needs_storage_image_non_uniform = requested_features.contains(
wgt::Features::TEXTURE_BINDING_ARRAY
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
| wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
);
let needs_partially_bound =
requested_features.intersects(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY);
@ -302,21 +293,15 @@ impl PhysicalDeviceFeatures {
.geometry_shader(requested_features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX))
.depth_clamp(requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL))
.dual_src_blend(requested_features.contains(wgt::Features::DUAL_SOURCE_BLENDING)),
descriptor_indexing: if requested_features.intersects(indexing_features()) {
descriptor_indexing: if requested_features.intersects(INDEXING_FEATURES) {
Some(
vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::default()
.shader_sampled_image_array_non_uniform_indexing(
needs_sampled_image_non_uniform,
)
.shader_storage_image_array_non_uniform_indexing(
needs_storage_image_non_uniform,
)
.shader_uniform_buffer_array_non_uniform_indexing(
needs_uniform_buffer_non_uniform,
)
.shader_storage_buffer_array_non_uniform_indexing(
needs_storage_buffer_non_uniform,
)
.shader_sampled_image_array_non_uniform_indexing(needs_bindless)
.shader_storage_image_array_non_uniform_indexing(needs_bindless)
.shader_storage_buffer_array_non_uniform_indexing(needs_bindless)
.descriptor_binding_sampled_image_update_after_bind(needs_bindless)
.descriptor_binding_storage_image_update_after_bind(needs_bindless)
.descriptor_binding_storage_buffer_update_after_bind(needs_bindless)
.descriptor_binding_partially_bound(needs_partially_bound),
)
} else {
@ -949,7 +934,7 @@ impl PhysicalDeviceProperties {
}
// Require `VK_EXT_descriptor_indexing` if one of the associated features was requested
if requested_features.intersects(indexing_features()) {
if requested_features.intersects(INDEXING_FEATURES) {
extensions.push(ext::descriptor_indexing::NAME);
}
@ -1070,6 +1055,24 @@ impl PhysicalDeviceProperties {
u64::MAX
};
let mut max_binding_array_elements = 0;
let mut max_sampler_binding_array_elements = 0;
if let Some(ref descriptor_indexing) = self.descriptor_indexing {
max_binding_array_elements = descriptor_indexing
.max_descriptor_set_update_after_bind_sampled_images
.min(descriptor_indexing.max_descriptor_set_update_after_bind_storage_images)
.min(descriptor_indexing.max_descriptor_set_update_after_bind_storage_buffers)
.min(descriptor_indexing.max_per_stage_descriptor_update_after_bind_sampled_images)
.min(descriptor_indexing.max_per_stage_descriptor_update_after_bind_storage_images)
.min(
descriptor_indexing.max_per_stage_descriptor_update_after_bind_storage_buffers,
);
max_sampler_binding_array_elements = descriptor_indexing
.max_descriptor_set_update_after_bind_samplers
.min(descriptor_indexing.max_per_stage_descriptor_update_after_bind_samplers);
}
// TODO: programmatically determine this, if possible. It's unclear whether we can
// as of https://github.com/gpuweb/gpuweb/issues/2965#issuecomment-1361315447.
//
@ -1098,6 +1101,8 @@ impl PhysicalDeviceProperties {
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_binding_array_elements_per_shader_stage: max_binding_array_elements,
max_binding_array_sampler_elements_per_shader_stage: max_sampler_binding_array_elements,
max_uniform_buffer_binding_size: limits
.max_uniform_buffer_range
.min(crate::auxil::MAX_I32_BINDING_SIZE),

View File

@ -1461,44 +1461,47 @@ impl crate::Device for super::Device {
})
.collect::<Vec<_>>();
let vk_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&vk_bindings);
let binding_arrays = desc
let binding_arrays: Vec<_> = desc
.entries
.iter()
.enumerate()
.filter_map(|(idx, entry)| entry.count.map(|count| (idx as u32, count)))
.collect();
let mut binding_flag_info;
let binding_flag_vec;
let vk_info = vk::DescriptorSetLayoutCreateInfo::default()
.bindings(&vk_bindings)
.flags(if !binding_arrays.is_empty() {
vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL
} else {
vk::DescriptorSetLayoutCreateFlags::empty()
});
let partially_bound = desc
.flags
.contains(crate::BindGroupLayoutFlags::PARTIALLY_BOUND);
let vk_info = if partially_bound {
binding_flag_vec = desc
.entries
.iter()
.map(|entry| {
let mut flags = vk::DescriptorBindingFlags::empty();
let binding_flag_vec = desc
.entries
.iter()
.map(|entry| {
let mut flags = vk::DescriptorBindingFlags::empty();
if partially_bound && entry.count.is_some() {
flags |= vk::DescriptorBindingFlags::PARTIALLY_BOUND;
}
if partially_bound && entry.count.is_some() {
flags |= vk::DescriptorBindingFlags::PARTIALLY_BOUND;
}
flags
})
.collect::<Vec<_>>();
if entry.count.is_some() {
flags |= vk::DescriptorBindingFlags::UPDATE_AFTER_BIND;
}
binding_flag_info = vk::DescriptorSetLayoutBindingFlagsCreateInfo::default()
.binding_flags(&binding_flag_vec);
flags
})
.collect::<Vec<_>>();
vk_info.push_next(&mut binding_flag_info)
} else {
vk_info
};
let mut binding_flag_info = vk::DescriptorSetLayoutBindingFlagsCreateInfo::default()
.binding_flags(&binding_flag_vec);
let vk_info = vk_info.push_next(&mut binding_flag_info);
let raw = unsafe {
self.shared

View File

@ -137,15 +137,14 @@ fn print_adapter(output: &mut impl io::Write, report: &AdapterReport, idx: usize
max_storage_buffers_per_shader_stage,
max_storage_textures_per_shader_stage,
max_uniform_buffers_per_shader_stage,
max_binding_array_elements_per_shader_stage,
max_binding_array_sampler_elements_per_shader_stage,
max_uniform_buffer_binding_size,
max_storage_buffer_binding_size,
max_buffer_size,
max_vertex_buffers,
max_buffer_size,
max_vertex_attributes,
max_vertex_buffer_array_stride,
min_subgroup_size,
max_subgroup_size,
max_push_constant_size,
min_uniform_buffer_offset_alignment,
min_storage_buffer_offset_alignment,
max_inter_stage_shader_components,
@ -157,41 +156,46 @@ fn print_adapter(output: &mut impl io::Write, report: &AdapterReport, idx: usize
max_compute_workgroup_size_y,
max_compute_workgroup_size_z,
max_compute_workgroups_per_dimension,
min_subgroup_size,
max_subgroup_size,
max_push_constant_size,
max_non_sampler_bindings,
} = limits;
writeln!(output, "\t\t Max Texture Dimension 1d: {max_texture_dimension_1d}")?;
writeln!(output, "\t\t Max Texture Dimension 2d: {max_texture_dimension_2d}")?;
writeln!(output, "\t\t Max Texture Dimension 3d: {max_texture_dimension_3d}")?;
writeln!(output, "\t\t Max Texture Array Layers: {max_texture_array_layers}")?;
writeln!(output, "\t\t Max Bind Groups: {max_bind_groups}")?;
writeln!(output, "\t\t Max Bindings Per Bind Group: {max_bindings_per_bind_group}")?;
writeln!(output, "\t\t Max Dynamic Uniform Buffers Per Pipeline Layout: {max_dynamic_uniform_buffers_per_pipeline_layout}")?;
writeln!(output, "\t\t Max Dynamic Storage Buffers Per Pipeline Layout: {max_dynamic_storage_buffers_per_pipeline_layout}")?;
writeln!(output, "\t\t Max Sampled Textures Per Shader Stage: {max_sampled_textures_per_shader_stage}")?;
writeln!(output, "\t\t Max Samplers Per Shader Stage: {max_samplers_per_shader_stage}")?;
writeln!(output, "\t\t Max Storage Buffers Per Shader Stage: {max_storage_buffers_per_shader_stage}")?;
writeln!(output, "\t\t Max Storage Textures Per Shader Stage: {max_storage_textures_per_shader_stage}")?;
writeln!(output, "\t\t Max Uniform Buffers Per Shader Stage: {max_uniform_buffers_per_shader_stage}")?;
writeln!(output, "\t\t Max Uniform Buffer Binding Size: {max_uniform_buffer_binding_size}")?;
writeln!(output, "\t\t Max Storage Buffer Binding Size: {max_storage_buffer_binding_size}")?;
writeln!(output, "\t\t Max Buffer Size: {max_buffer_size}")?;
writeln!(output, "\t\t Max Vertex Buffers: {max_vertex_buffers}")?;
writeln!(output, "\t\t Max Vertex Attributes: {max_vertex_attributes}")?;
writeln!(output, "\t\t Max Vertex Buffer Array Stride: {max_vertex_buffer_array_stride}")?;
writeln!(output, "\t\t Min Subgroup Size: {min_subgroup_size}")?;
writeln!(output, "\t\t Max Subgroup Size: {max_subgroup_size}")?;
writeln!(output, "\t\t Max Push Constant Size: {max_push_constant_size}")?;
writeln!(output, "\t\t Min Uniform Buffer Offset Alignment: {min_uniform_buffer_offset_alignment}")?;
writeln!(output, "\t\t Min Storage Buffer Offset Alignment: {min_storage_buffer_offset_alignment}")?;
writeln!(output, "\t\t Max Inter-Stage Shader Component: {max_inter_stage_shader_components}")?;
writeln!(output, "\t\t Max Color Attachments: {max_color_attachments}")?;
writeln!(output, "\t\t Max Color Attachment Bytes per sample: {max_color_attachment_bytes_per_sample}")?;
writeln!(output, "\t\t Max Compute Workgroup Storage Size: {max_compute_workgroup_storage_size}")?;
writeln!(output, "\t\t Max Compute Invocations Per Workgroup: {max_compute_invocations_per_workgroup}")?;
writeln!(output, "\t\t Max Compute Workgroup Size X: {max_compute_workgroup_size_x}")?;
writeln!(output, "\t\t Max Compute Workgroup Size Y: {max_compute_workgroup_size_y}")?;
writeln!(output, "\t\t Max Compute Workgroup Size Z: {max_compute_workgroup_size_z}")?;
writeln!(output, "\t\t Max Compute Workgroups Per Dimension: {max_compute_workgroups_per_dimension}")?;
writeln!(output, "\t\t Max Texture Dimension 1d: {max_texture_dimension_1d}")?;
writeln!(output, "\t\t Max Texture Dimension 2d: {max_texture_dimension_2d}")?;
writeln!(output, "\t\t Max Texture Dimension 3d: {max_texture_dimension_3d}")?;
writeln!(output, "\t\t Max Texture Array Layers: {max_texture_array_layers}")?;
writeln!(output, "\t\t Max Bind Groups: {max_bind_groups}")?;
writeln!(output, "\t\t Max Bindings Per Bind Group: {max_bindings_per_bind_group}")?;
writeln!(output, "\t\t Max Dynamic Uniform Buffers Per Pipeline Layout: {max_dynamic_uniform_buffers_per_pipeline_layout}")?;
writeln!(output, "\t\t Max Dynamic Storage Buffers Per Pipeline Layout: {max_dynamic_storage_buffers_per_pipeline_layout}")?;
writeln!(output, "\t\t Max Sampled Textures Per Shader Stage: {max_sampled_textures_per_shader_stage}")?;
writeln!(output, "\t\t Max Samplers Per Shader Stage: {max_samplers_per_shader_stage}")?;
writeln!(output, "\t\t Max Storage Buffers Per Shader Stage: {max_storage_buffers_per_shader_stage}")?;
writeln!(output, "\t\t Max Storage Textures Per Shader Stage: {max_storage_textures_per_shader_stage}")?;
writeln!(output, "\t\t Max Uniform Buffers Per Shader Stage: {max_uniform_buffers_per_shader_stage}")?;
writeln!(output, "\t\t Max Binding Array Elements Per Shader Stage: {max_binding_array_elements_per_shader_stage}")?;
writeln!(output, "\t\tMax Binding Array Sampler Elements Per Shader Stage: {max_binding_array_sampler_elements_per_shader_stage}")?;
writeln!(output, "\t\t Max Uniform Buffer Binding Size: {max_uniform_buffer_binding_size}")?;
writeln!(output, "\t\t Max Storage Buffer Binding Size: {max_storage_buffer_binding_size}")?;
writeln!(output, "\t\t Max Buffer Size: {max_buffer_size}")?;
writeln!(output, "\t\t Max Vertex Buffers: {max_vertex_buffers}")?;
writeln!(output, "\t\t Max Vertex Attributes: {max_vertex_attributes}")?;
writeln!(output, "\t\t Max Vertex Buffer Array Stride: {max_vertex_buffer_array_stride}")?;
writeln!(output, "\t\t Min Subgroup Size: {min_subgroup_size}")?;
writeln!(output, "\t\t Max Subgroup Size: {max_subgroup_size}")?;
writeln!(output, "\t\t Max Push Constant Size: {max_push_constant_size}")?;
writeln!(output, "\t\t Min Uniform Buffer Offset Alignment: {min_uniform_buffer_offset_alignment}")?;
writeln!(output, "\t\t Min Storage Buffer Offset Alignment: {min_storage_buffer_offset_alignment}")?;
writeln!(output, "\t\t Max Inter-Stage Shader Component: {max_inter_stage_shader_components}")?;
writeln!(output, "\t\t Max Color Attachments: {max_color_attachments}")?;
writeln!(output, "\t\t Max Color Attachment Bytes per sample: {max_color_attachment_bytes_per_sample}")?;
writeln!(output, "\t\t Max Compute Workgroup Storage Size: {max_compute_workgroup_storage_size}")?;
writeln!(output, "\t\t Max Compute Invocations Per Workgroup: {max_compute_invocations_per_workgroup}")?;
writeln!(output, "\t\t Max Compute Workgroup Size X: {max_compute_workgroup_size_x}")?;
writeln!(output, "\t\t Max Compute Workgroup Size Y: {max_compute_workgroup_size_y}")?;
writeln!(output, "\t\t Max Compute Workgroup Size Z: {max_compute_workgroup_size_z}")?;
writeln!(output, "\t\t Max Compute Workgroups Per Dimension: {max_compute_workgroups_per_dimension}")?;
// This one reflects more of a wgpu implementation limitations than a hardware limit
// so don't show it here.

View File

@ -384,6 +384,15 @@ pub struct Limits {
pub max_storage_textures_per_shader_stage: u32,
/// Amount of uniform buffers visible in a single shader stage. Defaults to 12. Higher is "better".
pub max_uniform_buffers_per_shader_stage: u32,
/// Amount of individual resources within binding arrays that can be accessed in a single shader stage. Applies
/// to all types of bindings except samplers.
///
/// This "defaults" to 0. However if binding arrays are supported, all devices can support 500,000. Higher is "better".
pub max_binding_array_elements_per_shader_stage: u32,
/// Amount of individual samplers within binding arrays that can be accessed in a single shader stage.
///
/// This "defaults" to 0. However if binding arrays are supported, all devices can support 1,000. Higher is "better".
pub max_binding_array_sampler_elements_per_shader_stage: u32,
/// Maximum size in bytes of a binding to a uniform buffer. Defaults to 64 KiB. Higher is "better".
pub max_uniform_buffer_binding_size: u32,
/// Maximum size in bytes of a binding to a storage buffer. Defaults to 128 MiB. Higher is "better".
@ -488,6 +497,8 @@ impl Limits {
max_storage_buffers_per_shader_stage: 8,
max_storage_textures_per_shader_stage: 4,
max_uniform_buffers_per_shader_stage: 12,
max_binding_array_elements_per_shader_stage: 0,
max_binding_array_sampler_elements_per_shader_stage: 0,
max_uniform_buffer_binding_size: 64 << 10, // (64 KiB)
max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
max_vertex_buffers: 8,
@ -531,6 +542,8 @@ impl Limits {
/// max_storage_buffers_per_shader_stage: 4, // *
/// max_storage_textures_per_shader_stage: 4,
/// max_uniform_buffers_per_shader_stage: 12,
/// max_binding_array_elements_per_shader_stage: 0,
/// max_binding_array_sampler_elements_per_shader_stage: 0,
/// max_uniform_buffer_binding_size: 16 << 10, // * (16 KiB)
/// max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
/// max_vertex_buffers: 8,
@ -589,6 +602,8 @@ impl Limits {
/// max_storage_buffers_per_shader_stage: 0, // * +
/// max_storage_textures_per_shader_stage: 0, // +
/// max_uniform_buffers_per_shader_stage: 11, // +
/// max_binding_array_elements_per_shader_stage: 0,
/// max_binding_array_sampler_elements_per_shader_stage: 0,
/// max_uniform_buffer_binding_size: 16 << 10, // * (16 KiB)
/// max_storage_buffer_binding_size: 0, // * +
/// max_vertex_buffers: 8,
@ -720,6 +735,7 @@ impl Limits {
compare!(max_storage_buffers_per_shader_stage, Less);
compare!(max_storage_textures_per_shader_stage, Less);
compare!(max_uniform_buffers_per_shader_stage, Less);
compare!(max_binding_array_elements_per_shader_stage, Less);
compare!(max_uniform_buffer_binding_size, Less);
compare!(max_storage_buffer_binding_size, Less);
compare!(max_vertex_buffers, Less);

View File

@ -811,6 +811,8 @@ fn map_wgt_limits(limits: webgpu_sys::GpuSupportedLimits) -> wgt::Limits {
max_storage_buffers_per_shader_stage: limits.max_storage_buffers_per_shader_stage(),
max_storage_textures_per_shader_stage: limits.max_storage_textures_per_shader_stage(),
max_uniform_buffers_per_shader_stage: limits.max_uniform_buffers_per_shader_stage(),
max_binding_array_elements_per_shader_stage: 0,
max_binding_array_sampler_elements_per_shader_stage: 0,
max_uniform_buffer_binding_size: limits.max_uniform_buffer_binding_size() as u32,
max_storage_buffer_binding_size: limits.max_storage_buffer_binding_size() as u32,
max_vertex_buffers: limits.max_vertex_buffers(),