GPU.js Built-In Thread Coordinates Explained

GPU.js abstracts WebGL and compute shaders into JavaScript, providing built-in context variables that serve the same purpose as GLSL identifiers like gl_FragCoord and gl_GlobalInvocationID. This article details how GPU.js exposes thread coordinates via the this.thread object, how these variables map to native shader execution indices, and how to utilize them within kernel functions.

The Equivalent: this.thread

In GPU.js, the execution index is accessed through the execution context using this.thread. Depending on whether your kernel output is 1D, 2D, or 3D, GPU.js populates the following integer properties:

These properties serve as the functional equivalent to gl_GlobalInvocationID in compute shaders and gl_FragCoord in fragment-shader-based GPGPU implementations.

Comparison to gl_GlobalInvocationID

In WebGPU or OpenGL compute shaders, gl_GlobalInvocationID represents the unique global work-item ID within the dispatch grid (uvec3). GPU.js was designed with this model in mind:

Like gl_GlobalInvocationID, this.thread values are 0-indexed integers representing the discrete work item currently being processed.

Comparison to gl_FragCoord

When using WebGL 1 or 2 fragment shaders for compute, developers traditionally use gl_FragCoord.xy to locate the current pixel. However, gl_FragCoord introduces minor differences:

  1. Floating-point offsets: gl_FragCoord provides window-relative coordinates centered at pixel halves (e.g., 0.5, 1.5, 2.5), requiring explicit floor() operations to convert to integer indices.
  2. Y-axis orientation: In raw WebGL, gl_FragCoord starts at the bottom-left corner.

GPU.js handles this mapping automatically. Under the hood, when GPU.js compiles a kernel to a WebGL fragment shader, it calculates discrete zero-based indices from internal texture coordinates, exposing clean integers via this.thread rather than raw fragment floats.

Companion Variable: this.output

In addition to the thread coordinate, GPU.js provides the grid dimensions via this.output:

This is analogous to obtaining texture dimensions via textureSize() or calculating the total invocation bounds (gl_NumWorkGroups * gl_WorkGroupSize) in GLSL.

Example Usage

const gpu = new GPU();

const kernel = gpu.createKernel(function() {
    // this.thread.x and this.thread.y identify the invocation
    // this.output.x provides the maximum width
    return this.thread.x + (this.thread.y * this.output.x);
}).setOutput([512, 512]);

const result = kernel();

Through this.thread and this.output, GPU.js provides a clean, native JavaScript interface for spatial thread mapping without requiring manual GLSL built-in parsing.