# Grayscale, the GPU way

*Task 3 of 6 · [Data In, Data Out](https://gpu.rocks/learn/data-in-data-out-42b68d01.md) · GPU.js Learn*

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

## Figures

- **one pixel in → one thread → one gray pixel out, for every pixel at once**

## Goal

**Goal:** write a graphical kernel that converts `image` to
grayscale using perceptual luminance.

## Requirements

- Create the kernel with `graphical: true` and `output: [512, 512]`
- Read the pixel for *this* thread from `image`
- Weight the channels `0.299 R + 0.587 G + 0.114 B`
- Write the result with `this.color()`

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

## Starter code

```js
// One thread per pixel. No loops over pixels — ever.
const gpu = new GPU({ mode });

const grayscale = gpu.createKernel(function (image) {
  // TODO: read this thread's pixel from image, weight the channels
  // 0.299 R + 0.587 G + 0.114 B, and write it with this.color()
  this.color(1, 0, 1, 1);
}, {
  output: [512, 512],
  graphical: true,
});

await grayscale(inputImage);
render(grayscale.canvas);
```

---

Interactive version: https://gpu.rocks/learn/data-in-data-out-42b68d01/3

[Previous task](https://gpu.rocks/learn/data-in-data-out-42b68d01/2.md) · [Next task](https://gpu.rocks/learn/data-in-data-out-42b68d01/4.md)
