• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Any way to force GMS 2 to NOT briefly load ALL resources into RAM on launch?

Bagoman

Member
I'm not sure why I am having the hardest time finding anything regarding this, perhaps because most projects don't hit the file size where it becomes necessary.

My game takes anywhere from 100-800MB of ram to run depending on what menu/gameplay segment you are in, but right on startup it spikes to the full value (1.4GB) of the whole project before going back down near instantaneously.

Problem is, this crashes some really low end PC's - and I cannot find anywhere a way to get the engine to not do this. 'Create textures on demand' appears to be nonexistent in the current version, so I'm honestly unsure how to proceed. Hopefully someone with a little more brainpower than I have has come across this problem before and knows of a solution. Thank you so much in advance!
 

TsukaYuriko

☄️
Forum Staff
Moderator
Texture pages are only loaded once they are required. This is the default. I don't think it's the texture pages that are causing the problem, or if it is, it's not intended behavior.

Audio resources will be loaded into memory if you set them to do so in their properties. How is your audio setup looking?

Neither of these would exhibit a memory usage spike followed by an instant decline, though. Put a breakpoint at the first line of your game and start in debug mode. Step through the code until the memory usage drops. When does that happen (if not instantly)?
 

Bagoman

Member
Texture pages are only loaded once they are required. This is the default. I don't think it's the texture pages that are causing the problem, or if it is, it's not intended behavior.

Audio resources will be loaded into memory if you set them to do so in their properties. How is your audio setup looking?

Neither of these would exhibit a memory usage spike followed by an instant decline, though. Put a breakpoint at the first line of your game and start in debug mode. Step through the code until the memory usage drops. When does that happen (if not instantly)?
All my longer music pieces are compressed/streamed, and a majority of other SE's and voice lines are compressed/not streamed in audio groups that don't get pulled until well after launching the game.
 

TsukaYuriko

☄️
Forum Staff
Moderator
Sounds good to me... weird. Have you tried the debugger method yet? It would be a good first step to know if this is something that happens before your code runs and is totally out of your control, or if something in your code is causing it.
 

Bagoman

Member
The debugger is weird here because GMS runnning the game uses the full ram amount the whole time, whereas a compiled build does not - however the spike happens before any code has a chance to run and stops as soon as the game actually opens into the first room.
 

kburkhart84

Firehammer Games
Maybe I'm wrong, but I thought the runner would load in all texture pages into RAM and never release them the whole time. I'm going to have to look it up but I swear I thought I remembered seeing that somewhere. Then the pages aren't sent to VRAM until they are needed(or loaded directly with the correct function).
 

TsukaYuriko

☄️
Forum Staff
Moderator
The manual for draw_texture_flush states that "by default on all targets, texture pages will only be loaded as they are required". (This used to be different - on Windows, everything used to be preloaded, always. Compare to GMS 1 manual.)


When in doubt... let's try it. 🤔
I tend to draw as much information as I can find from the manual, but unfortunately, there's a bit of radio silence about the inner workings of this (or I just haven't found the right page yet). So, to not get too far into making assumptions, I'll share my findings here, but please take my analysis as nothing more than considerations of what could be going on under the hood, as I unfortunately don't know that exactly and don't have access to any source for it.

Baseline RAM usage of my test project: 20.8 MB, constant within a few hundred KB
After adding 7 4096x4096 sprites, adding them to an otherwise empty texture group and disabling it being exported to Windows: 33.3 MB (odd, but okay), constant within a few hundred KB
After enabling it being exported to Windows: Roughly same as previous
After placing one of the sprites on an asset layer: 99.9 MB, then 35.3 MB after a while (!), constant within a few hundred KB
After placing the other sprites on the asset layer: Roughly same as previous (???)

Huh.

Memory readings are from Task Manager (active private working set), not the debugger. Shared working set reports 22 MB constantly, for all of the tests above.
Debugger reports memory readings of 6 MB for the baseline and 27 MB once I add a single sprite to the room. Further sprites (not instances of the same sprite, but different sprites altogether) don't increase it.

Unless my math is wrong, a 4096x4096 texture page should take up 64 MB of any memory uncompressed (8 bit per channel, RGBA). This is roughly the increase I see when switching the texture group on, at least for a while. It feels like while stuff does get loaded into RAM, it only stays there for a brief moment (before being loaded into VRAM and then removed from RAM?). Processes don't necessarily instantly release memory for performance reasons, so this could be why the spike is only the size of a single texture page even though multiple are loaded - any subsequent ones use and overwrite the memory that was allocated for the first.

This is however merely an experiment, as I'm not familiar with the actual inner workings of GM... so take it with a grain of salt.


