Task 2 of 5
Hardcoded weights mean writing a new kernel for every filter. The fix: pass the
filter in as an ordinary array argument and loop over its taps. But a GPU
loop wants bounds it can see at compile time — and that is exactly what
this.constants is for: values baked into the kernel when it compiles,
perfectly legal as loop bounds.
This kernel is built with constants: { size: 5, radius: 2 }. Tap
i of the filter lines up with input sample
x + i - radius — clamp that index like before and accumulate
filter[i] * signal[tap].
this.constants.size taps, clamp each tap index, and return the accumulated
weighted sum. One kernel, any 5-tap filter.for (let i = 0; i < this.constants.size; i++) — a constant is a legal boundx + i - this.constants.radius, clamped to 0…127filter[i] * signal[tap] into sum and return itKernel arguments change per call; constants are frozen into the compiled
kernel. That is why this.constants.size can bound a loop when a plain
argument could not.
let tap = x + i - this.constants.radius;
if (tap < 0) tap = 0;
if (tap > 127) tap = 127;
sum += filter[i] * signal[tap];__constant__ memory, Metal has function constants — all so the compiler
knows your loop bounds and can unroll the filter loop.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.