cera 0.5.1

Rust-native LLM inference engine
Documentation
// Polar half-spectrum → complex, for the GPU ISTFT front stage.
//
// The detokenizer emits each frame as `[log_abs_0..log_abs_{bins-1},
// angle_0..angle_{bins-1}]` (the CPU `istft_to_pcm` reads exactly this layout).
// This kernel maps that to the interleaved real/imag half-spectrum the iDFT
// matmul consumes: `re_j = exp(log_abs_j)·cos(angle_j)`, `im_j =
// exp(log_abs_j)·sin(angle_j)`. Input and output share the per-frame stride
// `2·bins`, so the re block overwrites the log_abs block position and the im
// block overwrites the angle block position (in a distinct output buffer).
//
//   binding 0: spectrum  f32, read  (n_frames · 2·bins)
//   binding 1: out       f32, write (n_frames · 2·bins), [re | im] per frame
//   binding 2: params    (n_frames, bins)
//
// Dispatch: one thread per (frame, bin), ceil(n_frames·bins / 256) groups of 256.

[[vk::binding(0)]] StructuredBuffer<float>   spec_buf : register(t0);
[[vk::binding(1)]] RWStructuredBuffer<float> out_buf  : register(u1);
[[vk::binding(2)]] StructuredBuffer<uint2>   par_buf  : register(t2);

[shader("compute")]
[numthreads(256, 1, 1)]
void exp_polar(uint3 gid : SV_DispatchThreadID) {
    uint bins = par_buf[0].y;
    uint total = par_buf[0].x * bins;
    uint i = gid.x;
    if (i >= total) {
        return;
    }
    uint frame = i / bins;
    uint j = i % bins;
    uint base = frame * 2u * bins;
    float log_abs = spec_buf[base + j];
    float angle = spec_buf[base + bins + j];
    float mag = exp(log_abs);
    out_buf[base + j] = mag * cos(angle);
    out_buf[base + bins + j] = mag * sin(angle);
}