This (old) post originally appeared on the website of Infi, the company I co-founded in 2003.
Every two weeks, one of us gives a talk to the other employees here at Infi. The subject of these talks are mostly related to our work -something technical or project management- but you are free to choose the subject you want.
Last Monday I gave this talk (which we call the ‘Infi Academy’). This was a good excuse for me to take some time and give two things a try that I’ve had on my wishlist for a while:
- The Go language introduced by Google last November.
- The rendering of distance fields described by Iñigo Quílez in this article on his site.
As usual, I had a tight schedule. Starting on the Sunday afternoon just before the Monday of my talk, I had only 6 hours to learn Go, build a distance field renderer and create a nice presentation.
Understanding (and writing) the distance field renderer was also easy, mainly because of the excellent article of Iñigo Quílez. In the slides of my presentation (which you can download below) I follow his line almost exactly.
A distance field is a function giving (at maximum) the minimal distance to a (theoretical) surface for each point in space. Having such a function you can write a fast ray marcher and render images of the surface.
A nice ‘trick’ is to transform the input domain before calling the distance function. Rotation of the input domain along the z-axis based on the z-value of this same domain gives a ‘wrangled’ surface for example. Another example of a nice transformation of the input domain is to use only the remainder of 10 of the original input domain as new input for the distance function. This produces a ‘matrix’ of infinite repeating copies of the original surface in all three dimensions. You can find the images produced by these examples in the presentation attached below.
If you use a lot of transformations and you combine different distance fields, the rendering of a distance field can become a very heavy and CPU-bounded process. For example, it took almost 10 minutes to render the image above.
One of the features of Go is the natural way of writing concurrent code using goroutines. A goroutine is a function executing in parallel with other goroutines in the same address space. You can prefix a function or method with ‘go’ in the Go language to run the call in a new goroutine (similar to the &-sign used in the Unix-shell to run commands in the background).
Because it is easy to parallelize a distance field renderer (by splitting the desired output buffer/image and render each part in parallel), I tried to speed up my renderer using goroutines. Having two CPUs in my laptop, I expected to get a 100% speed-gain by using two goroutines to render each half of the image.
Unfortunately, after parallelization using the goroutines still only one CPU of my laptop was used by the program and my renderer was running as slow as before. I don’t know what went wrong. Maybe the problem is that the goroutines are writing output to the same (shared) memory buffer? Or should I have added some specific compiler-flags while building the program? I still don’t know, so please give me the answer below.
[update] After adding: runtime.GOMAXPROCS(2); at the top of the main function both CPUs are used, resulting in a speed-gain of 80%. GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously. This call will go away when the scheduler improves.
Having two topics to cover (the Go language and the distance field renderer) and only a small amount of time, the presentation is a little bit chaotic and the Go code is probably not as good as it could be. That said: you can download my presentation below. Enjoy ;-)
If you like this post, you may also like one of my other posts:
- Tokyo – breakdown of a webgl fragment shader
- Bring The Pain And Throw It Around In Wreckdoll
- Raymarching distance fields
- Doom 3 – OpenGL Shading Language
- Shadertoy iOS app