mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
New Binding Array Limit (#6952)
This commit is contained in:
parent
9da04c2b0b
commit
194d4b1f36
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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()
|
||||
}),
|
||||
)
|
||||
|
||||
@ -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()
|
||||
}),
|
||||
)
|
||||
|
||||
@ -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)),
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user