GPU.js Out of Bounds Array Access Behavior

When running kernels in gpu.js, accessing an input array at indices beyond its dimensions does not trigger a typical JavaScript runtime error. Instead, the behavior depends directly on whether the kernel runs on the GPU via WebGL or falls back to the CPU. In GPU mode, out-of-bounds reads typically return zero or clamped edge values due to how textures are sampled, whereas CPU mode returns undefined, which frequently coerces to NaN in mathematical calculations. Understanding this divergence is essential for preventing silent data corruption in parallel processing pipelines.

GPU Mode Behavior (WebGL)

In GPU mode, gpu.js compiles your kernel function into GLSL shaders and loads input arrays into WebGL textures. When a thread accesses an input array using this.thread.x, this.thread.y, or calculated coordinates, the operation translates into texture lookups.

CPU Fallback Mode Behavior

If WebGL is unsupported or if the kernel is explicitly configured with { mode: 'cpu' }, gpu.js runs using standard JavaScript loops.

Consequences of Boundary Mismatches

A common scenario causing coordinate overruns occurs when the kernel's output dimensions are larger than the dimensions of the input array.

Because gpu.js runs one thread per unit of the specified output dimensions, threads assigned to higher coordinates will systematically request indices that do not exist in the source data. Because no error is thrown in GPU mode, kernels may produce output matrices filled partially with correct data and partially with unexpected zeros, masking logical bugs during development.

How to Prevent Out-of-Bounds Access

To ensure deterministic and accurate results across all execution modes:

  1. Synchronize Output and Input Dimensions: Ensure the output configuration of the kernel matches the size of the data being processed.
  2. Implement Manual Bounds Checking: If the output grid must exceed the input size, add conditional logic inside the kernel to handle boundary limits explicitly:
const kernel = gpu.createKernel(function(data, width, height) {
    const x = this.thread.x;
    const y = this.thread.y;

    if (x >= width || y >= height) {
        return 0; // Explicit fallback value
    }

    return data[y][x] * 2;
}).setOutput([largerWidth, largerHeight]);
  1. Pass Array Dimensions as Arguments: Kernels cannot inspect the .length property of input arrays on the GPU. Always supply array boundaries as uniform arguments to facilitate runtime boundary checks.