Major performance improvements

When I last worked on this game back in February (was it really that long ago?), I was very new to LÖVE and Lua (in fact, this was my first project ever to use them!) and there were a few suboptimal things I did in the render and update loop, and one of the shaders was pretty much terrible for performance, especially on mobile GPUs. My fastest Android device, a Nexus 5X, was getting around 10FPS, which was atrocious (and my Galaxy Tab 10.1 wouldn't even run at all due to GLSL capabilities).

The biggest culprit was the "reduce" shader, which is what is responsible for making the colors adapt to their neighbors. It had a bunch of unoptimized loops in it, and it used shader code that isn't even supported on older Android devices.

So I rewrote it. The effect is now slightly less accurate to what I was going for, but visually it looks mostly the same, and more importantly, it runs way, way faster on mobile GPUs; my Nexus 5X was now running at around 20FPS, and my Galaxy Tab was able to actually run it at all, albeit at around 2FPS.

That performance was still terrible. So I threw a profiler at it. The profiler told me that almost all the CPU time was being taken up by mapPixel, setPixel, and getPixel. The only place that happens on every frame is where the "anxiety jiggle" effect happens (where the more anxious the critter is, the more the colors jump around on their own).

The biggest problem was mapPixel; on every frame I was resetting the jiggle buffer by setting the texture coordinate to itself. This makes 65536 calls to a closure every frame. LuaJIT is apparently unable to optimize this very well. So I made it just keep track of which pixels were being modified in the swap function, and undid only those pixels afterward. This eliminated mapPixel from the profile.

Now the setPixel and getPixel calls were pretty enormously bad, still taking 53% and 12% of my frame time, respectively. (The rest of the jiggle function took an additional 18%.) So I dug into the LÖVE source; as I suspected, those functions mostly do some simple bounds and type checking on the parameters and marshals between a Lua tuple and a C struct.

Which is slow.

So I changed the jiggle function to manipulate the C struct itself, and now the jiggle function takes 34% of my frame time - down from a total of 83%!

The upshot of this is that on the Nexus 5X it runs at a smooth 60fps, and the Galaxy Tab is at around 5FPS. Still not actually playable  on the latter, but at least it's progress! And to be fair, the Galaxy Tab is from 2011; I'd expect any reasonably recent Android tablet to now be capable of running it acceptably.

(Sadly, my Kindle Fire from 2012 just gets a black screen and needs to be power-cycled. Who knows what's wrong there!)


LÖVE bundle version (1 MB)
Version 42 15 days ago
macOS, x86-64 (13 MB)
Version 36 15 days ago
Windows, x86-64 (4 MB)
Version 33 15 days ago
Windows, x86-32 (4 MB)
Version 35 15 days ago
Technical whitepaper (boring) (7 MB)
Version 7 15 days ago

Get Colorful Critter

Download NowName your own price


Log in with your account to leave a comment.


Nice example of appropriate optimization!