• 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!

Windows Is texture swapping extremely important?

Zuljaras

Member
Hello again,

I just read about this and I tested it in my games here is the result:
texture swaps.png

How much is normal? This is just the beginning of the game and I will have to draw SO MUCH MORE and add it to the game. Will it hinder my performance? This is really bothering me :(

How big should my Texture pages be? How to organize them? I have read articles but none of them explain this in understandable depth.

I am making open for exploration metroidvania games and there will be lots of free roaming and exploration.
 

obscene

Member
Its easy. Graphics draw in order based on depth (or layers). Put graphics that will draw at the same time on the same texture pages. In theory, you could put ALL your graphics on one texture page and have 0 unnecessary texture swaps. But if they won't fit, then you want to break it up into groups in some smart way based on the order they draw. Example:

1 backgrounds
2 objects
3 UI

3 texture swaps. Plus there are 4 built-in texture swaps so you'd be at 7 if you were doing it 100% right. Other stuff can cause swaps too, like drawing a surface.

13 isn't alot. My game runs between 25-50 based on which effects are on. It runs well for people with even a modest gaming PC but laptop users are having to turn everything off.
 

Coded Games

Member
It's something that I have to consider a lot in my game. The current art style of my game uses a lot of primitives and shapes so I've found that if I draw all of that stuff to surfaces one time and then just draw the surfaces later it improves performance a lot over drawing all the shapes every step. Since I'm using a bunch of surfaces it results in a relatively high number of texture swaps.

Along with that, all of the card art in my game uses fairly high resolution assets (600x600 px) which is then scaled down to fit the card. Since I never know for sure what cards are in the player's deck I can't really know what sprites the player will need at any give moment. Because I this, I use fairly small texture pages (2000x2000) and just accept that fact that things are going to swap a lot.

Overall I've had good enough performance. I have options in the game to reduce the graphs and have implemented a delta timing system so even if a person's computer can't hit 60fps the game is still playable and doesn't run in slow motion.

If anyone has suggestions to improve performance I'm looking for them!
 
"Extremely important" is overstating it. Probably 50-70% of users will program their games having no idea what a texture swap is and never run into any problems. However, if you're using large graphics, or have a metric 💩💩💩💩 ton of different graphics being drawn (or if you're programming for mobile or something where speed is fairly vital) then it -can- become important (not necessarily though). As Knuth said "Premature optimisation is the root of all evil." I'd see what you can get away with first and then optimise the pipeline later if need be, because chances are the problem won't be as big as you think it is. Computers are damn fast nowadays.
 

Zuljaras

Member
"Extremely important" is overstating it. Probably 50-70% of users will program their games having no idea what a texture swap is and never run into any problems. However, if you're using large graphics, or have a metric **** ton of different graphics being drawn (or if you're programming for mobile or something where speed is fairly vital) then it -can- become important (not necessarily though). As Knuth said "Premature optimisation is the root of all evil." I'd see what you can get away with first and then optimise the pipeline later if need be, because chances are the problem won't be as big as you think it is. Computers are damn fast nowadays.
I do not care about mobile so that is out. I do have big sprites on some bosses like 400x400 or something like that.
Should I keep my texture pages at 2000x2000 or make them 4000x4000 ?

I final goal is my game to run fine on low end 4GB RAM integrated Intel video card.
 

Smiechu

Member
The number of swaps is not so important as long as all used texture pages fit in the VRAM.
Big slowdowns occur when a texture page has to be constantly loaded and unloaded from RAM to VRAM every frame. This is the real performance killer.

From my experiance it is safer to use smaller texture pages, it mostly makes a big differance on lo-end devices and integrated graphics.

Also a good practice is to sort the sprites having in mind the draw order (like already mentioned above) - i.e. background, game objects, foreground, gui AND parallel the usage of sprites i.e. winter, summer, day, night, boss fight...
Sometimes it makes sense to duplicate sprites to avoid loading a texture only to draw one sprite from it.
 

TsukaYuriko

☄️
Forum Staff
Moderator
Since organization practices have been mentioned already, here are some general pointers about what's behind the technical terms and where the pitfalls are.

