Legend of Grimrock II Performance Optimization Blog

In case you're interested in reading about he kind of performance optimization tweaks the Legend of Grimrock II developers are working on right now, you'll probably want to check out their latest blog post. Here's a snippet:

Performance Profiler

Some might think that optimizing is boring and tedious because the work is very time consuming and nothing seems to happen to the game on the surface. To help with this I've turned opimizing into a sort of game for myself. Whatever I'm optimizing I first come up with some metric, usually a number whose value I can track and try to make it as small as possible. I set up a challenge for myself to see how low I can push that number. Some things are easy to measure like memory consumption of the process with Windows Task Manager or the time needed to process a single frame. But to really dig deep into performance issues it's necessary to breakdown the measurements into smaller bits to get a better idea what to optimize. Therefore I built a performance profiler directly into the game that I can summon with a press of a button.

The profiler shows milliseconds and percentage of frame time spent in each subsystem of the game and various other statistics. To run at 60 frames per second the computer can spent up to about 16 milliseconds to process each frame, including updating the game world and rendering the view. The profiler also shows amount of temporary memory allocations (Malloc column) during the frame more about that later.

Memory optimizations

Legend of Grimrock 2 is a 32-bit application on Windows so that means that the application can use up to 2GB of memory without hacks. To make matters worse in my experience the real limit is closer to 1.5GB presumably because DirectX resources eat up virtual address space. Textures and other assets eat a lot of memory so 1.5GB is not that much today. Optimizing memory usage will also help with load times, and can potentially increase overall performance too. It's important to get the memory usage as low as possible without sacrificing quality of assets.

After cleaning up unused assets we determined that we still needed to shave off some more memory so I begin looking into what could be done on the code size. One easy optimization which was already planned for Grimrock 1 but I never had time to work on was a simple animation compression technique. In Grimrock 1 animations are stored as (array of structs), where the struct contains position, rotation and scale. This was not optimal because, for example, scaling is very rarely used. In fact most skeletal animation nodes have only rotation movement. A simple optimization is to store keyframes as (struct of arrays), meaning that position, rotation and scale keys are optional. For many animation nodes we just need to store constant position and scale values and varying rotation keyframes. This optimization cut the memory usage of animations by 20 MB.

Another big optimization was compression of vertex format used by models. Previously all model vertices had normal, tangent, bitangent and texcoord vectors stored as 32-bit floating point values. Floats have a very big range and high precision, more than we need so I compressed those into 16-bit integers. Also a common trick is to leave out the bitangent needed for normal mapping because it can be reconstructed in the shader by computing the crossproduct of the normal and tangent vectors (TBN handedness still need to be stored but it fits nicely into tangent vector's fourth component). Vertex format optimization yielded about 75 MB saving.


Spotted on RPGWatch.