One fill per particle against a 2D canvas, issued from the CPU.
Every renderer runs the same simulation and the same controls, one at a time. Running them together would make them fight over one main thread, and every number would be wrong.
Canvas 2D runs everywhere and needs no feature detection. Below a few thousand shapes you will not be able to tell these renderers apart.
What it cannot do is batch, so cost tracks the number of shapes rather than the pixels they cover.