pub const WEBGPU_BASELINE: (u32, [u32; 3], u32) = (256, [256, 256, 64], 16384);
pub fn compute_limit_notes(module: &naga::Module) -> Vec<String> {
let mut notes = Vec::new();
let (invocations, axes, memory) = WEBGPU_BASELINE;
for entry in &module.entry_points {
if entry.stage != naga::ShaderStage::Compute {
continue;
}
let size = entry.workgroup_size;
let [x, y, z] = size.map(u64::from);
let total = x.saturating_mul(y).saturating_mul(z);
if total > u64::from(invocations) || size.iter().zip(axes).any(|(s, a)| *s > a) {
notes.push(format!(
"the thread group is {} by {} by {} ({total} invocations): WebGPU's default limits are \
{invocations} invocations and {} by {} by {}; the device's must be raised",
size[0], size[1], size[2], axes[0], axes[1], axes[2]
));
}
}
let shared: u64 = module
.global_variables
.iter()
.filter(|(_, g)| g.space == naga::AddressSpace::WorkGroup)
.map(|(_, g)| u64::from(module.types[g.ty].inner.size(module.to_ctx())))
.sum();
if shared > u64::from(memory) {
notes.push(format!(
"the thread group's shared memory is {shared} bytes: WebGPU's default limit is {memory}; the device's must \
be raised"
));
}
notes
}
pub fn interface_notes(interface: &crate::Interface) -> Vec<String> {
use crate::SystemValue::{RenderTargetArrayIndex, ViewportArrayIndex};
let mut notes = Vec::new();
let layered = |v: &crate::Varying| matches!(v.system, Some(RenderTargetArrayIndex | ViewportArrayIndex));
if interface.inputs.iter().chain(&interface.outputs).any(layered) {
notes.push(
"a render target array index or viewport index is carried as a flat varying: WebGPU has no built-in for \
it, and routing a primitive to the layer or viewport it names is the pipeline's"
.into(),
);
}
if interface
.outputs
.iter()
.any(|v| v.system == Some(crate::SystemValue::CullDistance))
{
notes.push(
"a cull distance is carried as a varying: WebGPU has no built-in for it, and culling a primitive whose \
vertices' distances are all negative is the pipeline's"
.into(),
);
}
if interface.stage == crate::Stage::Mesh {
notes.push(
"a mesh program needs the device's mesh shader support (WebGPU's baseline has none): the vertices and \
primitives it writes are the module's output variable, and it reads no payload of a task program"
.into(),
);
}
notes
}