Tuesday, 5 November 2019

Putting lipstick on Sisyphus

Development has been somewhat chaotic lately.  Instead of focusing on one or two particular areas, I've been hammering away at my TODO list - all the little bugs and enhancements and quality-of-life improvements needed to get XAGE in a shippable state.  I'm regularly pushing out new builds of the tools to itch.io to get into good habits as part of an established release process.

Having said that, a number of recent changes have a common theme, which is either to reduce the CPU usage (particularly startup time) or reduce the disk/memory requirements.  Often these optimisations work against each other, so it has taken some experimentation to determine which combinations achieve the best balance.

  • The custom BitArray ("BooleanMatrix", for fast alpha detection on textures) was changed to use a RoaringBitset implementation.  This massively reduces the amount of storage space needed, both file and memory, at a slight performance cost at runtime.
  • The pipeline was changed so that the PNG spritesheets are published as LZ4 compressed 32-bit bitmaps.  While testing with Cart Life I'd noticed some frame drops while loading in a 4K spritesheet mid-game.  The LZ4 compression has an extremely fast decompression rate, and having the raw bitmap data removes the need to decode from the original PNG in-engine.  This loads in textures much more quickly at a cost of moderately increased file sizes.
  • Profiling indicated that FAudio, the audio engine used by FNA, was slow to initialise.  By warming this up on program entry on a throwaway thread, we're able to shave a second or so from the initial startup time.
  • The GameSettings file is now stored as protobuf file, removing a minor XML deserialization performance overhead (a few 100ms).  
  • Using the 'PublishTrimmed' option on the game project has the linker remove unused code, which reduces the final package size.
  • Using the 'PublishReadyToRun' option - a sort of mini AOT solution - reduces the start up time, at the cost of increasing the final package size.
  • Warp was used to produce the final package (as the 'PublishSingleFile' option is not mature enough yet).  Packaging it up in this way increases the very first start up time but reduces the final package size and makes it easier to distribute and run.

I've released an updated version of Last 'n Furious with the above improvements.  The result is a single executable that is smaller (32MB) than the previous version (40MB zipped).  After the initial run, the game starts up in about 1 second, which is about as good as it gets until we are AOT-compiling the final executable in .NET 5.

CPU usage is down slightly, hovering around 2-3% CPU mid-race on my old laptop compared to 4-5% on the previous version.  Memory usage is also down to about 180MB compared to 220MB before.

Mac and Linux builds of the game also exist, though are not yet available due to an outstanding texture issue that only seems to affect the Mac platform - this should be resolved once I get my hands on some actual Apple hardware, like one of the ten richest kings in Europe.

Getting there.