- Home /
Does Unity load in memory textures that are target of public variables ? (iOS)
Hey !
I'm having performance issues on my iOS game and one of the questions I have to solve it is this :
I have some script that have public variables
public Texture tex;
Where I drop a texture in the Inspector view (texture are stored in the Assets/ folder)
When I press play I have a script that decide which texture to assign to the object material based on what's happening in the game.
I was wondering if Unity load all the textures in the public variables when the game starts or just load the texture when they are applied on a Material at runtime.
renderer.sharedMaterial.mainTexture = tex;
If someone has an idea or a related article that I can read ?
Many thanks.
Are you getting slow load times, or spikes when switching textures?
Not so sure about iOS, but in general there's "disk," regular memory and texture memory. As with anything else, textures are likely on disk (really flash memory) until you 1st touch them. They go into texture memory when Unity says they should. That's probably when you put them on a $$anonymous$$aterial, or when you use them. This is the "UsedTextures" stat, I think. Then they stay in texture memory until it gets too crowded and they are the last recently used.
I guess for a test, you could create 1000 materials, generate 1000 random textures, and assign them all, but not use the materials for anything. See if/when you get a spike.
The "context" I'm talking about is using 3 different textures for the different screen sizes of mobile devices (big texture for retina, small for old devices). At the scene start I'm swapping to whatever is the best texture based on what the resolution of the device is. So I have an script with an array for all graphic object in the scene where the 3 textures are setup. Then the script decide to assign the right texture to the object material. And I have a really long loading time between scenes. So I'm guessing all textures are loaded on scene start.
The experimentation you describe is interesting. I'm gonna go that way to understand the problem. Thanks !
Although i can't say for sure about Unity, most game engines have traditionally preloaded all assets for a level in rode to avoid load pauses.
$$anonymous$$y guess is that yes, if you reference it in the editor it gets loaded upfront. if you don't want to do that then you should use the Resources load calls at run-time to fetch assets.
Answer by supernat · Jun 03, 2014 at 04:05 PM
No, Unity does not load the texture until the texture is applied to a material that is on an object in the scene. It wouldn't make sense to load everything that was referenced, because you may have 20 variants for your main character for instance, and video memory is already at a premium, especially on mobile devices. Another example is one game object that has 20 references for the sky cube map but changes the camera's sky to only 1 of them based on the level loaded. The only memory used when you reference the texture above is to save information about the texture (such as the location, size, etc). Then when you assign it to a material, it is loaded into video memory.
If you are curious, create a cube in an empty scene with a script that references 10 very large textures, and set the OnMouseDown() to override the cube's renderer material with a new texture each time. You can see the VRAM usage (among others) from the Stats window on the Game view, and it will change accordingly.
For your specific problem, if you are assigning the material in the editor to for instance the highest resolution one you have, then your game/app will start up, load all of the high res textures, then unload them and replace them with the proper resolution. So just make sure all of your textures are null as assigned to the game object in the editor (you might be able to add an if (!Application.IsEditor) type statement to the Awake method of the game object to dereference the mainTexture of your objects. That way you can still edit and run/test in the Unity editor, but the mainTexture will (hopefully, can't say for sure) be null before you do the big swap over for the device-specific textures. Like:
void Awake() {
if (!Application.isEditor)
renderer.sharedMaterial.mainTexture = null;
}
This brings up another point. Make sure you are setting the sharedMaterial and not the material, because then every game object in your scene would get a new material that might cause a slowdown.
It depends on what you are trying to maximize/$$anonymous$$imize.
If you have the memory and are load-time sensitive then it would make sense to preload any texture that might get dynamically used.
Not preloading could cause a delay or hiccup in gameplay, as IO is often one of the slowest operations on a system.
When we used to build our own engines for games we almost always loaded all assets a level might need upfront.
Yes, this is true (good points), but by default, an engine like Unity which is made for general public consumption should only assume less memory usage first and let the developer take care of pooling objects and preloading stuff. I'm not sure if/how you would preload textures, so maybe it would make a nice option somewhere if that's not possible. I agree with you though if building the engine for your own purpose, you have better control over such design.
The first optimization I made was to remove all texture assigned to the objects material. Seems that there wasn't much change in scene loading time but I might have forgotten some texture assignation here and there.
Then I removed all reference to textures in public variable and loaded everything at runtime throught Resources.Load() and it worked better. Not perfect but now the game doesn't crash on scene load on 3GS.
I didn't had time to make sure that just removing texture from material was enought or not. I'm guessing it was enought but I went for the complete removal right away (time constraint).
Thanks for the feedback !
@ABerlemont, so you discovered that removing the references to textures in your scripts increased load performance? I would be curious if Unity is loading textures when they are referenced into video memory or maybe just system memory. The tests I did showed no video memory usage. Now I'm curious, because my answer could be wrong, and to Jeff's point, maybe they are loading the textures (which I still think is bad for a general use engine, but that's just my opinion), and I did my test wrong. What version of Unity are you using? and is it Pro?
4.3.2 pro
Like I said. I didn't had time to test things to be sure. I just went for the Resources.Load() fix. Your hypothesis is still valid.
Did you try in the editor or on device with the profiler ? Unity might manage texture differently than the device itself.