Task 3 of 6

Grayscale, the GPU way

On the CPU you'd loop over 262,144 pixels one by one. On the GPU, every pixel gets its own thread — the kernel body runs once per pixel, all at the same time.

Array layout in gpu.js

Image data comes in row-major: image[y][x] is the pixel in row y, column x, and each pixel is an [r, g, b, a] array with channels from 0 to 1. Mind the inversion that catches everyone — sizes are given width-first (output: [width, height]), but indexing runs row-first, so this thread's own pixel is image[this.thread.y][this.thread.x]. Swap those two and you read the transpose of your image. Three-dimensional data follows the same rule: output: [w, h, d] is indexed [z][y][x].

one pixel in → one thread → one gray pixel out, for every pixel at once
Goal: write a graphical kernel that converts image to grayscale using perceptual luminance.

Requirements

Hint 1 — which pixel is mine?

Inside a kernel, this.thread.x and this.thread.y tell you which output cell this thread owns. Use them to index into image.

Hint 2 — reading a pixel

image[this.thread.y][this.thread.x] gives you an [r, g, b, a] array with channels in the 0–1 range.

Same idea elsewhere

This is exactly a fragment shader in WebGPU/Metal, or a 2D thread block in CUDA and ROCm — one thread per output element.

All tasks in Data In, Data Out

  1. Pass an Array In
  2. Shape the Output: 2D
  3. Grayscale, the GPU way
  4. Read the Results Back
  5. Images Are Just Arrays
  6. Put It Together: Two Kernels

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.