GameMaker function sprite_add_from_surface() creates a texture page for each subimage added

F

Finn

Guest
When I create a sprite from a surface and then add subimages from the surface they appear in the texture pages as individual texture pages - one complete texture page for each subimage of the sprite added (see screenshots below). Is this intended? Seems like a performance nightmare.

What might be happening (not sure) is that GMS create a texture page every time a sprite_create_from_surface or sprite_add_from_surface gets called as it cant alter the previously created ones. This seems very inefficient though.

DETAILS:
The test sprite I want to create with the code should show the subimages "1", "2", "3", "4", ..., "8" - instead they appear each as individual texture pages and each multiple times.

The actual complete sprite I am trying to create does _NOT_ appear in any of the texture pages.

Any ideas why this would happen? My understanding is that GMS will create one new texture page for the sprite and its subimages.

Btw: In the example code of the function sprite_add_from_surface() is a typo. It should read "_i*32" as an argument where it calls the function.

EDIT: I forgot to say the sprite and its subimages work in game as intended. The 29 redundant texture pages for a single sprite seem like a performance nightmare though and not as it was intended.




I M A G E S
  • Code:
  • Sprite I want to create

 
Last edited by a moderator:
I'm going through this too, and I can't find an efficient solution.

I am working on a game that uses external files straight from a server. I use the sprite_replace function but the same thing happens, l GMS2 creates a texture for each frame of a sprite.

The solution I made is to create a 1x1px "empty sprite" and replace it with the sprite IDE. This works, but all sprites in the IDE are not excluded from RAM

My game is currently running with 680 MB RAM and 1980 texture pages !!!!
 
F

Finn

Guest
Funny, I have an empty sprite as well but the real problem are the texture pages and batch breaks and their impact on performance.
What you can do in some cases is draw all the sprites together on one surface and then draw into a big sprite afterwards; then use sprt_draw_part_ext() for drawing.

You also need to check that you delete the sprites you make carefully; otherwise it creates a ton of texture pages every time and keeps the old ones on top.

In my case the problem was how to then rotate such sprites; Matharoo gave me two suggestions for workarounds: a) use a shader or b) use matrix_set functions for rotation

var _mat = matrix_build(x, y, 0, 0, 0, image_angle, image_xscale, image_yscale, 1);
draw_sprite_part(my_sprite, my_sub_img, px, py, pw, ph, 0, 0);

If you make any progress let me know; I will do the same! :)

BTW: This information should be on the help page of the function. It is such a potential threat for performance and not even mentioned there at all. Developers should straight up know that a separate texture page is added for each sprite and not have to find out later when things break.
 

rIKmAN

Member
BTW: This information should be on the help page of the function. It is such a potential threat for performance and not even mentioned there at all. Developers should straight up know that a separate texture page is added for each sprite and not have to find out later when things break.
It is mentioned on the entry for sprite_add():
It should be noted that the memory used when adding a sprite in this way will be larger than you may expect. This is because GameMaker Studio 2 will store the sprite as a texture page and it will also be stored in GPU memory, so the total memory will be larger than would be expected for an image file of the same sprite.
File a bug report and choose the manual as the category and suggest it's added to other affected sprite_* functions too, although sprite_add_from_surface() is obviously a variation / extension of sprite_add() so maybe it's intentional it's only mentioned on the base function page as you would be expected to use / read that before using the from_surface variant.

You could also take at look at something like Braffolks custom sprite framework for use / ideas which seems to use a method similar to that you suggested. It's for 1.4 but should work in 2.x with some code cleaning / tweaks as the sprite functions are pretty much the same.

I didn't realise every frame of a sprite took a new texture page, I assumed it was every sprite (and all included frames) as even each sprite seems wasteful but that's even worse.
 

Joh

Member
I'm going through this too, and I can't find an efficient solution.

I am working on a game that uses external files straight from a server. I use the sprite_replace function but the same thing happens, l GMS2 creates a texture for each frame of a sprite.

The solution I made is to create a 1x1px "empty sprite" and replace it with the sprite IDE. This works, but all sprites in the IDE are not excluded from RAM

My game is currently running with 680 MB RAM and 1980 texture pages !!!!
Hey, I use that 1x1 sprite too with replace. I thought it was a crazy "workaround" I came up with after encountering the whole one texture per sprite with no way to get around it! Good to see others with the same solution! I also thought of the build one megasprite and keep track of "sprites" locations on the essentially hand-made texture page. (like Finn mentioned) but then every draw_sprite call is a complicated mess, thus you might as well use the custom sprite framework, which seemed like that process pre-implemented. but I felt that was over-kill for my needs.

a thing that bugged me out, and I dont think that was the case in older GM versions, sprites Ids don't get recycled? Its why I used replace with empty sprite rather than delete and re-add.
I don't think theres a difference between the two (delete & re-add feels cleaner) but I'm not comfortable with continuously incrementing sprite indices. Not sure what could go wrong, but it feels like a memory leak.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I didn't realise every frame of a sprite took a new texture page, I assumed it was every sprite (and all included frames) as even each sprite seems wasteful but that's even worse.
For this to be any other way, GMS2 would need to include the texture packer code with all executables and then run it every time a new sprite or sprite sub-image is added.

File a bug report and choose the manual as the category and suggest it's added to other affected sprite_* functions too
Please do this, as it is an omission that should be fixed.

I don't think theres a difference between the two (delete & re-add feels cleaner) but I'm not comfortable with continuously incrementing sprite indices. Not sure what could go wrong, but it feels like a memory leak.
It's a number. It goes up, but has no effect on memory and if that number ever goes above the 32bit int value ( 2,147,483,647!!!) I'm pretty sure it'll go back to 0 again, although I haven't even attempted testing it... :p
 

TheouAegis

Member
Are you flushing the texture pages too? I don't know if deleting custom sprites affects texture page count or not, but it's something to keep in mind too.
 
Hey, I use that 1x1 sprite too with replace. I thought it was a crazy "workaround" I came up with after encountering the whole one texture per sprite with no way to get around it! Good to see others with the same solution! I also thought of the build one megasprite and keep track of "sprites" locations on the essentially hand-made texture page. (like Finn mentioned) but then every draw_sprite call is a complicated mess, thus you might as well use the custom sprite framework, which seemed like that process pre-implemented. but I felt that was over-kill for my needs.

a thing that bugged me out, and I dont think that was the case in older GM versions, sprites Ids don't get recycled? Its why I used replace with empty sprite rather than delete and re-add.
I don't think theres a difference between the two (delete & re-add feels cleaner) but I'm not comfortable with continuously incrementing sprite indices. Not sure what could go wrong, but it feels like a memory leak.


Me too! Only geniuses think of this solution! :D
1x1 sprite works! The RAM actually goes down.

In my case I create the empty sprite in the IDE and use:
sprite_replace(sprite_ide, "sprite_null.png", 0,0,0,0,0);

and then on the load screen:
sprite_replace(sprite_ide, "sp_player_animation_strip8.png", 8,0,0,30,20);

I created a load system in my game loading only what I want at each moment, works great !! ^^

If there was a magic way to get over this texture_page question!


One thing I recently noticed is that if you use sprite_replace on a sprite that is in the IDE, it does not clear RAM. So I only use it for multi-frame sprite.


sprite_flush()
draw_texture_flush()

it seems this does not work for me = (
 

rIKmAN

Member
For this to be any other way, GMS2 would need to include the texture packer code with all executables and then run it every time a new sprite or sprite sub-image is added.
Yeah that makes sense, and I'm not sure what the solution may be but it's still pretty nasty to have a new texture page per frame.
 
Top