Should I try to make all readPixel calls happen immediately after the render calls have been made (perhaps this allows pipelining)?
Yes Yes Yes. readPixels is basically a blocking operation, stopping the pipeline and always killing your performance wherever it happens , because it sends a request for data to the GPU and then waits for an answer that you donโt need to draw ordinary calls.
Make readPixels as small as possible (use one combined buffer to read). Do it as long as possible. Everything else hardly matters.
Should I generally avoid getting information and do all the gpu-side layout and rendering (urgh ...)?
This will give you incredibly better performance.
If your graphics are similar to the one above, you donโt need to do any โlayoutโ at all (which is good, because it would be very inconvenient to implement) - everything except the text is a kind of color or border animation that can be easily performed in the shader, and the entire layout can only be a static vertex buffer (each vertex has attributes that indicate which simulation texel state it should depend on).
The text will be more tedious only because you need to load all the numbers into the texture for use as a sprite and search in it, but this is a standard technique. (Oh, and divide / modulo to get the numbers.)
source share