Skip to content

Commit

Permalink
fix(limits): properly calculate max_bindings_per_bind_group
Browse files Browse the repository at this point in the history
  • Loading branch information
ErichDonGubler committed Jul 19, 2023
1 parent 1161a22 commit d2fd46f
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 36 deletions.
8 changes: 8 additions & 0 deletions wgpu-hal/src/auxil/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
25 changes: 20 additions & 5 deletions wgpu-hal/src/dx11/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::num::NonZeroU64;

use winapi::um::{d3d11, d3dcommon};

use crate::auxil::MAX_SHADER_STAGES_PER_PIPELINE;

impl crate::Adapter<super::Api> for super::Adapter {
unsafe fn open(
&self,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
45 changes: 29 additions & 16 deletions wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
16 changes: 13 additions & 3 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
26 changes: 20 additions & 6 deletions wgpu-hal/src/metal/adapter.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
27 changes: 21 additions & 6 deletions wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::auxil::MAX_SHADER_STAGES_PER_PIPELINE;

use super::conv;

use ash::{extensions::khr, vk};
Expand Down Expand Up @@ -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,
Expand All @@ -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),
Expand Down

0 comments on commit d2fd46f

Please sign in to comment.