Rebellion: Building and testing an in-house cross-platform triple-A game engine

Rebellion: Building and testing an in-house cross-platform triple-A game engine

By Mike Healey, Rebellion

September 29th 2017 at 12:00PM

Mike Healey from Rebellion talks us through how the independent developer keeps its technology the best it can be

Rebellion’s in-house engine, codenamed Asura, has been in development for nearly two decades and has been used to ship dozens of games on platforms including PlayStation 2, PS3 and PS4, Xbox, Xbox 360 and Xbox One, Wii and WiiU, handheld devices such as the PSP and iOS/Android phones and tablets, not to mention all the versions of DirectX and the various PC graphics architectures which have arisen over that time as well as supporting VR on various PC headsets and PlayStation VR.

Most major components of the engine have been rewritten and replaced over the years to keep up with the state of the art and this process will continue in order to meet the changing needs of game development. The engine powered one of the first PC games supporting DirectX 12 and also a PlayStation VR launch title and continues to be cutting-edge. It now features support for PS4 Pro, Xbox One X and the latest generations of PC CPUs and GPUs and was featured at AMD’s Ryzen and Threadripper worldwide launches to demonstrate the speedups that can be achieved using multi-GPU rendering and multithreaded CPUs.

How does a relatively modest-sized team in an independent game development studio keep up with all of the innovation and new features required to produce an engine capable of delivering high-end graphics to make AAA games such as Sniper Elite 4 and Battlezone VR?

These days the architectural differences between the CPU and GPU hardware used on current platforms are much less than they used to be, and there has been some convergence in the approaches taken by graphics APIs such as DirectX 12, Vulkan and the various console-specific equivalents. This has opened up new opportunities to share more of the rendering code between different platforms. Where the engine used to have completely separate code paths for the rendering on each platform and specialised shaders to match it is now possible to write efficient rendering code at a higher level. With a minimal translation step, the same shader code can be fed into the shader compiler for each platform and produce optimised binary code.

An interesting problem that arises in a cross-platform engine is ensuring that all platforms render the same scene correctly. When each platform was using bespoke rendering code this testing was difficult to automate as some slight variations in nearly every pixel could be expected and still have the scene look correct to the player. The best method was found to be manual acceptance of a visual comparison of various test scenes and then using the nightly code builds to regenerate the same test scenes and using image comparison tools to ensure that any changes introduced day to day were flagged up and checked.

However, now that the rendering code is identical across multiple platforms it has become possible to have image comparison tools check different platforms against each other simply by setting the graphics options (texture and shadow detail, render target resolution etc) to the same values on each platform.

The Asura engine tries to make as much code as possible be platform-independent but without compromising on efficiency; where a system can be written more efficiently using platform-specific methods (e.g. file access which wants to take advantage of APIs to deal with decompression) a chunk of code is written for each platform rather than trying to use purely portable code with standard APIs. However, around 90% of the engine code is cross-platform.

This approach does not come without its challenges: building the same code for multiple platforms can reveal subtle differences in how compilers build the same code. Although compilers from different providers are slowly becoming more uniform, sometimes their adherence to C++ standards varies and inevitably some compilers will be better at issuing warnings for code that looks like it is not doing what the programmer intended and these warnings are useful in catching bugs early, even though they may only result in compilation errors on one platform.

To try and address these types of issues, Rebellion has invested in a large build farm consisting of dozens of computers including both physical desktop machines and virtualised instances which constantly build changes made to the source code by the development team. This system is able not only to catch problems after code has been committed to the source code repository but is also configured to build various configurations automatically at the pre-commit code review stage and report any errors or warnings before it goes near any other developers.

More rarely, there may be some code that runs correctly on one platform but due to a difference in compiler optimisations or the speed of the target hardware does not work as intended on another. There is no substitute for interactive testing to catch things like this and it is well known that a bug is much easier to fix the sooner it is found. This is one reason that Rebellion’s development teams always use the latest available engine code every day and do not wait for a lengthy release process to be completed before being able to take advantage of the latest features and improvements.

This means that when testing content changes on various target platforms anyone on the development team, including artists and designers can spot and report problems so they get resolved much more quickly. It also means that it’s possible for them to make a feature request for the engine in the morning and for it to be added and available on all target platforms by lunchtime! Of course, when a project is nearing completion it moves to a stable branch of the engine, but as testimony to how stable the live engine typically is, this lockdown typically happens only a matter of weeks before a project enters its final submission stage.

Now that more of the grind work of porting code to new platforms and testing it is taken away from the development team it means that more time can be spent optimising the code and adding new features to keep up with all the latest advances in rendering techniques. The result is that the company is now in a period of growth where every team member’s contribution is able to make a bigger difference than ever.