Skip to content

Commit bd4a9e6

Browse files
committed
Support descriptor arrays shorter than binding length
1 parent 180e3e3 commit bd4a9e6

File tree

14 files changed

+482
-121
lines changed

14 files changed

+482
-121
lines changed

wgpu-core/src/binding_model.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,16 @@ pub enum CreateBindGroupError {
6565
InvalidTextureView(TextureViewId),
6666
#[error("sampler {0:?} is invalid")]
6767
InvalidSampler(SamplerId),
68-
#[error("binding count declared with {expected} items, but {actual} items were provided")]
68+
#[error(
69+
"binding count declared with at most {expected} items, but {actual} items were provided"
70+
)]
71+
BindingArrayPartialLengthMismatch { actual: usize, expected: usize },
72+
#[error(
73+
"binding count declared with exactly {expected} items, but {actual} items were provided"
74+
)]
6975
BindingArrayLengthMismatch { actual: usize, expected: usize },
76+
#[error("array binding provided zero elements")]
77+
BindingArrayZeroLength,
7078
#[error("bound buffer range {range:?} does not fit in buffer of size {size}")]
7179
BindingRangeTooLarge {
7280
buffer: BufferId,

wgpu-core/src/conv.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,12 @@ pub fn check_texture_dimension_size(
152152

153153
Ok(())
154154
}
155+
156+
pub fn bind_group_layout_flags(features: wgt::Features) -> hal::BindGroupLayoutFlags {
157+
let mut flags = hal::BindGroupLayoutFlags::empty();
158+
flags.set(
159+
hal::BindGroupLayoutFlags::PARTIALLY_BOUND,
160+
features.contains(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY),
161+
);
162+
flags
163+
}

wgpu-core/src/device/mod.rs

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use smallvec::SmallVec;
1919
use thiserror::Error;
2020
use wgt::{BufferAddress, TextureFormat, TextureViewDimension};
2121

22-
use std::{borrow::Cow, iter, marker::PhantomData, mem, ops::Range, ptr};
22+
use std::{borrow::Cow, iter, marker::PhantomData, mem, num::NonZeroU32, ops::Range, ptr};
2323

2424
mod life;
2525
pub mod queue;
@@ -1183,10 +1183,13 @@ impl<A: HalApi> Device<A> {
11831183
})?;
11841184
}
11851185

