Task 6 of 6

Put It Together: Two Kernels

Everything from this module in one pipeline. Kernel one reads the photo and produces a 64×64 luminance map — pure numbers. That result comes back to JavaScript, and you pass it straight into kernel two, a graphical kernel that paints the map as a grayscale picture.

Array in → numbers out → array in again → pixels out. Data flowing through kernels is the whole game (and Pipelines & Textures shows how to keep that flow on the GPU).

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].

Goal: finish both kernels — luminance returns 0.299r + 0.587g + 0.114b per pixel, and paint renders the map as gray pixels with this.color().

Requirements

Hint 1 — the luminance pass

Same lookup as before, but return a number:

return 0.299 * pixel[0] + 0.587 * pixel[1] + 0.114 * pixel[2];
Hint 2 — the paint pass

map is a plain 2D array of numbers, so

const l = map[this.thread.y][this.thread.x];
this.color(l, l, l, 1);

Same idea elsewhere

Multi-pass pipelines are the backbone of GPU work: render passes in graphics, kernel launch chains in CUDA, encoder passes in WebGPU. The handoff you just did through JavaScript is the slow version — pipelines (Pipelines & Textures) keep it on-device.

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.