Well my final observations after testing... To me sf::VertexBuffer was slower than sf::VertexArray when storing 50,000 objects with sf::TriangleFan using 8 points (octagon). The difference was roughly 580ms to 110ms .
And within the sf::VertexBuffer options, The speed was fastest with sf::VertexBuffer::Static then Dynamic then Stream respectively.
Comparing sf::Texture to a regular colour fill at around 50,000 objects regular colour fill was slightly faster at about 10% (110ms to 100ms) But anything below 5000 objects the difference is negligible. (11ms to 12ms) And sf::Vertex was faster than sf::VertexArray.
With 50000 objects using sf::Vertex in loop, using textures was 23ms as opposed to around 17ms with color fill. With 5000 objects both resulted about 1 or 2ms each.
Lastly, avoiding divisions and optimizing algorithms did speed up the rendering by another 1-4%. And less points (for instance using an octagon instead of circle) sped things up even more.
Of course, on stackoverflow there was one QuadTree expert who claimed to hit a million particles at 60fps! But I'm happy with 50,000 objects for now, maybe one day I'll tackle dynamic QuadTrees, and re-examine SDL2 as well.
Edit: Running i9-9900k + Nvidia RTX 3090 FE windows 10 x64