1186+
let bgl_flags = conv::bind_group_layout_flags(self.features);
1187+
11861188
let mut hal_bindings = entry_map.values().cloned().collect::<Vec<_>>();
11871189
hal_bindings.sort_by_key(|b| b.binding);
11881190
let hal_desc = hal::BindGroupLayoutDescriptor {
11891191
label,
1192+
flags: bgl_flags,
11901193
entries: &hal_bindings,
11911194
};
11921195
let raw = unsafe {
@@ -1387,7 +1390,7 @@ impl<A: HalApi> Device<A> {
13871390
.entries
13881391
.get(&binding)
13891392
.ok_or(Error::MissingBindingDeclaration(binding))?;
1390-
let res_index = match entry.resource {
1393+
let (res_index, count) = match entry.resource {
13911394
Br::Buffer(ref bb) => {
13921395
let bb = Self::create_buffer_binding(
13931396
bb,
@@ -1402,21 +1405,11 @@ impl<A: HalApi> Device<A> {
14021405

14031406
let res_index = hal_buffers.len();
14041407
hal_buffers.push(bb);
1405-
res_index
1408+
(res_index, 1)
14061409
}
14071410
Br::BufferArray(ref bindings_array) => {
1408-
if let Some(count) = decl.count {
1409-
let count = count.get() as usize;
1410-
let num_bindings = bindings_array.len();
1411-
if count != num_bindings {
1412-
return Err(Error::BindingArrayLengthMismatch {
1413-
actual: num_bindings,
1414-
expected: count,
1415-
});
1416-
}
1417-
} else {
1418-
return Err(Error::SingleBindingExpected);
1419-
}
1411+
let num_bindings = bindings_array.len();
1412+
Self::check_array_binding(self.features, decl.count, num_bindings)?;
14201413

14211414
let res_index = hal_buffers.len();
14221415
for bb in bindings_array.iter() {
@@ -1432,7 +1425,7 @@ impl<A: HalApi> Device<A> {
14321425
)?;
14331426
hal_buffers.push(bb);
14341427
}
1435-
res_index
1428+
(res_index, num_bindings)
14361429
}
14371430
Br::Sampler(id) => {
14381431
match decl.ty {
@@ -1464,7 +1457,7 @@ impl<A: HalApi> Device<A> {
14641457

14651458
let res_index = hal_samplers.len();
14661459
hal_samplers.push(&sampler.raw);
1467-
res_index
1460+
(res_index, 1)
14681461
}
14691462
_ => {
14701463
return Err(Error::WrongBindingType {
@@ -1505,21 +1498,11 @@ impl<A: HalApi> Device<A> {
15051498
view: &view.raw,
15061499
usage: internal_use,
15071500
});
1508-
res_index
1501+
(res_index, 1)
15091502
}
15101503
Br::TextureViewArray(ref bindings_array) => {
1511-
if let Some(count) = decl.count {
1512-
let count = count.get() as usize;
1513-
let num_bindings = bindings_array.len();
1514-
if count != num_bindings {
1515-
return Err(Error::BindingArrayLengthMismatch {
1516-
actual: num_bindings,
1517-
expected: count,
1518-
});
1519-
}
1520-
} else {
1521-
return Err(Error::SingleBindingExpected);
1522-
}
1504+
let num_bindings = bindings_array.len();
1505+
Self::check_array_binding(self.features, decl.count, num_bindings)?;
15231506

15241507
let res_index = hal_textures.len();
15251508
for &id in bindings_array.iter() {
@@ -1551,13 +1534,14 @@ impl<A: HalApi> Device<A> {
15511534
});
15521535
}
15531536

1554-
res_index
1537+
(res_index, num_bindings)
15551538
}
15561539
};
15571540

15581541
hal_entries.push(hal::BindGroupEntry {
15591542
binding,
15601543
resource_index: res_index as u32,
1544+
count: count as u32,
15611545
});
15621546
}
15631547

@@ -1596,6 +1580,39 @@ impl<A: HalApi> Device<A> {
15961580
})
15971581
}
15981582

1583+
fn check_array_binding(
1584+
features: wgt::Features,
1585+
count: Option<NonZeroU32>,
1586+
num_bindings: usize,
1587+
) -> Result<(), super::binding_model::CreateBindGroupError> {
1588+
use super::binding_model::CreateBindGroupError as Error;
1589+
1590+
if let Some(count) = count {
1591+
let count = count.get() as usize;
1592+
if count < num_bindings {
1593+
return Err(Error::BindingArrayPartialLengthMismatch {
1594+
actual: num_bindings,
1595+
expected: count,
1596+
});
1597+
}
1598+
if count != num_bindings
1599+
&& !features.contains(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY)
1600+
{
1601+
return Err(Error::BindingArrayLengthMismatch {
1602+
actual: num_bindings,
1603+
expected: count,
1604+
});
1605+
}
1606+
if num_bindings == 0 {
1607+
return Err(Error::BindingArrayZeroLength);
1608+
}
1609+
} else {
1610+
return Err(Error::SingleBindingExpected);
1611+
};
1612+
1613+
Ok(())
1614+
}
1615+
15991616
fn texture_use_parameters(
16001617
binding: u32,
16011618
decl: &wgt::BindGroupLayoutEntry,

wgpu-core/src/instance.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,12 @@ impl<A: HalApi> Adapter<A> {
334334
desc: &DeviceDescriptor,
335335
trace_path: Option<&std::path::Path>,
336336
) -> Result<Device<A>, RequestDeviceError> {
337-
let open = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err {
338-
hal::DeviceError::Lost => RequestDeviceError::DeviceLost,
339-
hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory,
340-
})?;
337+
let open = unsafe { self.raw.adapter.open(desc.features, &desc.limits) }.map_err(
338+
|err| match err {
339+
hal::DeviceError::Lost => RequestDeviceError::DeviceLost,
340+
hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory,
341+
},
342+
)?;
341343

342344
self.create_device_from_hal(self_id, open, desc, trace_path)
343345
}

wgpu-hal/examples/halmark/main.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,11 @@ impl<A: hal::Api> Example<A> {
102102
);
103103
(exposed.adapter, exposed.capabilities)
104104
};
105-
let hal::OpenDevice { device, mut queue } =
106-
unsafe { adapter.open(wgt::Features::empty()).unwrap() };
105+
let hal::OpenDevice { device, mut queue } = unsafe {
106+
adapter
107+
.open(wgt::Features::empty(), &wgt::Limits::default())
108+
.unwrap()
109+
};
107110

108111
let window_size: (u32, u32) = window.inner_size().into();
109112
let surface_config = hal::SurfaceConfiguration {
@@ -146,6 +149,7 @@ impl<A: hal::Api> Example<A> {
146149

147150
let global_bgl_desc = hal::BindGroupLayoutDescriptor {
148151
label: None,
152+
flags: hal::BindGroupLayoutFlags::empty(),
149153
entries: &[
150154
wgt::BindGroupLayoutEntry {
151155
binding: 0,
@@ -183,6 +187,8 @@ impl<A: hal::Api> Example<A> {
183187
unsafe { device.create_bind_group_layout(&global_bgl_desc).unwrap() };
184188

185189
let local_bgl_desc = hal::BindGroupLayoutDescriptor {
190+
label: None,
191+
flags: hal::BindGroupLayoutFlags::empty(),
186192
entries: &[wgt::BindGroupLayoutEntry {
187193
binding: 0,
188194
visibility: wgt::ShaderStages::VERTEX,
@@ -193,7 +199,6 @@ impl<A: hal::Api> Example<A> {
193199
},
194200
count: None,
195201
}],
196-
label: None,
197202
};
198203
let local_group_layout =
199204
unsafe { device.create_bind_group_layout(&local_bgl_desc).unwrap() };
@@ -417,14 +422,17 @@ impl<A: hal::Api> Example<A> {
417422
hal::BindGroupEntry {
418423
binding: 0,
419424
resource_index: 0,
425+
count: 1,
420426
},
421427
hal::BindGroupEntry {
422428
binding: 1,
423429
resource_index: 0,
430+
count: 1,
424431
},
425432
hal::BindGroupEntry {
426433
binding: 2,
427434
resource_index: 0,
435+
count: 1,
428436
},
429437
],
430438
};
@@ -446,6 +454,7 @@ impl<A: hal::Api> Example<A> {
446454
entries: &[hal::BindGroupEntry {
447455
binding: 0,
448456
resource_index: 0,
457+
count: 1,
449458
}],
450459
};
451460
unsafe { device.create_bind_group(&local_group_desc).unwrap() }

wgpu-hal/src/dx12/adapter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
262262
unsafe fn open(
263263
&self,
264264
features: wgt::Features,
265+
_limits: &wgt::Limits,
265266
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
266267
let queue = self
267268
.device

wgpu-hal/src/empty.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ impl crate::Surface<Api> for Context {
7474
}
7575

7676
impl crate::Adapter<Api> for Context {
77-
unsafe fn open(&self, features: wgt::Features) -> DeviceResult<crate::OpenDevice<Api>> {
77+
unsafe fn open(
78+
&self,
79+
features: wgt::Features,
80+
_limits: &wgt::Limits,
81+
) -> DeviceResult<crate::OpenDevice<Api>> {
7882
Err(crate::DeviceError::Lost)
7983
}
8084
unsafe fn texture_format_capabilities(

wgpu-hal/src/gles/adapter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
419419
unsafe fn open(
420420
&self,
421421
features: wgt::Features,
422+
_limits: &wgt::Limits,
422423
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
423424
let gl = &self.shared.context.lock();
424425
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);

wgpu-hal/src/lib.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,11 @@ pub trait Surface<A: Api>: Send + Sync {
188188
}
189189

190190
pub trait Adapter<A: Api>: Send + Sync {
191-
unsafe fn open(&self, features: wgt::Features) -> Result<OpenDevice<A>, DeviceError>;
191+
unsafe fn open(
192+
&self,
193+
features: wgt::Features,
194+
limits: &wgt::Limits,
195+
) -> Result<OpenDevice<A>, DeviceError>;
192196

193197
/// Return the set of supported capabilities for a texture format.
194198
unsafe fn texture_format_capabilities(
@@ -524,6 +528,14 @@ bitflags!(
524528
}
525529
);
526530

531+
bitflags!(
532+
/// Pipeline layout creation flags.
533+
pub struct BindGroupLayoutFlags: u32 {
534+
/// Allows for bind group binding arrays to be shorter than the array in the BGL.
535+
const PARTIALLY_BOUND = 1 << 0;
536+
}
537+
);
538+
527539
bitflags!(
528540
/// Texture format capability flags.
529541
pub struct TextureFormatCapabilities: u32 {
@@ -798,6 +810,7 @@ pub struct SamplerDescriptor<'a> {
798810
#[derive(Clone, Debug)]
799811
pub struct BindGroupLayoutDescriptor<'a> {
800812
pub label: Label<'a>,
813+
pub flags: BindGroupLayoutFlags,
801814
pub entries: &'a [wgt::BindGroupLayoutEntry],
802815
}
803816

@@ -847,6 +860,7 @@ impl<A: Api> Clone for TextureBinding<'_, A> {
847860
pub struct BindGroupEntry {
848861
pub binding: u32,
849862
pub resource_index: u32,
863+
pub count: u32,
850864
}
851865

852866
/// BindGroup descriptor.

wgpu-hal/src/metal/adapter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
1919
unsafe fn open(
2020
&self,
2121
features: wgt::Features,
22+
_limits: &wgt::Limits,
2223
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
2324
let queue = self
2425
.shared

0 commit comments

Comments
 (0)