Texture Size in Memory

Member
Posts: 241
Joined: 2008.07
Post: #1
Hey guys, I'm about to start a texture manager. I would like it to accurately track the amount of memory being used by textures. This would be greatly helpful to keep memory usage down and help identify if memory becomes an issue due to textures. Since textures are the most memory hungry thing in a game usually, I decided it would be a very important feature.

Anyway, what I wanted to ask is if anyone knows how to determine exactly how much memory is being used by a PNG file when it's loaded into RAM. I know it's not the same as it is on disk.

The CGBitmapContext documentation indicates that it is:

bytes per row * height. This makes sense to me. It further indicates that bytes per row is defined as width * 4 because of 8 bits per component (1 byte) and 4 components (RGBA). Okay, simple enough but doesn't the iPhone premultiply the alpha or something like that? In that case, would it be

(width*3*height) bytes?

Thanks!
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
Premultiplication doesn't change the number of channels (and no the "iPhone" doesn't, but CoreGraphics might).

I have to say, I don't really see the usefulness. What do you plan on doing if you discover you're using "too much" memory on textures? It might be a useful statistic during development, to know how much memory the textures for a given scene occupy, I suppose...
Quote this message in a reply
Member
Posts: 241
Joined: 2008.07
Post: #3
Exactly, it's a useful statistic during development. We may want to limit the amount of texture memory we use to 10MB for example and when we start getting close to that mark, it will be a cause for concern, so we will then consider lower resolution textures before it becomes a big problem.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #4
Yes, using CG on iPhone (as in, the popular Texture2D class) does indeed premultiply the alpha -- not that that has anything to do with memory usage. I was going to move to LibPNG on iPhone, but apparently Apple mucks up PNG images when creating the app bundle for some kind of optimization. Haven't been able to figure out how to get past that yet, so I'm stuck with CG (and its premultiplied alpha) on iPhone for now.

Figuring out exactly how much you're using with any given texture upload is kind of tricky, since how it is ultimately stored by the GL is up to the GL. I usually figure an uncompressed 32 bit image (with alpha) will be 4 * width * height bytes. That's what a PNG including alpha will probably be once you load it.

But to be more accurate, what I've been doing so far is watching memory usage in Instruments. There's a catch though: UIImage caches its loaded images. Because of that, I switched to loading PNGs directly with CGImageCreateWithPNGDataProvider so that I can release it as soon as it's loaded, which seems to give more reasonable usage estimates. That saved a boatload of RAM up front. Note that UIImage will automatically flush cached images when a memory warning is received, but of course, that doesn't help if you're trying to measure needed usage.

16 bit images seem okay when you can use them, but the best advice I could offer is to use PVRTC images wherever you can. PVRTC offers un-freaking-believable memory savings. Doesn't seem to work well with images that require alpha, but seems fine for animated images where you can't see artifacts because they're flipping through frames so fast, but it is *crazy* awesome for static images that don't require alpha. I mean, we're talking like 1/8 the size of uncompressed, or less, in memory == wowzerz!
Quote this message in a reply
Member
Posts: 241
Joined: 2008.07
Post: #5
nice

I also asked the same question at the apple developer forums, you can read the replies here:

https://devforums.apple.com/thread/2310?tstart=0
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #6
Yea, Xcode automatically premultiplies PNGs (and swaps the R and B channels) for use on the iPhone. You can read about it here. It doesn't remove the alpha channel though, so it's still 32-bit pixels.

This also has a side-effect in that it apparently premultiplies with black, creating a nasty black halo around sprites drawn with OGL ES. Still haven't figured that one out yet. Sad

AnotherJake Wrote:There's a catch though: UIImage caches its loaded images. Because of that, I switched to loading PNGs directly with CGImageCreateWithPNGDataProvider so that I can release it as soon as it's loaded, which seems to give more reasonable usage estimates. That saved a boatload of RAM up front. Note that UIImage will automatically flush cached images when a memory warning is received, but of course, that doesn't help if you're trying to measure needed usage.

Apparently [UIImage imageNamed:] caches the image it loads, but [UIImage imageWithContentsOfFile:] doesn't. At least if other forums can be believed. I haven't gotten a chance to verify that 100% yet. I'll have to compare it with CGImageCreateWithPNGDataProvider to see if there's a difference.
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #7
To avoid the halo, just blend the image as if it has been pre-multiplied (because it has).
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

iPhone or not, I always use premultiplied alpha when drawing sprites as it avoids drawing objects with white halos. Wink

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #8
Bachus Wrote:Apparently [UIImage imageNamed:] caches the image it loads, but [UIImage imageWithContentsOfFile:] doesn't. At least if other forums can be believed. I haven't gotten a chance to verify that 100% yet. I'll have to compare it with CGImageCreateWithPNGDataProvider to see if there's a difference.

Great find! I just tried it out, and it does not appear to cache the image. That's great because that makes it a very simple switch to use it and not have to modify the Texture2D class. One can do something like:

Code:
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"myImage" ofType:@"png"]]

instead of

Code:
[UIImage imageNamed:@"myImage.png"]

for some easy, free memory up-front (before a memory warning would have flushed it anyway that is). Smile
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #9
Skorche Wrote:To avoid the halo, just blend the image as if it has been pre-multiplied (because it has).
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

iPhone or not, I always use premultiplied alpha when drawing sprites as it avoids drawing objects with white halos. Wink

*smacks forehead* That fixed it. Thanks.
Quote this message in a reply
Member
Posts: 241
Joined: 2008.07
Post: #10
AnotherJake Wrote:
Code:
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"myImage" ofType:@"png"]]

instead of

Code:
[UIImage imageNamed:@"myImage.png"]

I just wanted to say thanks because I did a simple swap

Code:
    newImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileName ofType:nil]].CGImage;
    //newImage = [UIImage imageNamed:fileName].CGImage;

With the commented out code as the loading code, ObjectAlloc was showing over 50MB of memory used, with the new line of code, it dropped to about 28MB. That's a HUGE difference! Thanks a bunch!!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Small size texture problem kendric 3 2,957 Mar 25, 2009 06:40 PM
Last Post: kendric