Full disclosure: I don't have a full understanding of this topic. In fact, it used to confuse the hell out of me. I used to find the manual about this rather unclear, in some places using the term "memory" in a way that doesn't make it fully clear whether it's talking about RAM or VRAM, which confused me a lot when I initially tried to become familiar with the topic of texture pages years ago. The manual seems to be a lot clearer nowadays, and - as far as I can find - explicitly states "video memory" on any pages that have anything to do with loading texture pages.

I initially replied to this topic thinking - drawing from prior experience, or at least what I thought was what I had experienced in the past - that texture pages are stored both in RAM and VRAM when loaded. This seems to either not be the case anymore, or it has never been the case, although I'm sure that exactly that (texture pages taking up RAM while being loaded) is what many others had problems with and that I helped fix by suggesting them to load their sprites dynamically from external files and only loading the ones that are needed.
According to my experiment, it seems like texture pages are only temporarily loaded into RAM, then loaded into VRAM, then the RAM that was used for this process is freed and, after a while, deallocated. Which blows my mind, to say the least.

This unfortunately doesn't move this topic forward in any way, though, because if my results and conclusions are in any way close to the truth, OP's game should not be loading everything into RAM, but merely the size of one texture page into RAM at most.

I'm unable to find any documentation in the runtime or IDE release notes that says this was recently changed, and I'm now thoroughly confused about how this all really works between what I thought was my past experience and this experiment to the point where I don't trust either of them anymore. The best thing I can suggest at this point is to contact the helpdesk to get it straight from the source (if they are willing to provide this info, that is).
 

Ricardo

Member
Texture pages are always held in RAM no matter what according to my experiments - however they don’t take the usual width*height*4 bytes as when loaded to VRAM, meaning they are somehow compressed. This can be easily tested by adding dozens of big sprites to an unused texture group.The more texture pages, the more RAM is taken. For me, this is by far one of the most frustrating GMS limitations ever since the most obvious workaround - sprite_add - doesn’t work asynchronous when loading local files and loading surfaces dumps using async buffers isn’t a good solution either (dumps are too big even if compressed and create new sprites from surfaces is painfully slow and also blocks the main thread). I’m really looking forward for the day this is going to be properly addressed.
 

kburkhart84

Firehammer Games
The manual for draw_texture_flush states that "by default on all targets, texture pages will only be loaded as they are required".
manual.....

With this function you can remove all textures from video memory, and they will then be reloaded on first use.
Notice how it says VRAM, not just RAM. It then goes on to use the word "memory" but never clarifies it referring to RAM instead of VRAM, inferring that it is referring to VRAM the whole topic.

*****

As you say, nothing wrong with testing. I'm using debug builds and using the Windows Task Manager to see RAM usage. There is only a single object, room, and passthrough shader(not even used). The room doesn't even have an instance in it, and just shows nothing but black, not even referencing the sprites. For easier testing, I upped the TPage size to 8192x8192. I'm just duplicating and modifying the sprite(otherwise the TPage editor will notice that it is the same sprite and optimize the TPage space). I'm doing massive 8192x8192 sprites to ensure one page per sprite.

Notes - RAM in Task Manager(RAM in debugger)

Single sprite - 23.4 MB(12.31MB)
Two Sprites - 32.5MB(20.88MB)
Three Sprites - 40.5MB(29.83MB)

I redid the test, but actually using the sprites in some form(all same TPage group), specifically as the room background. The RAM usage was exactly the same, regardless of whether I was drawing the sprites anywhere or not.

For giggles, I paid some attention to my E.T. Jam entry. It has a couple 1920x1080 sprites, and one 4096x4096 one for the level, plus lots of 128x128 frames of animation for the enemies and E.T. It never goes over 72.8MB RAM via the task manager, despite all those sprites. I noticed the IDE had jumped to 4GB RAM usage when debugging the E.T. project too, and didn't release that RAM despite reloading the "test bed" project.

*****
So going from this, things are certainly being loaded into RAM, and more sprites means more stuff in RAM. However, though I had originally thought we were getting full sized lossless images, it certainly seems to not be the case. You mentioned the 4096x4096 page using 64MB, but the RAM didn't increase by that much. Even with my 8192x8192 pages, RAM was only increasing by 8MB or so for each added page. I also noted that for some reason, the "Surfaces & Textures" watch for debugging isn't working with my test bed project, though it works fine for E.T. and shows everything. It does indeed show 64MB for the 4096x4096 TPages, of which I had I think 4 or 5 in the end. But the RAM never shows usage of much of that. I guess there is either some kind of extremely compressed version stored in RAM, and whether that also gets used in VRAM or not, I can only guess, but it is certainly possible that it doesn't stay compressed in VRAM since the debugger shows the "full" size as far as memory usage.

