Most efficient way to render large number of 2D objects in GLMakie in real-time?

I’m implementing a real-time visualisation of a simulation that consists of drawing up to tens of thousands of objects on the screen where objects are represented by simple geometric shapes (or combinations thereof). Position, number and state of each object can potentially change in each frame.

So far I have an implementation in SDL2, but it would be nice to be able to use Makie graphs to display some statistics as well. What I am looking for is the most efficient way to implement this with quality being of secondary concern. Potential solutions I have found so far are:

  • rendering into a buffer and then using image to display it (it would be easy to port my SDL2 code for this)
  • using poly directly

Which of these is going to be more efficient and are there any options I have missed?

ETA: all of this is 2D

Thousands of poly’s is quite slow.
What are the shapes?
Would scatter or meshscatter work, with rotation/markersize?
What’s you SDL2 code, to get an idea?
Do you have an MWE?

Currently mostly circles of varying sizes/colours, but I tend to mix that around depending on what exactly I want to know.

It would definitely work, the question is how efficient it would be. Note that objects are removed and created reasonably frequently, so I’m not sure if that would work with Observables.

Not sure how much that will help, but this is what the bit of the code that does the population rendering currently looks like:

	pc = model.world.pop_cache.data

	r1_p = 1
	r2_p = floor(Int, model.pars.spread_exchange/zoomx)

	for y in 1:size(pc)[1], x in 1:size(pc)[2]
		for a in pc[y, x]
			p = a.pos ./ (zoomy, zoomx)

			col = rgb(a.coop*150+105, a.coop*150+105, 255)
			col2 = rgb(100, 100, 100)
			
			circle_fill(canvas, floor(Int, p[1]), floor(Int, p[2]), r1_p, col, true)
			circle(canvas, floor(Int, p[1]), floor(Int, p[2]), r2_p, col2, true)
		end
	end

For technical reasons (event-based simulation) there is no central register for the population and I have to access it via the grid cache that I use to speed up 2D range queries. That should be irrelevant for the visualisation, though.

Note also that circle* and rgb are my own implementation (from a time before SimpleDirectMediaLayer.jl had SDL’s drawing primitives), so it would be quite easy to change them to draw into something that’s compatible with image.

The naive way of just changing the whole vector of particles should work for a few hundred thousands I’d say.

With a few tricks you could also delete/remove and only update a few particles on GPU memory directly… I don’t have time right now, but I can make an example some time.