lampshade 0.13.0

Fast, composable GPU primitives for Rust applications using wgpu and WGSL.
Documentation
@group(0) @binding(0)
var<storage, read> input: array<u32>;

@group(0) @binding(1)
var<storage, read_write> data: array<u32>;

@group(0) @binding(2)
var<storage, read_write> aux: array<u32>;

var<workgroup> subgroup_prefixes: array<u32, {{BLOCK_SIZE}}>;

const VT: u32 = {{VT}}u;
const BLOCK_SIZE: u32 = {{BLOCK_SIZE}}u;
const ITEMS_PER_BLOCK: u32 = VT * BLOCK_SIZE;
override EXCLUSIVE: bool = false;

@compute @workgroup_size(BLOCK_SIZE)
fn main(
    @builtin(local_invocation_id) local_id: vec3<u32>,
    @builtin(workgroup_id) group_id: vec3<u32>,
    @builtin(subgroup_id) subgroup_id: u32,
    @builtin(subgroup_invocation_id) lane: u32,
    @builtin(subgroup_size) subgroup_size: u32
) {
    let tid = local_id.x;
    let flat_group_id = group_id.y * 65535u + group_id.x;
    let group_base = flat_group_id * ITEMS_PER_BLOCK;
    let thread_base = group_base + tid * VT;

    var my_vals: array<u32, {{VT}}>;
    var my_sum = 0u;
    for (var i = 0u; i < VT; i++) {
        let idx = thread_base + i;
        if (idx < arrayLength(&input)) {
            my_vals[i] = input[idx];
            my_sum += my_vals[i];
        } else {
            my_vals[i] = 0u;
        }
    }

    let lane_prefix = subgroupExclusiveAdd(my_sum);
    if (lane == subgroup_size - 1u) {
        subgroup_prefixes[subgroup_id] = lane_prefix + my_sum;
    }
    workgroupBarrier();

    let subgroup_count = (BLOCK_SIZE + subgroup_size - 1u) / subgroup_size;
    if (tid == 0u) {
        var prefix = 0u;
        for (var group = 0u; group < subgroup_count; group++) {
            let total = subgroup_prefixes[group];
            subgroup_prefixes[group] = prefix;
            prefix += total;
        }
    }
    workgroupBarrier();

    var running_prefix = subgroup_prefixes[subgroup_id] + lane_prefix;
    for (var i = 0u; i < VT; i++) {
        let idx = thread_base + i;
        if (idx < arrayLength(&input)) {
            if (EXCLUSIVE) {
                data[idx] = running_prefix;
                running_prefix += my_vals[i];
            } else {
                running_prefix += my_vals[i];
                data[idx] = running_prefix;
            }
        }
    }

    if (tid == BLOCK_SIZE - 1u && flat_group_id < arrayLength(&aux)) {
        aux[flat_group_id] = subgroup_prefixes[subgroup_id] + lane_prefix + my_sum;
    }
}