[wgpu-core] make implicit_pipeline_ids arg optional for users that don't provide IDs

This commit is contained in:
teoxoy 2024-07-17 11:29:18 +02:00 committed by Teodor Tanasoaia
parent 7e112ca4c0
commit 91924fb603
7 changed files with 70 additions and 117 deletions

View File

@ -14,8 +14,6 @@ use std::rc::Rc;
use super::error::WebGpuError; use super::error::WebGpuError;
use super::error::WebGpuResult; use super::error::WebGpuResult;
const MAX_BIND_GROUPS: usize = 8;
pub(crate) struct WebGpuPipelineLayout( pub(crate) struct WebGpuPipelineLayout(
pub(crate) crate::Instance, pub(crate) crate::Instance,
pub(crate) wgpu_core::id::PipelineLayoutId, pub(crate) wgpu_core::id::PipelineLayoutId,
@ -118,21 +116,12 @@ pub fn op_webgpu_create_compute_pipeline(
}, },
cache: None, cache: None,
}; };
let implicit_pipelines = match layout {
GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None,
GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => {
Some(wgpu_core::device::ImplicitPipelineIds {
root_id: None,
group_ids: &[None; MAX_BIND_GROUPS],
})
}
};
let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline(
device, device,
&descriptor, &descriptor,
None, None,
implicit_pipelines None,
)); ));
let rid = state let rid = state
@ -397,21 +386,11 @@ pub fn op_webgpu_create_render_pipeline(
cache: None, cache: None,
}; };
let implicit_pipelines = match args.layout {
GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None,
GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => {
Some(wgpu_core::device::ImplicitPipelineIds {
root_id: None,
group_ids: &[None; MAX_BIND_GROUPS],
})
}
};
let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline(
device, device,
&descriptor, &descriptor,
None, None,
implicit_pipelines None,
)); ));
let rid = state let rid = state

View File

