How do we solve big video memory requirements in a 2D game?
We are developing a 2D game (Factorio) in allegro C/C++, and we are facing a problem with increasing video memory requirements as the game content increases.
We currently gather all the info about images that are going to be used first, crop all of these images as much as possible and organize them into big atlases as tightly as possible. These atlases are stored in video memory, the size of which depends on the system limitations; currently it is usually 2 images of up to 8192x8192, so they require 256Mb to 512Mb video memory.
This system works pretty good for us, as with some custom optimisations and splitting the render and update thread we are able to draw tens of thousands of images on the screen in 60 fps; we have many objects on the screen, and allowing a big zoom-out is a critical requirement. As we would like to add more, there is going to be some trouble with the video memory requirements, so this system can't possibly hold.
One of the things we wanted to try is to have one atlas with the most common images, and the second as a cache. The images would be moved there from the memory bitmap, on demand. There are two problems with this approach:
- The drawing from memory bitmap to video bitmap is painfully slow, in allegro.
- It is not possible to work with video bitmap in other than the main thread, in allegro, so it is practically unusable.
Here are some additional requirements we have:
- The game must be determistic, so the performance issues/loading times can never alter the game state.
- The game is real time, and soon to be multiplayer, as well. We need to avoid even the smallest stutter at all costs.
- Most of the game is one continuous open world.
The test consisted of drawing 10 000 sprites in a batch for sizes from 1x1 to 300x300, several times for every configuration. I did the tests on the Nvidia Geforce GTX 760.
- Video bitmap to video bitmap drawing took 0.1us per sprite, when the source bitmap wasn't changing between individual bitmaps (the atlas variant); the size didn't matter
- Video bitmap to video bitmap drawing, while the source bitmap was switched between drawings (non atlas variant), took 0.56us per sprite; the size didn't matter, either.
- Memory bitmap to video bitmap drawing was really suspicious. Sizes from 1x1 to 200x200 took 0.3us per bitmap, so not so horribly slow. For larger sizes, the time started to raise very dramatically, at 9us for 201x201 to 3116us for 291x291.
Using atlas increases the performance by a factor greater than 5. If I had 10ms for the rendering, with an atlas I'm limited to 100 000 sprites per frame, and without it, a limit of 20 000 sprites. This would be problematic.
I was also trying to find a way to test the bitmap compression and 1bpp bitmap format for shadows, but I was unable to find a way to do this in allegro.