# The Brightest Pixels

*Task 3 of 5 · [Top-K Selection](https://gpu.rocks/learn/top-k-selection-1ba56df3.md) · GPU.js Learn*

The same two moves, one dimension up. `brightness` is a 64×64 grid — a
sensor frame, a heat map, a saliency map — and the question is which eight cells are
brightest. Every thread now scans the grid with two loops instead of one, and "earlier in
the array" means earlier in **row-major order**: the flat index of cell
`[y][x]` is `y * 64 + x`. (Mind the inversion that catches everyone:
the launch shape is given width-first, `output: [64, 64]`, but indexing runs
row-first, `grid[this.thread.y][this.thread.x]`.)

The other change is what comes back. The eight brightest *values* are rarely what
anyone wants — you want to know *where* they are. So the picker returns the flat
index rather than the value, and JavaScript decodes it: `y = Math.floor(idx / 64)`,
`x = idx % 64`. Carry the index and you can always look the value back up; carry
the value and the location is gone for good.

## Goal

**Goal:** rank all 4,096 cells, then return the **flat indices**
of the eight brightest, brightest first.

## Requirements

- The ranking kernel is 2D — `output: [64, 64]`, two loops over the whole grid
- Tie-break on the flat index `y * 64 + x`: an earlier cell wins a tie
- The picker returns the flat *index* of the cell whose rank is `this.thread.x`
- The brightest cell's value, row and column are logged (already wired up)

## Hint 1 — the same rule, flattened

Compute your own flat index once, before the loops:

```js
const myIndex = this.thread.y * this.constants.size + this.thread.x;
```

Then compare each visited cell's flat index against it — that is exactly the
`j < this.thread.x` test from task 1, in two dimensions.

## Hint 2 — the ranking body

```js
const other = grid[y][x];
if (y * this.constants.size + x < myIndex) {
  if (other >= mine) ahead++;
} else if (other > mine) {
  ahead++;
}
```

## Hint 3 — returning a location

Track the coordinates as you scan and combine them at the end, so nothing has to
be pulled apart again:

```js
if (ranks[y][x] === this.thread.x) {
  foundY = y;
  foundX = x;
}
```

then `return foundY * this.constants.size + foundX;`

## Same idea elsewhere

Finding the brightest few cells of a grid is the last step of a stack of real
pipelines: keypoint detection (SIFT/ORB pick local maxima of a response map), object
detectors ranking anchor boxes before non-max suppression, astronomy source extraction.
They all rank on the device and hand back *indices*, because the payload behind an
index is usually far bigger than a float — the same reason CUDA's
`cub::ArgMax` returns a `KeyValuePair` rather than a value.

## Starter code

```js
// Top-8 over a grid — and what comes back is WHERE, not what.
const gpu = new GPU({ mode });

const rankCells = gpu.createKernel(function (grid) {
  const mine = grid[this.thread.y][this.thread.x];
  const myIndex = this.thread.y * this.constants.size + this.thread.x;
  let ahead = 0;
  for (let y = 0; y < this.constants.size; y++) {
    for (let x = 0; x < this.constants.size; x++) {
      // TODO: this counts every cell. Count grid[y][x] only when it
      // outranks mine — brighter anywhere, or equally bright at a
      // lower flat index than myIndex.
      ahead++;
    }
  }
  return ahead;
}, { output: [64, 64], constants: { size: 64 } });

const pickBrightest = gpu.createKernel(function (ranks) {
  let foundY = 0;
  let foundX = 0;
  for (let y = 0; y < this.constants.size; y++) {
    for (let x = 0; x < this.constants.size; x++) {
      // TODO: every slot is fetching rank 0. Slot this.thread.x wants
      // the cell whose rank is this.thread.x.
      if (ranks[y][x] === 0) {
        foundY = y;
        foundX = x;
      }
    }
  }
  return foundY * this.constants.size + foundX;
}, { output: [8], constants: { size: 64 } });

const ranks = await rankCells(brightness);
const spots = await pickBrightest(ranks);

// Flat index back to a location — this part is plain JavaScript.
const row = Math.floor(spots[0] / 64);
const col = spots[0] % 64;
console.log('brightest:', brightness[row][col], 'at row', row, 'col', col);
console.log('all eight (flat indices):', spots);
```

---

Interactive version: https://gpu.rocks/learn/top-k-selection-1ba56df3/3

[Previous task](https://gpu.rocks/learn/top-k-selection-1ba56df3/2.md) · [Next task](https://gpu.rocks/learn/top-k-selection-1ba56df3/4.md)
