GPGPU

You may need to read the article about framebuffers before this one.


General-purpose GPU (GPGPU) refers to doing work with the GPU other than rendering scenes. This can be useful when you need to perform lots of small, independent tasks, which GPUs are designed to excel at. GPGPU work can be performed both via textures and via buffers.

GPGPU With Textures

Conceptually, GPGPU is very similar to a map function, which takes a list and a lambda expression as inputs and creates an output list by applying the lambda expression to each entry in the input list correspondingly. In this example, the rendered fragments compose the input list, the shader program is the lambda function, and a texture or buffer is used to store the output list.

Previous articles have already covered writing to textures and reading from textures via framebuffers. From that point, the only new thing that needs to be done to perform GPGPU work is to read data from a texture on the CPU. This can be achieved with readPixels, which reads pixel data from the read buffer of the currently-bound read framebuffer and stores it in either a typed array or the currently-bound pixel pack buffer.

const out = new Uint8Array(3 * 2 * 4); // 4 channels per fragment for `RGBA`.
gl.readPixels(0, 0, 3, 2, gl.RGBA, gl.UNSIGNED_BYTE, out);

Similar to how the unpack alignment needs to be set to properly load image data into a texture, the pack alignment needs to be set to read data out of a texture. If this isn't done before calling readPixels, rows that aren't divisible by the pack alignment will be padded to the next multiple of the pack alignment with zeros.

gl.pixelStorei(gl.PACK_ALIGNMENT, 1);

Note that since we don't actually care how the result looks, we can use an OffscreenCanvas.

GPGPU With Buffers

This article is a work-in-progress. In the meantime, consider reading these other articles about the same topic:


The next article is about picking.