I am curious as to what the expected size in memory would be for a simple scene with a 3MB model loaded in using the ColladaLoader.js. (The model was initially a sketchup file, converted to .dae)
Currently when I load in my 3MB .dae model file into the scene & profile by taking a heap snapshot, my scene is at 118MB! (The model is the only thing in the scene.)
I believe a memory leak is the culprit. But I also can't find any information on what I should expect the size to be. I read Collada files are expensive, bandwidth-wise, but can someone give me a realistic example of what memory usage to expect?
(I'm using three.js r69)
It's because the ColladaLoader convert the geometry into an Array, 3MB of Informations is a huge Array. I got 6 100KB Models in my Scene, but the Head Snapshot give a size of 31MB.
Related
This question's kind of a 4-parter:
Is it true that all BitmapData is immediately cached to the GPU as soon as it's created (even if it's never applied to a Bitmap or added to stage?)
Does this still happen if the GPU texture buffer is already full? Bonus points: if so, what's the preferential swap method the GPU chooses to select which textures to remove from memory?
If (1), then does setting the width/height of any BitmapData uncache it and/or does replacing its pixels therefore upload the new pixels to the same memory address on the GPU? Bonus: What if the size changes?
To bring this all together, would a hybrid class that extends BitmapData but stores its actual data in a ByteArray be able to use setPixels/getPixels on itself to control upload/download from the GPU as necessary, to buffer a large number of bitmaps? Bonus: Would speed improve for actually placing them in Bitmaps if the instances of this class were static?
Here are some answers
No. In AIR, you manually upload bitmaps to GPU and have control WHEN to do it
As far as I've reached, if the buffer is full, you simply get an error for it - the GPU cannot make a choice what do to. Removing a random texture won't be nice if it's important to you, right? :)
You can check for example Starling and how it uploads textures to GPU. Once you force it to do so, it doesn't care what you do with the bitmap. It's like making a photo image of an object so that you can just show it instead of explaining it with words. It won't matter if you change the object, the photo will be still the same.
Simplified answer: no. Again - it's best to check out how textures are created and how you upload stuff to GPU.
I'm having a performance issue regarding Apple Spritekit Framework.
I use the method preloadTextureAtlases:withCompletionHandler: of SKTextureAtlas to make sure all my textures are loaded before the game really starts.
Yet when the first texture of this atlas (whatever it is) is added to the scene as a child I got a small lag, like if the texture wasn't loaded. It only happens the first time.
I tried real hard to debug this and to find the reason but I couldn't find it. Looking with Instrument and the Time Profiler I got this
Which seems strange since my texture atlas contains all the allocated textures (and they are still allocated). Why does it call a load method ? Maybe it's something related to OpenGL like the texture binding.
I'm sure this correspond to the frame where my object is allocated (see the spike on the right). Nothing else is allocated or in motion here.
I'm really stuck on this and any help would be deeply appreciated.
Thanks for your time.
I have been searching these threads and other sites but have not come across a way to do this both efficiently and memory friendly. And so, here is my story:
My IOS (iPad) app uses sprite sheets (a large image, such as 2k x 2k at 16 bpp, which is composed of many smaller sprites). I have created a sprite atlas class which manages these sheets, handle sprite animations, and other features.
The idea (in the load method) is to load in the sheet from the file system, split it apart into UIImages (one per sprite) using CGImageCreateWithImageInRect, and then dispose of the loaded sheet. Seems simple enough.
Note that the sheet is loaded into a UIImage by initWithContentsOfFile or imageNamed (more on that below).
The desire is to save file memory by using sprite sheets, and then save runtime memory by only retaining the actual sprites themselves as UIImages. In my experiments thus far this is what I find happening:
If I use initWithContentsOfFile I see (from Instruments) that it appears to do a file open, fstat64, and close for the file for EACH sprite in it. This takes an horrendous amount of time to load all the sprites. It actually seems to load the entire sheet, grab one sprite, close the sheet, then load the entire sheet again for the next sprite, until they are all created. Also it appears to consume lots of memory (proven by the "received memory warning" after just the second sheet loaded, as well as by Instruments allocations).
Next I tried imageNamed (which caches the sheet). The file loading occurs once and so it is MUCH faster. All seems good and in fact and I can go until many sheets are loaded. But eventually the dreaded "received memory warning" appears... and a few seconds later the app crashes. It appears to be the case that the cached image (even though the pointer is set to null after pulling out the sprites) never goes away. I have read several posts that also state this seems to be its behavior (although other posts say other things, so that is not conclusive - does anyone know definitively?).
And so it appears that neither method is what is needed. What I want is to load the file, pull out each sprite into its own UIImage, then have the UIImage for the big sheet file released completely.
I have read one site that talked about using the initWithContentsOfFile approach to set up their own caching system (rather than trust the IOS plan with imageNamed) so they can release the image when desired. However, I don't think they had sprite sheets in mind.
And so, I turn this over to the experts out there to see if there are some ideas on how to get both fast load times AND use minimal memory.
[and yes, I know that IOS 7 has SpriteKit. But this needs to also work on IOS 6.x.]
One interesting data point is that on an original iPad the imageNamed version actually works fine with no "received memory warning". It might have been IOS 5.x. But the app will crash on the iPad 2 device.
I am not including code here because what I am after is an understanding of the mechanics involved with how memory is used with these functions related to image handling.
And while I am at it, can someone please clarify this point:
True or False: When using CGImageCreateWithImageInRect, what it does is actually creates from new memory a bitmap the size of the rectangle specified and then COPIES from the original UIImage the pixels into this new memory (as opposed to setting up the bitmap format and having a pointer point into the original UIImage's pixel data). I think this is True, but want verification.
Thanks!
I have an iOS opengl es 2.0 app that needs to use a TON of large textures. Ideally 4096x4096. I have a struct array that contains all the info about the texture, and as I need to use each one I glGenTextures a new texture id and load the image there, free up the uiimage, etc. That all works great.
My app uses a bunch of textures for UI, image processing, etc. About 4-5 of the 15 I'm using for all of that are 4k x 4k. Rest are smaller. And then these load-as-needed textures are also 4k.
On loading about the 4th-5th of those the app crashes HARD. No console or debug. Just quits to the springboard in the middle of trying to load the next texture.
I don't have a memory leak - I ran instruments. I'm using ARC. I can post the crash report from the Organizer but it doesn't have much info. Just that my app's rpages was 170504.
I could post the image load code but its the same code I've used on all my apps for years. The new thing is pushing the system that hard and trying to load that many large textures.
Q1: Anyone have experience with using a ton of large textures?
So I resolved to the fact that I'll have to do preview res stuff at 1024x1024 and then final res stuff at 4096. The 1k images are now loading as needed and staying loaded. The 4k images will all be loaded one at a time into the same texture to be used and then move on to the next.
I wrote into my image loader a preview parameter and when set it shrinks the image to fit in 1024 during the load. Now Instead of crashing on the 4th or 5th I can add textures 'all day'. My GUESS is that I could do 16x as many as before. But I only need like 20-30 at a time. (only!) So far I've tried 20 with no memory warnings or crashes.
However.. if the app keeps running, because my textures are loaded at unique texture ids, at some point I would hit that spot where I need to unload one that's no longer needed to load the next one. This is probably very simple, but....
Q2: How do I free up a texture that's at an texture id when I no longer need it?
Q3: Will a memory warning tell me that I need to free up an open gl texture?
Q4: Aren't textures loaded on the PVR chip? Are they or how are they even taking up the phone's memory?
Thanks!
Removing Texture:
You have to use this GL call from the main thread.
glDeleteTextures(1, &_texture);
Memory warning is a general call to the application. It will not give you specific information. It is always better to remove unwanted textures from the memory if they are not needed anymore. Eg: We usually remove textures used in menu when the user moves to the In-Game screens, they are reloaded again when the user navigates back. This is much easier to manage memory than waiting for the system to call memory warning.
When you load PNG image, the data is decompressed and stored raw as array of colors per pixel. A 1K texture will use 4 mb despite of content/colors in the image. PVR is a hardware decompression chip which will decompress realtime when the image is used by the GPU, and the image file size you see is what memory it uses.
I apologize upfront for the long question, with multiple subquestions, but the question is really as stated in the title. All that follows is a detailed breakup of different aspects of the question.
In my universal ios game built using cocos2d, I have four categories of images - I want to determine which of them should go into spritesheets and which are better off loaded as individual images. My current guess is that only character animations that run throughout the game provide value being loaded in memory as spritesheets:
Character animations that run throughout the game play (except
when user is in menus): for these, I assume that having the images
in a spritesheet will reduce runtime memory usage (due to the
padding of individual files to power of two byte boundaries), hence
they are candidates for a spritesheet. Is that correct?
Small images (about 200 of them) of which 0 to 4 are displayed at any
time, picked at random, during game play. For these, I am not sure
if it is worth having all 200 images loaded in memory when only at
most any 4 are used at a time. So it may be better to directly
access them as images. Is that correct?
A few (about 20) small menu elements like buttons that are used only in static menus: since the menu items are used only during menu display, I assume they are not of much value in improving memory access via spritesheets. Is that correct?
A few large images that are used as backgrounds for the menus, the game play scene, etc. Most of these images are as large as the screen resolution. Since the screen resolution is roughly equal to the maximum size of a single image (for example, for ipad retina, 4096 x 4096 image size versus screen size of 2048 x 1536), there isn't much gain in using spritesheets as at most 1 or 2 large images would fit in one spritesheet. Also, since each of these large files is used only in one scene, loading all these large images as spritesheets in memory upfront seems like an unnecessary overhead. Hence, directly access them as spritesheets. Is that correct?
A couple of common related questions:
a) Packing images used across different scenes into the same spritesheet makes us load them into memory even when only a subset of the images is used in that scene. I assume that is a bad idea. Correct?
b) There is a stutter in the game play only on older devices (iPad 1 and iPhone 3gs). Will spritesheets help reduce such stutter?
c) I assume that spritesheets are only going to benefit runtime memory footprint, and not so much the on disk size of the app archive. I noticed, for instance, that a set of files which are 11.8 MB in size, when put in a spritesheet are 11 Mb - not much of a compression benefit. Is that a valid assumption?
Please let me know your thoughts on my rationale above.
Thanks
Anand
Rule of thumb: everything goes in a spritesheet (texture atlas), unless there's a good reason not to.
Definitely texture atlas.
Cocos2d's caching mechanism will cause all individual images to be cached and remain in memory, so eventually they'll use more than if they were in a texture atlas. I would only use single images if they're rarely needed (ie menu icons) and I would also remove them from CCTextureCache just after they've been added to the scene, to make sure they will be removed from memory when leaving that menu screen.
Assumption may be wrong. A 320x480 image uses 512x512 as a texture in memory. If you have multiple of them, you may be better off having them all in a single texture atlas. Unless you enabled NPOT support in cocos2d. Again, don't forget that CCTextureCache is caching the textures.
Keep in mind that large textures benefit a lot from spritebatching. So even if there may only be 2-3 images in the texture atlas, it can make a difference in performance.
a) It really depends. If your app is running low on memory, you might want to have separate texture atlases. Otherwise it would be wasteful not to pack the images into a single texture atlas (if possible).
b) It depends on what's causing the stutter. Most common issue: loading resources (ie images) during gameplay, or creating and removing many nodes every frame instead of re-using existing ones.
c) Probably. It may depend on the texture atlas tool (I recommend TexturePacker). It definitely depends on the file format. If you can pack multiple PNG into a single .pvr.ccz texture atlas, you'll save a lot of memory (and gain loading speed).
For more info refer to my cocos2d memory optimization blog post.