use cubecl::prelude::*;
use dspk_core::compute::{negative_infinity, positive_infinity, row_position};
pub const PAIR: u32 = 2;
#[cube(launch)]
pub fn envelope_kernel<F: Float>(
input: &[F],
edges: &[u32],
out: &mut [F],
columns: u32,
rows: u32,
row_stride: u32,
#[comptime] units: u32,
) {
let row = row_position();
if row < rows {
let unit = UNIT_POS_X;
let channel = row / columns;
let column = row % columns;
let base = channel * row_stride;
let end = edges[(column + 1u32) as usize];
let mut lo = positive_infinity::<F>();
let mut hi = negative_infinity::<F>();
let mut s = edges[column as usize] + unit;
while s < end {
let x = input[(base + s) as usize];
if x < lo {
lo = x;
}
if x > hi {
hi = x;
}
s += units;
}
let mut lo_s = Shared::<[F]>::new_slice(comptime!(units as usize));
let mut hi_s = Shared::<[F]>::new_slice(comptime!(units as usize));
lo_s[unit as usize] = lo;
hi_s[unit as usize] = hi;
sync_cube();
let stride = RuntimeCell::<u32>::new(units / 2u32);
while stride.read() > 0u32 {
let s = stride.read();
if unit < s {
let other = (unit + s) as usize;
let (lo_o, hi_o) = (lo_s[other], hi_s[other]);
if lo_o < lo_s[unit as usize] {
lo_s[unit as usize] = lo_o;
}
if hi_o > hi_s[unit as usize] {
hi_s[unit as usize] = hi_o;
}
}
sync_cube();
stride.store(s / 2u32);
}
if unit == 0u32 {
out[(row * PAIR) as usize] = lo_s[0];
out[(row * PAIR + 1u32) as usize] = hi_s[0];
}
}
}