Lightmaps using twice as much memory as expected

I have 40 lightmaps at 1024x1024. Each one is compressed to pvr 4, without mip maps, which results in there being exactly 20 mb of lightmap data.

However once I load it on the iPad, I found including all of these lightmaps adds 40 mb of memory usage to my app! Regularly its 36 mb in use, I add all the lightmaps, it then is 76 mb in usage. Seems like the lightmaps are being stored twice or something?

are they marked for get pixel - set pixel? (shouldn’t be but who knows?) cause in that case they are twice in RAM, once in RAM and once in VRAM which on mobiles is the same basically from the “losing ram” PoV

Also is calculating the lightmap the only thing you did?
so all the rest including settings for static batching and alike are equal?

I compressed them to PVR via commandline utility and then dropped the pvr’s into unity. Do they come in marked for get set like that?

I am trying to get at the lightmap textures by this:
LightmapSettings.lightmaps[1].lightmapNear = testTex2D;

but that seems to have no effect, it doesn’t change the loaded lightmap

Where is this setting at? "pixel - set pixel? How do I set that?

The setting is only exposed for advanced textures
Unsure to what it defaults for the rest, but a simple usage of SetPixel + Apply will tell you if they are not marked for it by throwing an error

@eem: In that case you pretty surely forgot the 33% overhead of mipmaps thats present whenever a texture is not set to not use them

I replaced all my commandline generated .pvr’s with the original PNG files and let unity handle the pvr conversion with the ‘lightmap’ flag checked in the advanced settings. And it comes in now with an expected 20 mb of memory usage… So maybe get/set wasn’t turned off.

What would be the best way to turn get/set off on .pvr files you drop into unity? Is there somewhere to disable that before Unity even loads the scene?

Also, are you sure about this 33% overhead without using mip maps? Because I started out with all my lightmaps having mip maps, checked memory usage and it was around like 65. Then I disabled all mip maps for my lightmaps and then checked memory usage and its now at 56. So disabling mip maps for sure reduced memory usage.

If you don’t use mipmaps then its no overhead naturally.

As for disabling get / set: Set the texture type to advanced, there the checkbox will be present

Well for .pvr files you drop into unity, you don’t get an advanced tab. You don’t get any settings to set… So I assume you do it through code but, whats the best place to do that?

My first thought would be do it under Start() but that seems like a bad idea because youd prolly want to disable this before the app even loads…

@ eem
How detailed are your lightmaps, how big is your scenes?? My scenes are a good size and I average about 1-3 MB total (compressed and Max size set to 512) per scene ( 4-8 lightmaps) and the quality is still very good. Are you overdoing it??

This for an archviz project, so getting photoreal lighting is most important.

The lightmaps are baked out of mental ray and I’ve actually really condensed this scene to fit on 40 1024x1024 images.

you can do that from editor script
you need this

I disabled all of the isReadable flags and the .pvr files that I dropped into Unity still are using twice as much memory as they should.

Im running a script in Awake that does this:

		Texture2D tx2d;
		for (int i = 0; i < lightmapMaterials.Length; i++)
		{

			tx2d = (Texture2D)lightmapMaterials[i].mainTexture;
			tx2d.Apply(false,true);

		}	
	
		for (int i = 0; i < LightmapSettings.lightmaps.Length; i++)
		{
			if (LightmapSettings.lightmaps[i].lightmapNear != null)
				LightmapSettings.lightmaps[i].lightmapNear.Apply(false,true);
			
			if (LightmapSettings.lightmaps[i].lightmapFar != null)			
				LightmapSettings.lightmaps[i].lightmapFar.Apply(false,true);
		}

and I tried running a script from the editor that does this:

    static void DisableReadablePVR(bool enabled) {
   
        Object[] textures = GetSelectedTextures();
		Debug.Log("Got " + textures.Length + " textures");
        Selection.objects = new Object[0];
        foreach (Texture2D texture in textures)  {

	texture.Apply(false, true);
        }
    }

it is reporting that it got all selected textures via GetSelectedTextures();

And I am calling Resources.UnloadUnusedAssets on Awake.

But still, all .pvr files dropped into Unity are using up twice as much memory as they should!

help please, I really need to get this working. Is there another way to do this?

Since I am dropping .pvr files into unity, there is no instances of TextureImporter, so I can’t use this function Unity - Scripting API: TextureImporter.isReadable

The only other function I knew of to disable the isreadable flag is via Texture2D.Apply but that doesn’t seem to work? Am I doing something wrong? Is there another reason why textures would be stored in memory twice?

Oh right. Your double use of not, “is not set to not use them” confused me. Thought you were saying mips added 33% overhead.

Ok after disabling the isReadable flag every which way I could possibly found, I discovered doing so in the OnPostProcessTexture function makes it actually result in using the proper memory amount on the ipad. Here is the code:

using UnityEngine;
using UnityEditor;

public class TextureProcessor : AssetPostprocessor
{
	
	
	void OnPostprocessTexture(Texture2D texture)
    {
	
		if (assetPath.IndexOf ("PVR") == -1)
			return;
		
		Debug.Log("disabling isReadable on " + assetPath);
		
		texture.Apply(false, true);
		
	}

}

what that does is look for the capitalized letters PVR in your asset path. So put all of your PVR compressed textures into a folder suffixed by PVR, Assets/TexturesPVR/texture, and then it will automatically disable the isreadable on all PVR files coming into unity from that folder

This doesn’t seem to be working for us :frowning:

Just adding a small detail:
The script has to be placed inside the ‘Editor’ folder in the Assets.
Then, it will work only when assets are imported. So, if you already have your pvr textures in the project, re-import them once and watch the console for the results

Thank you very much eem! :slight_smile:

What’s the story with this, Alexey? I tried this (because I hadn’t read enough of what eem said):

if (System.IO.Path.GetExtension(assetPath) == ".pvr")
	(assetImporter as TextureImporter).isReadable = false;

But that doesn’t work, because, as I discovered, the assetImporter is a PVRImporter, not a TextureImporter. So, I tried this:

var pvrImporter = assetImporter as PVRImporter;
if (pvrImporter) pvrImporter.isReadable = false;

But that just gave me an error, as we’re not allowed to directly use UnityEngine.PVRImporter. Come on, now. :stuck_out_tongue: I want feedback about the readability.

You shouldn’t need to mark them as not readable cause they are never writable on the device anyway (texture compression is only available on desktop and only available for DXT within the client)

You’re talking about writing when the operative word is reading!

Theoretically.
Practically there is only one setting and thats ‘Get / Set Pixel’ or basically ‘is changeable’ and for PVR this is force defined as false, independent if you want that or not.
Thats also why it has an own asset importer, why the asset importer is not accessable (as there is nothing you can change if you use pvr - see the different threads on why mipmap stuff and other things are ignored when you use pvr images) and why it has an own texture import inspector that does not even expose the readable flag inside of unity if you check it.
In 3.4 the inspector was slightly bugged and pretended that you can change stuff, 3.5 b6 (dev preview) finally shows you a blank inspector beside the preview

Basically if you use PVR then the PVR is what you have and what you will use, point.
Its the only format where Unity does not give you the possibility to change anything. (the only other limited format is PSD where you get no activation / deactivation control over the layers upon flat baking on import inside of unity)