Just to check, I ran builds of my Clown game(has less graphics but still big sprites), and I ran E.T. as well, both as built projects. They run pretty much the same in IDE as they do as builds from what I'm seeing.

Finally, I opened the actual graph view of my memory usage in the task manager. I'm not seeing any spikes just as the project is loaded either.

*******

So, final verdict, at least as far as I'm seeing things now. It does seem to be loading the whole data.win file(which would basically be the whole game's data except for streaming audio which is external for whatever reason). However, there seems to be some massive compression going on with the graphics.

It seems that GMS2, version 2.3.2 anyway, is quite capable of handling sprites, seemingly much better than before. Despite multiple 4096x4096 textures needed for my E.T. project(which should be 64MB each), the entry is only around just over 64MB as built(even before zip compression). I don't see any RAM spikes beyond basically whatever is the loading of data.win, which is much smaller than expected(53MB for E.T.). The .exe is about 5MB, and there are a few OGGs sitting there as well. I also looked at my PNG file for the terrain(4096x4096), and I'm sure it has some lossless compression, but it is still over 31MB, which is half the "uncompressed full size" of 64MB for that image data. This tells me that our images are indeed supposedly supposed to take up as much memory as we think they are. But Gamemaker is still doing some pretty hard compressing on this data. I'm unsure if the GPU is getting sent full uncompressed data or not, but it is certainly possible it is(which would mean slower texture uploads but theoretical faster performance after that since the GPU isn't messing with compression).

So, I'd have to ask what version the OP is using as far as the IDE and runner, and just how much texture data is actually in this project. I'm not claiming that E.T. is that big of a project but it certainly has enough graphics that it should theoretically use a couple hundred MB of RAM but isn't since the images seem to be highly compressed.
 

rytan451

Member
There is actually texture compression at the GPU level, which is why they don't take width*height*4 bytes when loaded to VRAM. The Factorio development blog actually addresses this in their blog post FFF #281. Here's some technical details on how texture compression on the GPU works.

If you want to save space with surface dumps, you can always use buffer_compress and buffer_decompress. These functions use zlib to compress data, which is the same thing as is used to compressed PNG files (though, I will admit, PNG has some optimizations made to improve compression performance, so you won't get as good of a result).
 

kburkhart84

Firehammer Games
There is actually texture compression at the GPU level, which is why they don't take width*height*4 bytes when loaded to VRAM. The Factorio development blog actually addresses this in their blog post FFF #281.
I wouldn't be fully surprised if this is true, though the debugger claims that the "full" amount of memory is used. It doesn't seem to be using it in RAM, and I haven't done more tests to show the exact GPU VRAM in use for these things. In any case, the issue in this topic is more about RAM spikes at the start of a project it seems, not so much the VRAM or even regular RAM usage over time.

EDIT***

Also, Factorio didn't use Gamemaker, so what they did isn't going to help us here honestly except in a very general sense. And since GMS2 currently doesn't let us do things like controlling texture compression and what-not, we have to go with what we have if we choose to use it.
 

Ricardo

Member
There is actually texture compression at the GPU level, which is why they don't take width*height*4 bytes when loaded to VRAM. The Factorio development blog actually addresses this in their blog post FFF #281. Here's some technical details on how texture compression on the GPU works.
GMS2 doesn’t use not support any GPU compression technique at the moment. Anything loaded to video memory is unpacked in plain RGBA meaning the classic width*height*4 bytes of VRAM. If the system doesn’t have a dedicated GPU, RAM usage goes up quickly when working with big TPages.

Returning to the OP subject, though: TPages are held in RAM (compressed) even if not used, but is hard to tell if the memory spike observed is caused by too many TPages loading at once at startup. This could be the case if all the project sprites were thrown at the Default group, though.
 

kburkhart84

Firehammer Games
GMS2 doesn’t use not support any GPU compression technique at the moment. Anything loaded to video memory is unpacked in plain RGBA meaning the classic width*height*4 bytes of VRAM. If the system doesn’t have a dedicated GPU, RAM usage goes up quickly when working with big TPages.
This is what everything seemed like to me, both because it is technically better for GPU performance and because the debugger shows the full "classic" values even though the RAM does not.

TPages are held in RAM (compressed) even if not used
This is basically the conclusion of my testing, though I'm surprised at exactly how well the compression was working(atleast for my test bunches of scratches for sprites).

but is hard to tell if the memory spike observed is caused by too many TPages loading at once at startup. This could be the case if all the project sprites were thrown at the Default group, though.
This is honestly the conclusion I'm leaning towards. The OP never did mention anything about properly using the texture page system and organizing sprites as such, so it is certainly possible. They mention that the game only uses between 100 and 800MB generally, and that the spike to 1.4GB is right at the start only. Since the sprite data would have to be uncompressed to be sent to the GPU(AFAIK), this RAM spike makes sense if we are right that they haven't organized TPages properly, and I'm generally leaning to that being the issue here.
 
This is honestly the conclusion I'm leaning towards. The OP never did mention anything about properly using the texture page system and organizing sprites as such, so it is certainly possible. They mention that the game only uses between 100 and 800MB generally, and that the spike to 1.4GB is right at the start only. Since the sprite data would have to be uncompressed to be sent to the GPU(AFAIK), this RAM spike makes sense if we are right that they haven't organized TPages properly, and I'm generally leaning to that being the issue here.
Not even sure it has something to do with texture pages. If you have an empty project and you add a bunch of empty sprites, and then run an empty room, you'll see more used Memory in the task manager (RAM, not GPU).
You also get the same numbers if they are split in multiple texture pages. I doubt multiple pages would help for that initial 'spike', since it's all loaded on startup anyways, and I don't see any way around it.
 

kburkhart84

Firehammer Games
Not even sure it has something to do with texture pages. If you have an empty project and you add a bunch of empty sprites, and then run an empty room, you'll see more used Memory in the task manager (RAM, not GPU).
You also get the same numbers if they are split in multiple texture pages. I doubt multiple pages would help for that initial 'spike', since it's all loaded on startup anyways, and I don't see any way around it.
Indeed, it may be exactly based on "pages" but in the end it basically is because more sprites means more pages(unless you make bigger pages, which is same result as far as using more RAM). And I'm still not sure what is going on with the spike either(the OP still hasn't given us much more info to go on). But I understand that there is indeed a specific memory allocation for all the data in the data.win file(which includes the textures, etc...). But that allocation then stays in use, so isn't really a "spike" because it stays there.
 