Should I keep my texture pages at 2000x2000 or make them 4000x4000 ?
Bigger texture page size leads to less compatibility, as older devices may not be able to handle them properly. This is mainly determined by the GPU. It's up to you, a bit of research regarding what supports which size and, in the best case, testing on actual target hardware, to determine where you should draw the line.

I final goal is my game to run fine on low end 4GB RAM integrated Intel video card.
Probably the most crucial thing to be aware of here is that 4GB RAM and an integrated graphics card doesn't mean that you have 4GB of video memory. How much of it is usable depends on the amount of memory that is shared with the graphics card, usually called shared memory for that reason.


Any such memory will need enough space to store your texture page twice while it's being used - once in RAM, once in the shared RAM that's used as VRAM - and that's on top of anything else that's running on your target device, such as the operating system, background services and other running programs.

The process of swapping texture pages in and out of VRAM is what's referred to as a "texture swap". It happens when the graphic you are attempting to draw is not located on the texture page that is currently loaded into VRAM, causing it to be overwritten with the right texture page before the graphic can be drawn. This process takes some time to complete, and it stalls the drawing process until it's completed. Texture swaps by themselves aren't exactly a sign of impending doom, and to a certain extent, they are normal, as it is not always possible to put everything on the same texture page (in which case you would have the lowest possible amount of swaps).

The real concern here are situations where the same texture pages are swapped in and out numerous times during a single frame - like when you have lots of instances of an object which draws multiple sprites, both of which are on different texture pages - this adds a lot of waiting time in between the actual drawing and can lead to performance issues. This is why you should organize texture pages based on roughly when they will be drawn, so that once a texture page is unloaded from VRAM, it won't need to be loaded again for the rest of the frame.


While all other texture pages won't be loaded into VRAM when not in use, they will be loaded into RAM - that is, unless you specifically load and unload them dynamically. Great care should be taken with that, however - dynamically loaded graphics take up more memory than static ones, and I doubt that the amount of graphics that could be loaded dynamically (and, therefore, the amount of graphics that would not need to be loaded all the time) would not be sufficient to make this method be worth it, and would actually increase memory usage rather than decreasing it.

Since you're dealing with a 32-bit application here, you're also subject to the 32-bit memory limitations - although I doubt this will make a difference on your hypothetical target machine, as it is more likely to hit the total memory limit of 4GB with all other RAM usage taken into account before it hits the 2GB limit for the application.


Here's an example about texture page organization: Imagine everything that needs to be drawn to your screen as a color-by-number image.

One method to complete it is to pick up a crayon that corresponds to any color, provided that there are tiles left that need to be colored with it, and coloring all corresponding tiles. You first color all "1"s, "3"s and "7"s pink, then all "2"s, "4"s and "6"s purple... and so on.
Another method is starting in the top-left corner, which is a "1". You pick up the pink pencil and color the tile before moving on to the next tile, which is a "2". Therefore, you drop the pink pencil, pick up the purple one and color the tile. You move on to the next tile, which is a "1" again, so you drop the pink pencil, pick up the purple one and color the tile...

Coloring a tile takes a certain amount of time.
Dropping a pencil and picking up another takes a certain amount of time too.

Coloring a tile represents drawing a graphic.
All tiles marked with the same number are drawing instructions to the same graphic located on a specific texture page.
A color is a texture page.
Swapping pencils represents texture swaps.

Finally, imagine the color-by-number image to be a simple chess board pattern - that's a worst-case scenario for method 2 (which stands for unorganized texture pages) and no problem at all for method 1 (which represents organized texture pages). Depending on how long a texture swap takes, method 2 can potentially be multiple times slower than method 1.


I'd say the primary concern should be compatibility - if your game doesn't run on the target device at all, any optimization you perform will be useless. The best way to ensure this is to run it on the target device, or a device with comparable specs. Optimization comes after that, and again, the best way to check whether you have to optimize something is to run it on the target machine. If there is no noticeable lag and the profiler doesn't capture any suspicious performance drains, your time is better spent on further development than on micro-optimization.
 

Zuljaras

Member
Thanks for the advices. For now the game runs ok on the low-end target. But I have to monitor that in the future when I add tons and tons of new graphics.

However I would try and group together my textures for example my player sprites, or a zone in the Castle to its own texture page.

