Skip to content

Commit

Permalink
New Binding Array Limit
Browse files Browse the repository at this point in the history
  • Loading branch information
cwfitzgerald committed Jan 19, 2025
1 parent 78549c4 commit 1b2fdae
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 136 deletions.
8 changes: 4 additions & 4 deletions tests/tests/binding_array/buffers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ static BINDING_ARRAY_UNIFORM_BUFFERS: GpuTestConfiguration = GpuTestConfiguratio
TestParameters::default()
.features(Features::BUFFER_BINDING_ARRAY | Features::UNIFORM_BUFFER_INDEXING)
.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
Expand All @@ -31,7 +31,7 @@ static PARTIAL_BINDING_ARRAY_UNIFORM_BUFFERS: GpuTestConfiguration = GpuTestConf
| Features::UNIFORM_BUFFER_INDEXING,
)
.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
Expand All @@ -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.
Expand All @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/binding_array/sampled_textures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}),
)
Expand All @@ -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()
}),
)
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/binding_array/samplers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ 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,
..Limits::default()
}),
)
Expand All @@ -28,7 +28,7 @@ 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,
..Limits::default()
}),
)
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/binding_array/storage_textures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand All @@ -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)),
Expand Down
1 change: 1 addition & 0 deletions tests/tests/binding_array/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ 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(
Expand Down
82 changes: 49 additions & 33 deletions wgpu-core/src/binding_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ pub enum BindingTypeMaxCountErrorKind {
StorageBuffers,
StorageTextures,
UniformBuffers,
BindingArrayElements,
}

impl BindingTypeMaxCountErrorKind {
Expand All @@ -249,6 +250,9 @@ 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"
}
}
}
}
Expand Down Expand Up @@ -323,49 +327,53 @@ pub(crate) struct BindingTypeMaxCountValidator {
storage_textures: PerStageBindingTypeCounter,
uniform_buffers: PerStageBindingTypeCounter,
acceleration_structures: PerStageBindingTypeCounter,
binding_array_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;

if binding.count.is_some() {
self.binding_array_elements.add(binding.visibility, count);
self.has_bindless_array = true;
} 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::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);
}
}
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.has_bindless_array = true;
}
}

pub(crate) fn merge(&mut self, other: &Self) {
Expand All @@ -376,6 +384,10 @@ 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);
}

pub(crate) fn validate(&self, limits: &wgt::Limits) -> Result<(), BindingTypeMaxCountError> {
Expand Down Expand Up @@ -415,6 +427,10 @@ 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,
)?;
Ok(())
}

Expand Down
15 changes: 7 additions & 8 deletions wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,14 +341,11 @@ impl super::Adapter {
wgt::Features::TEXTURE_BINDING_ARRAY
| wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
| wgt::Features::UNIFORM_BUFFER_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 = {
Expand Down Expand Up @@ -497,6 +494,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,
Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,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,
Expand Down
29 changes: 28 additions & 1 deletion wgpu-hal/src/metal/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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+
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/src/metal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,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,
Expand Down
Loading

0 comments on commit 1b2fdae

Please sign in to comment.