What's the point of "work groups" for OpenGL compute shaders? glDispatchCompute has the number of work groups as arguments.

What is the point of having work groups? How are they useful, compared to just having NxM independent pixel calculations with a known (x,y) input parameter in the shader?
Work groups share resources. The most notable resources they share are barriers and LDS (Local Data Storage aka shared memory in GL lingo, aka Thread Group Shared Memory).

See Efficient Compute Shader Programming for an example where LDS/TGSM is used to accelerate a simple gaussian blur.

It is an interesting thought exercise of how a simple algorithm (weight average N values and output the result) can be rewritten to better leverage the hardware. Basically with a kernel radius of 5, Pixel A will load pixels [A; E] to average them, pixel B loads pixels [A; F] to average, pixel C loads pixels [A; G], and so on until we hit pixel F which will load pixels [B; J] to average them. So the paper asks the question: why do we load pixels A through F from main RAM so many times? (note: GPUs DO have caches, but if multiple threads are requesting all the same regions is likely many of these loads will miss the cache or have bank conflicts) and instead tries to load A through F ONCE (each thread loads only one pixel) and store it into TGSM memory which is much faster (and can also be accessed directly by the HW). It's basically very similar to manual cache management.

Also if the workgroup happens to be &lt;= than the GPU's native workgroup size, barriers are much cheaper.

Note not all GPUs are created equal. For example current Mali's GPU do not have LDS, and shared memory is "emulated" via RAM fetches, thus trying to use LDS like a cache is only going to hurt performance.