Also How to measure the memory usage properly? Is the task manager usage ok? I mean I run my game and then I use the task manager to see how much MB my game is using when running to have a faint grasp of the load on the machine.
 

TsukaYuriko

☄️
Forum Staff
Moderator
I'll also chime in to say that if you are using Studio 2, I remember one of the devs mention that texture swapping isn't as big of a problem as it was on Studio 1.x
 

DukeSoft

Member
Since 2.x uses the newer DirectX version, texture swaps are much less of an performance impact than on the older GMS1.4 - and I can confirm that :) I have a game with over 300 texture swaps which runs smoothly on a laptop with integrated graphics. It can still be nice to look into making the number smaller though. Its probably better to keep it at 2048x2048 than 4096x4096 - or at least give players an option to scale down for lower end computers. I found out that this (not very well known) function can make _all_ the difference on older machines / integrated graphics: https://docs2.yoyogames.com/source/...ce/drawing/textures/texture_global_scale.html
 

kupo15

Member
Wow, useful function indeed! So I can create my tex pages at my native 4096x size and have an option that will use that function to instead make them loaded in as 2048x instead halving my memory usage and upping my compatibility due to smaller tex page size. I assume this means I can mix match sizes too. Like if my Stage Tex pages are the primary source of potential memory issues, I can halve only that and keep everything else at full 4096 size. Thanks @DukeSoft
 

DukeSoft

Member
@kupo please do keep in mind that your graphics will suffer greatly from this! Its not that its being loaded as 4 2048x2048 textures this way - but it just scales down the entire texture. For example small fonts become unreadable at a 4x scale. But its a good fallback mechanism to keep a game playable on old hardware :)
 

DukeSoft

Member
Also - Antialiasing has a very big impact on VRAM usage (and thus kills integrated video cards) - a game at 1280x720 res using 100mb vram will use about 1.1gb with 8x antialiasing. Make sure you use display_reset(0,0); ( https://docs2.yoyogames.com/source/...ameras and display/display/display_reset.html )

Also, adding *gml_pragma("PNGCrush");* will run PNGCrush over your textures, keeping them smaller in size ( https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/miscellaneous/gml_pragma.html )
 

kupo15

Member
@kupo please do keep in mind that your graphics will suffer greatly from this! Its not that its being loaded as 4 2048x2048 textures this way - but it just scales down the entire texture. For example small fonts become unreadable at a 4x scale. But its a good fallback mechanism to keep a game playable on old hardware :)
Right, for the "2" factor, its the same thing as taking the texture page, shrinking it down to 2048, then I guess it gets loaded in as that smaller size but then gets blown up to stay the same 4096x size for the game to run at the memory of 2048? I did a test and the 2 factor did reduce it to at least half the memory.

I understand the reduction of quality too, but this in fact isn't a problem because this function gives me more flexibility and better results. My game is being built at 1080 and lots of assets are at full size. However, some things in my stage do not need to be full size like the Skybox in the distance. It would be like 6000x2000 if that were the case. I currently have manually shrunk that down 4x inside the IDE to save memory and blew it back up 4x in game and it still looks great. The same thing with other background layers except those are 2x instead.

With this function, instead of locking those assets in at the lower resolution manually, I can now load them in their full size and use that function to shrink them instead for more flexibility. If someone has a super computer and can handle all my textures at full strength they can do that. If they can't, they can turn on the function to reduce the memory to where it was when I manually did it and it'll still look just as good. In fact, I did one more test with quality to compare me manually shrinking an asset in the IDE then blowing it up with image_scale vs shrinking it at full size using that code and the results of the quality were actually better using texture_global_scale!

So that code gives me better flexibility and better quality than what I have been doing. Unless I'm mistaken, I guess I could theoretically build the game at double 1080, throw that function to cut it in half and still use the same memory as 1080 game and still have the flexibility to have the game easily display the higher res textures in the future when technology gets better. Sounds like a great addition to me, right? :D

Also - Antialiasing has a very big impact on VRAM usage (and thus kills integrated video cards) - a game at 1280x720 res using 100mb vram will use about 1.1gb with 8x antialiasing. Make sure you use display_reset(0,0); ( https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/cameras and display/display/display_reset.html )

