Improved JS Mandelbrot Renderer
Recently I decided to see how much I could improve it with improvements to the web stack that have happened since then. The result was much faster than what I’d managed previously:
The main improvements came from the use of typed arrays. As well as the memory savings compared to regular JS arrays that can contain arbitrary values, it enabled the following improvements:
It’s possible for two arrays to share the same backing buffer, even if they have different types. So while image data is exposed as byte arrays with four entries per pixel (the RGBA components), we can create a
uint32array view of the same data with one entry per pixel.
Array buffers can be transferred when posting messages to/from workers. This basically lets us move blocks of memory between threads rather than having to copy them.
It’s now possible to construct new
ImageDataobjects from existing arrays. So we can use arrays transferred from workers as image data directly, removing another set of copies.
I also switched the workers over to rendering 128x128 tiles rather than single rows. This means the memory buffers don’t have to change when the window is resized. In fact, I can allocate one buffer per worker up front, and just transfer it back and forward to avoid more allocations.
It renders nice and fast on my 16 hyperthread desktop system, and also performs decently on the Android devices I have.
Another improvement I added is a simple a toolbar to allow panning around the image, zooming out as well as in, resetting the viewport and switching to fullscreen.
I’ve published the code in a git repo here: