Skip to main content
  1. Articles/

A rant about GameMaker texture management

Article Game Development GameMaker Performance
I love computers and video games since I was a little kid, and spend my time developing them or porting them to consoles.
Table of Contents

The problem #

I’m currently porting an indie game to consoles that is done with GameMaker. And each time I have to deal with this engine, one thing that pisses me off is how it handles textures. They can’t be compressed at all. For a long time, all textures in a game were stored in PNGs with transparency, taking a lot of disk space, RAM space and video memory (VRAM) space. I mean, PNG actually has some lossless compression (not much for certain kinds of images), but the contents of a PNG have to always be decompressed first before they can be seen or used. So in practice, it’s all uncompressed on the GPU’s VRAM. So, basically, they have a bit of compression when stored in disk, but they are decompressed when loaded into memory, which is what matters most.

What I mean about texture compression is using formats like DXT, ETC, PVRTC or ASTC. These are special compression formats that are designed to be used without decompression by the GPU, that is, when having a texture compressed with any of these formats, it is loaded to the GPU’s VRAM, and the GPU will be able to render that texture without having to decompress it. So textures in VRAM take a lot less space, take less time to load, there’s no time spent in decompression, so more and bigger resolution textures will fit into memory and can improve the look of your game. And this is what the vast majority of games and game engines do… except GameMaker.

Can you let us choose, please? #

Searching about this issue years ago, I found a thread in the GameMaker forums where people talked about the lack of compression options, and one of the devs basically said that compressing textures didn’t make sense as they would look bad on 2D games. There, no compression for you ¯\_(ツ)_/¯. I agree that in some cases like when using pixel art, compression looks really bad and it’s not recommended for that style. But how about letting people choose? And have they thought that maybe not all 2D games have pixel art and have big 2D illustrations that would benefit with the extra performance despite the barely noticeable quality loss? A lot of people have complained for many years about performance and memory problems in their games.

Is it that hard to just add another option and let people choose?

Let’s imagine a game like Hollow Knight (which luckily it wasn’t made with GameMaker). It is a beautiful 2D Metroidvania style game, really good by the way. Imagine all those sprites, backgrounds and animations fully uncompressed. That would have a series of consequences:

  • It would make the game tons of gigabytes bigger. This is the least of the problems, as there are games that surpass 100GBs nowadays anyway. But it’s unnecessary.
  • Loading times would be a lot longer.
  • The game would crash in a lot of systems as it would require a lot more RAM and a lot more VRAM that old systems might not have.
  • A lot more stuttering caused by loading big textures on the fly during gameplay.

So it would become a game much more demanding and difficult to optimize. Pixel art usually consists on really small textures, so having them all uncompressed is not an issue at all. But for the rest of 2D games… I can assure you that many of them consume more VRAM that some big budget 3D games.

They tried… #

After many years of the engine not having compression options, one day they finally announced a new format. YAY! Hurray! And it’s called QOI. Textures are a bit smaller and faster to decompress than PNG. And that’s nice and all… but we’ve got exactly the same problem. They have to be decompressed before they can be used… so they still take a lot of memory once loaded… so in practice still nothing has changed…

Also they provided a variant compression format called BZ2+QOI, which is kind of like putting an image inside a Zip file. It has a bit better compression but decompression is A LOT slower. Maybe it’s not that noticeable on PC, but on the Nintendo Switch… oh boy… that format is unusable. It’s painfully slow. A couple of games I’ve worked on took like ten seconds to load each room, and then the gameplay was a stuttery and painful mess. And BZ2+QOI is what comes set by default. So the first thing I always have to do is to change all textures to QOI. And suddenly no more loading times and no more slowdowns. But still there’s the problem of crashes due to textures not fitting the VRAM…

It gets worse #

Speaking of loading times, I noticed that GameMaker games take a bit to boot. And on Switch is even worse. I’ve worked on games that took like 20 seconds to boot! In fact, the engine allows you to set a boot loading image so the game is not stuck at a black screen for that long. So what’s up with that? Recently I discovered the reason… EVERY GAMEMAKER GAME LOADS ALL TEXTURES, ALL THE TEXTURES THAT THE WHOLE GAME HAS FROM BEGINNING TO END, INTO RAM DURING BOOT AND STAY THERE THE WHOLE TIME YOU PLAY THE GAME. TAKING A FUCKTON OF MEMORY.

What any sane game engine does is as follows. Let’s imagine that we want to render a wooden box:

  • First the texture of the box is loaded from the hard disk or SSD into RAM.
  • From RAM proceed to copy it to the GPU VRAM.
  • Once the texture is in the VRAM, it is ready to be used and rendered.
  • The texture that was loaded into RAM can be deleted, as it is not needed anymore. Having it on VRAM is all that’s needed for rendering. There are exceptions though. For example, if you want to do real-time changes to the texture, you want to keep it in RAM to edit it there, and then upload it again to VRAM after each change for rendering. But most of the time, you won’t need to keep the texture in RAM.

And here comes PainMaker and not only keeps currently used textures in RAM unnecessarily… keeps ALL OF THEM.

And let’s think about the Switch, which only has 4GB of unified memory, and about 1GB is used by the operating system. So in practice, ~3GB of memory. Being unified memory means that those 3GB are used for BOTH RAM and VRAM, instead of being separated. In those miserable 3GB we need to fit all the textures of the game, and then duplicates of some of those textures for rendering (along with audio, buffers, code, etc). I’m guessing that on smartphones it will be a similar experience.

They’ve done some improvements though #

Thank heavens… just last year (2022, after 23 years since the engine exists) they added the possibility of not loading all textures into memory 🎊🎉🎉🎉🎊. You can load only the ones you need! The feature is called “Dynamic Texture Pages”, and that makes quite the difference. I’ve been reducing boot times a lot and I no longer have to worry about having low memory. But it takes some work when the game has not been designed to use this feature.

Conclusion #

So in the end, a lot of these issues have been resolved actually. Very recently, but better late than never. I had to deal with them in my previous projects and it wasn’t fun. But for the current one, in which I was having memory issues and crashes, I discovered the “Dynamic Texture Pages” feature just a few days ago and it helped a lot. But there’s still the problem of textures being uncompressed in VRAM, which is pretty important. I hope to see the day in which they add proper compression formats so it finally works like a normal game engine.