But I understand that there is indeed a specific memory allocation for all the data in the data.win file(which includes the textures, etc...). But that allocation then stays in use, so isn't really a "spike" because it stays there.
Exactly. Every single thing seems pre-allocated in RAM and then loaded in VRAM as needed/told to.
Don't know how 'compressed' they are in RAM when not yet loaded and not using PNGCrush, tho.
 

kburkhart84

Firehammer Games
Exactly. Every single thing seems pre-allocated in RAM and then loaded in VRAM as needed/told to.
Don't know how 'compressed' they are in RAM when not yet loaded and not using PNGCrush, tho.
PNGCrush....that explains why the image data takes up such little space....I had forgotten that they use that. I think that's how it is stored in RAM as well, and just decompressed when sent to the GPUs, considering the RAM usage seems to be consistently close to the size of the data.win file.
 

Ricardo

Member
PNGCrush is only used at compile time through gml_pragma ("PNGCrush"). Is not used at runtime in any level.
 

kburkhart84

Firehammer Games
PNGCrush is only used at compile time through gml_pragma ("PNGCrush"). Is not used at runtime in any level.
How sure of that are we though? As you say it would seem to be accurate since the manual words it like that...but if they aren't using PNGCrush, they must be using something to compress and then decompress those PNGs. It's certainly possible that they have internal algorithms they are using of course.
 
PNGCrush is only used at compile time through gml_pragma ("PNGCrush"). Is not used at runtime in any level.
Didn't thought of that. Maybe I made the mistake to assume they are compressed until their texture page is loaded, but a look at the manual says...well...pretty much nothing about it.
Will try to check out the actual PNGCrush docs from their own website, see if I have more luck!
 

Ricardo

Member
PNGCrush....that explains why the image data takes up such little space....I had forgotten that they use that. I think that's how it is stored in RAM as well, and just decompressed when sent to the GPUs, considering the RAM usage seems to be consistently close to the size of the data.win file.
99.99% sure is not PNGCrush since that kind of algorithm is not performant enough for real time usage. Add it to a project, flush the cache and build. The compiler log will reveal how awfully slow it is when compressing the TPages.

TPages on RAM seems to take about half of what they take on VRAM... but to be honest I’m not sure what’s exactly used... If I had to guess, taking into account the needed speed, I’d said maybe some sort of zlib. I think I’ll send a ticket and just ask YoYo to figure this out.
 

Ricardo

Member
YoYo support reply:

This is a difficult question to answer because it varies between platforms. An article will likely be added in future on this subject.
 
Top