DevBlog #70 | Scaling (the performance of) the factory
Greetings Founders!
From all of us at Foundry, we wish you all a happy new year. As some of you may know, we’ve been hard at work at expanding the gameplay side of Foundry. For example, with the recently announced trains we want to allow the player to make factories that span the entire map. But as the factory expands, we have to make sure that it runs properly for our players, even on portable devices like the Steam Deck.
While going through some save files from users that had reported performance issues, we came across a particular condition that would make the game’s performance come to a crawl. By profiling it, we discovered that the game would sometimes spend up to a third of the time that it took to render a frame just on the screen panels of machines. Here’s a screenshot of the mere 27 FPS within a base that definitely needs some performance improvements.
The benchmark place, where performance goes to die…
For the screen panels we already had some optimizations in place to not update the text or contents of the screen panel every frame, but rather periodically. This load balancing trick is used in many systems throughout Foundry, and it prevents the game from suddenly having large stutters when you move around your camera or a power outage hits your base.
However, even though we update the contents of the screens only every few frames, Unity will still have to render each of the 36 screens in the above screenshot one-by-one, each consisting of multiple steps. This is unlike the 3D geometry of the buildings, which are rendered using GPU instancing which makes it cheap to render either 10 or 100 buildings on the screen.
To address this, we thought that it’d made sense to only re-render the screen panels when the screen contents get rendered. Since our screen panels already uses Unity’s UI system and it would take a long time to make a comparable UI system, we opted for trying to get Unity’s UI to rerender periodically. However, to do this we need to take full control over Unity’s UI rendering and replicate how Unity renders the UI of the screens ourselves.
After having done exactly that, the game is now able to render all the screen panels of all the buildings in the world to this single texture. By only updating a single screen per-frame, we avoid the large cost of having to re-render hundreds of individual widgets of the screen panels. And to avoid losing responsiveness when a user wants to read or interact with the screen, the game will only use this optimization at far away distances at various smaller resolutions.
An example of how the various screen panels are all tightly packed into this texture
The last step is to replace the regular screen panel rendering with the versions that are drawn inside this texture atlas cache, as we internally refer to it. Using the same GPU instancing that we use for the assemblers and many of the other buildings, we can draw both old and newly rendered texture just by a single render instruction for the GPU.
The same place, but now optimized!
And the end result is… pretty decent. In this benchmark factory we went from 27 FPS to 32 FPS, which is a 16% improvement that might affect quite a few of our player’s factories out there. This optimization made the screen rendering itself 33% faster in this specific location, but we also no longer risk the issue of having too many screen panels being rendered at the same time since the custom rendering system will only update up to a certain amount of screens anyway. We also have a lot of room for performance improvements regarding the screens now that they’re manually rendered.
I hope this somewhat technical breakdown was understandable enough! For future reports, we’ll try to get back to a more relaxed angle, but I think this was a great example to explain some of the behind-the-screen tricks we use to improve the performance in our game.
- Milan
Follow us on socials:
Sign Up & Get The Exclusive 'NLR-9001' mining drill skin
Get the latest news and updates straight to your inbox and secure your 'NLR-9001' mining drill skin by signing up for news now! The Skin will be available to you in-game once FOUNDRY is released.
By subscribing, you agree to receive news and special offers from Paradox Interactive.