pub const WORKGROUP: u32 = crate::shader_bindings::henad::dispatch::WORKGROUP;
const MAX_GROUPS_PER_DIM: u32 = 65_535;
pub fn linear_dispatch(invocations: u32) -> (u32, u32) {
let groups = invocations.div_ceil(WORKGROUP).max(1);
let groups_x = groups.min(MAX_GROUPS_PER_DIM);
(groups_x, groups.div_ceil(groups_x))
}
#[cfg(test)]
mod tests {
use super::{MAX_GROUPS_PER_DIM, WORKGROUP, linear_dispatch};
#[test]
fn every_invocation_is_covered() {
for n in [0, 1, 255, 256, 257, 50_000, 10_000_000, 100_000_000] {
let (x, y) = linear_dispatch(n);
assert!(
u64::from(x) * u64::from(y) * u64::from(WORKGROUP) >= u64::from(n),
"{n} invocations are not covered by {x}x{y} workgroups"
);
assert!(
x <= MAX_GROUPS_PER_DIM && y <= MAX_GROUPS_PER_DIM,
"{n} exceeds a dimension"
);
}
}
#[test]
fn small_domains_stay_one_dimensional() {
assert_eq!(linear_dispatch(0), (1, 1));
assert_eq!(linear_dispatch(1), (1, 1));
assert_eq!(linear_dispatch(WORKGROUP), (1, 1));
assert_eq!(linear_dispatch(WORKGROUP + 1), (2, 1));
assert_eq!(linear_dispatch(50_000), (196, 1));
}
#[test]
fn the_target_population_needs_a_second_dimension() {
let (_, y) = linear_dispatch(100_000_000);
assert!(y > 1, "100M agents should have folded onto a second dimension");
}
}