@ -256,8 +256,8 @@ impl GlobalPlay for wgc::global::Global {
implicit_context implicit_context
.as_ref() .as_ref()
.map(|ic| wgc::device::ImplicitPipelineIds { .map(|ic| wgc::device::ImplicitPipelineIds {
root_id: Some(ic.root_id), root_id: ic.root_id,
group_ids: wgc::id::as_option_slice(&ic.group_ids), group_ids: &ic.group_ids,
}); });
let (_, error) = let (_, error) =
self.device_create_compute_pipeline::<A>(device, &desc, Some(id), implicit_ids); self.device_create_compute_pipeline::<A>(device, &desc, Some(id), implicit_ids);
@ -277,8 +277,8 @@ impl GlobalPlay for wgc::global::Global {
implicit_context implicit_context
.as_ref() .as_ref()
.map(|ic| wgc::device::ImplicitPipelineIds { .map(|ic| wgc::device::ImplicitPipelineIds {
root_id: Some(ic.root_id), root_id: ic.root_id,
group_ids: wgc::id::as_option_slice(&ic.group_ids), group_ids: &ic.group_ids,
}); });
let (_, error) = let (_, error) =
self.device_create_render_pipeline::<A>(device, &desc, Some(id), implicit_ids); self.device_create_render_pipeline::<A>(device, &desc, Some(id), implicit_ids);

View File

@ -1385,12 +1385,18 @@ impl Global {
let hub = A::hub(self); let hub = A::hub(self);
let missing_implicit_pipeline_ids =
desc.layout.is_none() && id_in.is_some() && implicit_pipeline_ids.is_none();
let fid = hub.render_pipelines.prepare(id_in); let fid = hub.render_pipelines.prepare(id_in);
let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
let is_auto_layout = desc.layout.is_none();
let error = 'error: { let error = 'error: {
if missing_implicit_pipeline_ids {
// TODO: categorize this error as API misuse
break 'error pipeline::ImplicitLayoutError::MissingImplicitPipelineIds.into();
}
let device = match hub.devices.get(device_id) { let device = match hub.devices.get(device_id) {
Ok(device) => device, Ok(device) => device,
Err(_) => break 'error DeviceError::InvalidDeviceId.into(), Err(_) => break 'error DeviceError::InvalidDeviceId.into(),
@ -1505,23 +1511,18 @@ impl Global {
Err(e) => break 'error e, Err(e) => break 'error e,
}; };
if is_auto_layout { if let Some(ids) = implicit_context.as_ref() {
// TODO: categorize the errors below as API misuse let group_count = pipeline.layout.bind_group_layouts.len();
let ids = if let Some(ids) = implicit_context.as_ref() { if ids.group_ids.len() < group_count {
let group_count = pipeline.layout.bind_group_layouts.len(); log::error!(
if ids.group_ids.len() < group_count { "Not enough bind group IDs ({}) specified for the implicit layout ({})",
log::error!( ids.group_ids.len(),
"Not enough bind group IDs ({}) specified for the implicit layout ({})", group_count
ids.group_ids.len(), );
group_count // TODO: categorize this error as API misuse
); break 'error pipeline::ImplicitLayoutError::MissingIds(group_count as _)
break 'error pipeline::ImplicitLayoutError::MissingIds(group_count as _) .into();
.into(); }
}
ids
} else {
break 'error pipeline::ImplicitLayoutError::MissingIds(0).into();
};
let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut pipeline_layout_guard = hub.pipeline_layouts.write();
let mut bgl_guard = hub.bind_group_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write();
@ -1552,16 +1553,14 @@ impl Global {
let id = fid.assign_error(); let id = fid.assign_error();
if is_auto_layout { // We also need to assign errors to the implicit pipeline layout and the
// We also need to assign errors to the implicit pipeline layout and the // implicit bind group layouts.
// implicit bind group layouts. if let Some(ids) = implicit_context {
if let Some(ids) = implicit_context { let mut pipeline_layout_guard = hub.pipeline_layouts.write();
let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write();
let mut bgl_guard = hub.bind_group_layouts.write(); pipeline_layout_guard.insert_error(ids.root_id);
pipeline_layout_guard.insert_error(ids.root_id); for bgl_id in ids.group_ids {
for bgl_id in ids.group_ids { bgl_guard.insert_error(bgl_id);
bgl_guard.insert_error(bgl_id);
}
} }
} }
@ -1629,12 +1628,18 @@ impl Global {
let hub = A::hub(self); let hub = A::hub(self);
let missing_implicit_pipeline_ids =
desc.layout.is_none() && id_in.is_some() && implicit_pipeline_ids.is_none();
let fid = hub.compute_pipelines.prepare(id_in); let fid = hub.compute_pipelines.prepare(id_in);
let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
let is_auto_layout = desc.layout.is_none();
let error = 'error: { let error = 'error: {
if missing_implicit_pipeline_ids {
// TODO: categorize this error as API misuse
break 'error pipeline::ImplicitLayoutError::MissingImplicitPipelineIds.into();
}
let device = match hub.devices.get(device_id) { let device = match hub.devices.get(device_id) {
Ok(device) => device, Ok(device) => device,
Err(_) => break 'error DeviceError::InvalidDeviceId.into(), Err(_) => break 'error DeviceError::InvalidDeviceId.into(),
@ -1703,23 +1708,18 @@ impl Global {
Err(e) => break 'error e, Err(e) => break 'error e,
}; };
if is_auto_layout { if let Some(ids) = implicit_context.as_ref() {
// TODO: categorize the errors below as API misuse let group_count = pipeline.layout.bind_group_layouts.len();
let ids = if let Some(ids) = implicit_context.as_ref() { if ids.group_ids.len() < group_count {
let group_count = pipeline.layout.bind_group_layouts.len(); log::error!(
if ids.group_ids.len() < group_count { "Not enough bind group IDs ({}) specified for the implicit layout ({})",
log::error!( ids.group_ids.len(),
"Not enough bind group IDs ({}) specified for the implicit layout ({})", group_count
ids.group_ids.len(), );
group_count // TODO: categorize this error as API misuse
); break 'error pipeline::ImplicitLayoutError::MissingIds(group_count as _)
break 'error pipeline::ImplicitLayoutError::MissingIds(group_count as _) .into();
.into(); }
}
ids
} else {
break 'error pipeline::ImplicitLayoutError::MissingIds(0).into();
};
let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut pipeline_layout_guard = hub.pipeline_layouts.write();
let mut bgl_guard = hub.bind_group_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write();
@ -1750,16 +1750,14 @@ impl Global {
let id = fid.assign_error(); let id = fid.assign_error();
if is_auto_layout { // We also need to assign errors to the implicit pipeline layout and the
// We also need to assign errors to the implicit pipeline layout and the // implicit bind group layouts.
// implicit bind group layouts. if let Some(ids) = implicit_context {
if let Some(ids) = implicit_context { let mut pipeline_layout_guard = hub.pipeline_layouts.write();
let mut pipeline_layout_guard = hub.pipeline_layouts.write(); let mut bgl_guard = hub.bind_group_layouts.write();
let mut bgl_guard = hub.bind_group_layouts.write(); pipeline_layout_guard.insert_error(ids.root_id);
pipeline_layout_guard.insert_error(ids.root_id); for bgl_id in ids.group_ids {
for bgl_id in ids.group_ids { bgl_guard.insert_error(bgl_id);
bgl_guard.insert_error(bgl_id);
}
} }
} }

View File

@ -433,18 +433,18 @@ pub struct ImplicitPipelineContext {
} }
pub struct ImplicitPipelineIds<'a> { pub struct ImplicitPipelineIds<'a> {
pub root_id: Option<PipelineLayoutId>, pub root_id: PipelineLayoutId,
pub group_ids: &'a [Option<BindGroupLayoutId>], pub group_ids: &'a [BindGroupLayoutId],
} }
impl ImplicitPipelineIds<'_> { impl ImplicitPipelineIds<'_> {
fn prepare<A: HalApi>(self, hub: &Hub<A>) -> ImplicitPipelineContext { fn prepare<A: HalApi>(self, hub: &Hub<A>) -> ImplicitPipelineContext {
ImplicitPipelineContext { ImplicitPipelineContext {
root_id: hub.pipeline_layouts.prepare(self.root_id).into_id(), root_id: hub.pipeline_layouts.prepare(Some(self.root_id)).into_id(),
group_ids: self group_ids: self
.group_ids .group_ids
.iter() .iter()
.map(|id_in| hub.bind_group_layouts.prepare(*id_in).into_id()) .map(|id_in| hub.bind_group_layouts.prepare(Some(*id_in)).into_id())
.collect(), .collect(),
} }
} }

View File

@ -77,18 +77,6 @@ impl RawId {
} }
} }
/// Coerce a slice of identifiers into a slice of optional raw identifiers.
///
/// There's two reasons why we know this is correct:
/// * `Option<T>` is guaranteed to be niche-filled to 0's.
/// * The `T` in `Option<T>` can inhabit any representation except 0's, since
/// its underlying representation is `NonZero*`.
pub fn as_option_slice<T: Marker>(ids: &[Id<T>]) -> &[Option<Id<T>>] {
// SAFETY: Any Id<T> is repr(transparent) over `Option<RawId>`, since both
// are backed by non-zero types.
unsafe { std::slice::from_raw_parts(ids.as_ptr().cast(), ids.len()) }
}
/// An identifier for a wgpu object. /// An identifier for a wgpu object.
/// ///
/// An `Id<T>` value identifies a value stored in a [`Global`]'s [`Hub`]. /// An `Id<T>` value identifies a value stored in a [`Global`]'s [`Hub`].

View File

@ -186,6 +186,8 @@ pub type ImplicitBindGroupCount = u8;
#[derive(Clone, Debug, Error)] #[derive(Clone, Debug, Error)]
#[non_exhaustive] #[non_exhaustive]
pub enum ImplicitLayoutError { pub enum ImplicitLayoutError {
#[error("The implicit_pipeline_ids arg is required")]
MissingImplicitPipelineIds,
#[error("Missing IDs for deriving {0} bind groups")] #[error("Missing IDs for deriving {0} bind groups")]
MissingIds(ImplicitBindGroupCount), MissingIds(ImplicitBindGroupCount),
#[error("Unable to reflect the shader {0:?} interface")] #[error("Unable to reflect the shader {0:?} interface")]

View File

@ -1162,13 +1162,6 @@ impl crate::Context for ContextWgpuCore {
}) })
.collect(); .collect();
let implicit_pipeline_ids = match desc.layout {
Some(_) => None,
None => Some(wgc::device::ImplicitPipelineIds {
root_id: None,
group_ids: &[None; wgc::MAX_BIND_GROUPS],
}),
};
let descriptor = pipe::RenderPipelineDescriptor { let descriptor = pipe::RenderPipelineDescriptor {
label: desc.label.map(Borrowed), label: desc.label.map(Borrowed),
layout: desc.layout.map(|l| l.id.into()), layout: desc.layout.map(|l| l.id.into()),
@ -1211,7 +1204,7 @@ impl crate::Context for ContextWgpuCore {
*device, *device,
&descriptor, &descriptor,
None, None,
implicit_pipeline_ids None,
)); ));
if let Some(cause) = error { if let Some(cause) = error {
if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause { if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause {
@ -1235,13 +1228,6 @@ impl crate::Context for ContextWgpuCore {
) -> (Self::ComputePipelineId, Self::ComputePipelineData) { ) -> (Self::ComputePipelineId, Self::ComputePipelineData) {
use wgc::pipeline as pipe; use wgc::pipeline as pipe;
let implicit_pipeline_ids = match desc.layout {
Some(_) => None,
None => Some(wgc::device::ImplicitPipelineIds {
root_id: None,
group_ids: &[None; wgc::MAX_BIND_GROUPS],
}),
};
let descriptor = pipe::ComputePipelineDescriptor { let descriptor = pipe::ComputePipelineDescriptor {
label: desc.label.map(Borrowed), label: desc.label.map(Borrowed),
layout: desc.layout.map(|l| l.id.into()), layout: desc.layout.map(|l| l.id.into()),
@ -1261,7 +1247,7 @@ impl crate::Context for ContextWgpuCore {
*device, *device,
&descriptor, &descriptor,
None, None,
implicit_pipeline_ids None,
)); ));
if let Some(cause) = error { if let Some(cause) = error {
if let wgc::pipeline::CreateComputePipelineError::Internal(ref error) = cause { if let wgc::pipeline::CreateComputePipelineError::Internal(ref error) = cause {