Also, adding *gml_pragma("PNGCrush");* will run PNGCrush over your textures, keeping them smaller in size ( https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/miscellaneous/gml_pragma.html )
Wow, really? Did not know about AA doing that. I'll have to see what my current AA settings are at. Because I'm using HD assets and have a zoomable view, I feel like AA is a necessity to avoid jaggies during the constant scaling process. Another method maybe since my assets are already big is to have them be built even bigger and scale them down? I heard highest resolution scaled down is the best form of AA there is instead of using AA?

Does pngCrush reduce the VRAM size? But at the expense of some quality? I'll have to check this out to see what it does to my assets
 
Last edited:

DukeSoft

Member
AA is an "after" effect. Since you're talking a lot about textures and stuff I imagine your game is 3D-ish? The AA might really improve the overall image, because it fixes "jiggies" on rendered models. In case of a 2D game, linear texture interpolation will probably have a better effect on the display than AA, and is _much_ cheaper.

In my 2D game, the AA does almost nothing visually, and the linear texture interpolation makes a huge difference. The AA does however use up a lot of VRAM.

The PNGCrush does _not_ reduce VRAM size - only the texturepage size on disk. It doesn't do anything to VRAM and actually increases loading times (because better compression -> more CPU to unpack), but thats hardly noticable.

When the game runs, it loads the texture from disk into VRAM - where its represented as a 32-bit bitmap (RGBA) - so a 128x128 PNG thats 0.12kb in size, and a 128x128PNG thats 29mb in size, will both be 64kb VRAM. a 4096x4096 texture can be 1mb on disk, but will be 65MB in VRAM.

If you use the global scale, GM will load the 4096x4096 file as a 2048x2048 bitmap (essentially skipping every odd / even pixel), making it use only 16mb VRAM.

I don't think you can manually set a scale _per_ texture page, but that would be an awesome feature since it will indeed allow you to build your game with 8192x8192 textures, and load them in as 4k, 2k, 1k, 512 etc. based on the users' preferences. If you can't do it per texture page that would mean you'd also render your fonts and all on those textures.. And even a 32px wide font becomes unreadable if its scaled down 4 times.

Also, in case of 3D games - you should look into setting the mipmaps with the new GPU functions - this will increase the quality of far away rendered objects a LOT, and it migth even solve some "jiggies" because of texture resolutions on big distances ( https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/drawing/mipmapping/index.html )
 

kupo15

Member
Thanks for the info @DukeSoft!

Nope, my game is 2d, (check the link in my sig). Now that you mention it, I remember doing AA and interpolation tests too and noticing that AA doesn't do much of anything so I don't think I use it. So I don't have to worry about AA anymore.

That's what I thought about pngcrush. Doesn't sound like something super useful really with games well over 3GB in size these days and HD sizes massive. I doubt my game will even get that big anyway. Unless this compressed size on disk also factors a little bit towards RAM in some way to not get close to that 32bit application memory cap. Then I can see that being useful!

And yes, you in fact can assign texture_global_scale per texture page. As long as that texture page is not already prefetched you can change the scale of it before you do. If it is, simply flush that texpage, set the scale and prefetch again. I tested this yesterday and was able to make my character texture pages half scale while still keeping my text super sharp at full scale. Its looking extremely promising so far and seems that you can create 8k textures and use that function to scale it down to your desired res. I intend on using this to put my Stage images at full res in the IDE, scale the Skybox down 4x, far-ish parallax layers 2x while keeping everything in the foreground full res.

Is there a downside to creating massive textures? For the extreme example, 8K size and downscaling them to 2K? Is there a limit where too big sprites start hurting image quality because you are downscaling too far for HD assets? So far the only drawback from a 4x downscale through my testing was gaps in stitching together tiles/backgrounds. Black lines appeared from bleeding. I think it can be fixed by extending the texture pixels further than I currently have but I haven't tested that yet

I'm also not sure, but using the new texture_debug code, it seems that even if you scale down a texture page, it still gets loaded in as the original size unless the debug information doesn't take into account this downscaling. If so, then using 8K tex pages and scaling down might not be good compatibility wise if GPUs can't work with 8K sizes. What you said about the tex page being scaled down to a new dimension seems correct, how else would GM reduce memory size if it didn't?
 
Last edited:
Top