Drawing geometric shapes and lines with LÖVE is pretty straightforward currently, and most of the time the performance overhead from calling
love.graphics.circle / etc. many times every frame is not large enough to have a meaningful impact.
However, those functions can be a huge bottleneck for the same reason that many
love.graphics.draw(image, ...) calls is much less performant than using a SpriteBatch for images: transferring vertex data from the CPU to the GPU each time the function is called is very expensive, and having so many draw calls instead of batching data together is very expensive. GPUs can handle drawing hundreds of thousands of lines or shapes every frame, but only if the data is kept on the GPU and batched together.
When mobile devices using OpenGL ES enter the equation, the current bottlenecks with drawing geometric shapes become much worse - keeping data on the GPU (via vertex buffers) and batching the rendering of multiple objects into a single draw call can mean the difference between being able to draw only 30 objects at 60fps versus 10000+ objects at 60fps.
The trouble with creating an API for using vertex buffers with LÖVE's lines and shapes is that, unlike images which always have 4 vertices, every shape can have a different number of vertices, and vertex buffers have a static size. Lines are even tougher because the number of vertices depends on the line style - 'smooth' lines use many more vertices than 'rough' ones.
Incidentally, the current SpriteBatch implementation has a similar problem with Geometry objects which have more than 4 vertices - it can't accept them because each sprite id corresponds to a fixed size of 4 vertices, and the sprite size can't be variable both because the SpriteBatch can't be efficiently resized and because internally the SpriteBatch uses a static repeating list of vertex indices so it can render triangles from the vertices (although that's more of an implementation detail.)
Is it possible to make a nice API for using vertex buffers with geometric shapes without imposing too many restrictions, given the constraints? What would it look like?
One option would be for the lover to simply specify the maximum number of vertices (rather than individual shapes) in a single geometry batch. However, due to LÖVE's implementations of shape/line rendering, the number of vertices per shape is not at all clear to lovers. This would also have unsolved problems with the vertex index buffer (index buffers likely being necessary to batch multiple distinct shapes into a single draw call) having a static size but the number of vertex per shape not being clear either, and not scaling linearly with the amount of vertices per shape.