Do I understand correctly that CCLabelBMFont only loads the font texture once, no matter how many labels you have, thus 10 labels will not exceed the memory requirements of 1 label, or said another way, the actual memory usage of any and all labels is approx equivalent to the memory usage of the font texture itself?
I ask because I preferred to use CCLabel but when I compared it to UILable, the resolution of UILabel is much sharper; I'm not sure the cause of this but CCLabel just doesn't look that great.
Yes.
Every texture cocos2d uses is cached only once. CCTextureCache does that, regardless of the class that created or loaded the texture. Memory-wise the only difference between using 1 CCLabelBMFont and 1000 is just the memory of the CCLabelBMFont instances. Which is roughly around 500 Bytes per instance.
Related
I have created a simple 2D image viewer in C++ using MFC and OpenGL. This image viewer allows a user to open an image, zoom in/out, pan around, and view the image in its different color layers (cyan, yellow, magenta, black). The program works wonderfully for reasonably sized images. However I am doing some stress testing on some very large images and I am easily running out of memory. One such image that I have is 16,700x15,700. My program will run out of memory before it can even draw anything because I am dynamically creating an UCHAR[] with a size of height x width x 4. I multiply it by 4 because there is one byte for each RGBA value when I feed this array to glTexImage2D(GLTEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGBA, GLUNSIGNED_BYTE, (GLvoid*)myArray)
I've done some searching and have read a few things about splitting my image up into tiles, instead of one large texture on a single quad. Is this something that I should be doing? How will this help me with my memory? Or is there something better that I should be doing?
Your allocation is of size 16.7k * 15.7k * 4 which is ~1GB in size. The rest of the answer depends on whether you are compiling to 32 bit or 64 bit executable and whether you are making use of Physical Address Extensions (PAE). If you are unfamiliar with PAE, chances are you aren't using it, by the way.
Assuming 32 Bit
If you have a 32 bit executable, you can address 3GB of that memory so one third of your memory is being used up in a single allocation. Now, to add to the problem, when you allocate a chunk of memory, that memory must be available as a single continuous range of free memory. You might easily have more than 1GB of memory free but in chunks smaller than 1GB, which is why people suggest you split your texture up into tiles. Splitting it into 32 x 32 smaller tiles means you are allocating 1024 allocations of 1MB for example (this is probably unnecessarily fine-grained).
Note: citation required but some modes of linux allow only 2GB..
Assuming 64 Bit
It seems unlikely that you are building a 64 bit executable, but if you were then the logically addressable memory is much higher. Typical numbers will be 2^42 or 2^ 48 (4096 GB and 256 TB, respectively). This means that large allocations shouldn't fail under anything other than artificial stress tests and you will kill your swapfile before you exhaust the logical memory.
If your constraints / hardware allow, I'd suggest building to 64bit instead of 32bit. Otherwise, see below
Tiling vs. Subsampling
Tiling and subsampling are not mutually exclusive, up front. You may only need to make one change to solve your problem but you might choose to implement a more complex solution.
Tiling is a good idea if you are in 32 bit address space. It complicates the code but removes the single 1GB contiguous block problem that you seem to be facing. If you must build a 32 bit executable, I would prefer that over sub-sampling the image.
Sub-sampling the image means that you have an additional (albeit-smaller) block of memory for the subsampled vs. original image. It might have a performance advantage inside openGL but set that against additional memory pressure.
A third way, with additional complications is to stream the image from disk when necessary. If you zoom out to show the whole image, you will be subsampling >100 pixels per screen pixel on a 1920 x 1200 monitor. You might choose to create an image that is significantly subsampled by default, and use that until you are sufficiently zoomed-in that you need a higher-resolution version of a subset of the image. If you are using SSDs this can give acceptable performance but adds a lot by way of additional complication.
So, I'm working on a project that has some big textures and recently I decided to split into different atlases by scene so that when navigating through scenes SpritKit can get actually rid of unused textures
(Since I cannot control memory usage manually I hope SpriteKit is smart enough to know when a texture atlas is not being used at all and release it if required).
Now, after doing this change i went to take a look at resulting atlases and to my surprise their size isn't a power of 2, which was one of the first things you learned in Cocos2D. (ie. a texture of 540x540 would actually end up being a 1024x1024 in OpenGL so that it makes more sense to be 1024x512 if possible or even fill as many sprites as possible to not waste memory)
If this the same in SpriteKit or any idea how it actually works? Maybe it'd make more sense to not split atlases since I'm going to end up maybe using the same or even more memory with the awful atlases that have been auto-generated...
This info is looooong outdated. Textures no longer need to be strictly POT (exception: PVR compressed textures have to be POT). NPOT was first supported by iPhone 3GS.
These days it is recommended not to use POT textures when you don't have to in order to conserve memory.
I am getting crashes on iPhone 4s due to "memory pressure." My game is set up like this:
Main scene sprite sheet that always stays in memory.
Individual game scene levels load from individual textures (not sprite sheets).
When a level is done and we return to the main scene, I would like those cached game scene textures to get dumped. What ends up happening is that when you play through 3-4 levels, it crashes as it runs out of memory as it never releases this memory after a level. I don't want the level textures to be cached past the lifespan of the game scene. When returning to the main scene, it needs to release this memory.
I have tried removing all of the game scene children which does nothing to memory. I have tried looking for a specific way to clear just these textures I have loaded in this game scene from the cache.
Any suggestions?
Are you using cocos2d v2? You probably have memory leaks since unused textures are removed when necessary. Try profiling your app to see if you have leaks and where they are at.
You also can call these methods yourself at the appropriate time, although I doubt you'd have to:
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
But again what you describe sounds more like memory leaks. When your application receives a memory warning the cached data is purged. During this purge the remove unused textures method is called on the texture cache, among other things. If you have 3/4 levels of data still lurking around long after you've exited those scenes, that sounds like a memory leak.
I'm assuming this only happens after visiting multiple scenes and the problem just isn't that your 4th scene is simply trying to load more data than the device can handle.
You can remove specific textures calling:
In cocos2D-x v3.x :
Director::getInstance()->getTextureCache()->removeTextureForKey(ImageKeyName)
In cocos2D-x v2.x :
CCTextureCache::sharedTextureCache()->removeTextureForKey(ImageKeyName);
Where ImageKeyName is just the path of the image (the same you used to load the texture)
I developed a game with SDL2.00 and c++. I seemed to be having memory and CPU issues. CPU usage goes up to 40% and memory usage goes up by 5mg a second.
So I think the reason is the way Im handling Textures\Sprites.
My question is should I create a different/new sprite/texture for every instance ?
For example, I have a class called Enemy which contains all the variable and methods related to enemy monsters such as HP, damage, location , image(Texture) etc. This class contains its own texture to be rendered onto the renderer.
Is this the right way? Or should I create a Sprite/Texture for all the images before hand and render them as needed?
and I'm wondering if this will render two different images onto the renderer:
RenderCopy(renderer, image);
image->SetPosition(X,Y);
RenderCopy(renderer,image);
or is it going to move the sprite to the new position?
I think my issues are caused my overloading the renderer and/or having too many textures being loaded.
Let me know what you think .
OpenGL is not a scene graph. It's a drawing API. So everytime you're allocating a new texture you're creating a new data object that consumes memory. You should reuse and share resources where possible.
My question is should I create a different/new sprite/texture for
every instance ?
No, not unless every instance of the sprite uses different textures, otherwise you should reuse them, ie only load them once and store a pointer to the texture the sprite uses.
and I'm wondering if this will render two different images onto the
renderer:
RenderCopy(renderer, image);
image->SetPosition(X,Y);
RenderCopy(renderer,image);
or is it going to move the sprite to the new position?
This will copy the image twice. First at the old position and then at the new. What you will get is a trailing image. You should probably either clear the previous position or render the background at that position (or whatever should be there).
I want to know if there is any benefiting caching a sprite sheet and accessing the sprite by frame without using the CCSpriteBatchNode?
In some parts of my game the sprite batch node is useful because there is a lot on the screen, however on another part its not, because there are just a few things, and there are requirements for layers so CCSpriteBatchNode wouldn't be useful. However, for the sake of consistency I would like to use Sprite Sheets for all my sprites, and so was beginning to wonder if I would still receive any benefit from it? (Or worse that it could some how be slower...)
There is defiantly a benefit to putting all your sprites into a texture atlas or sprite sheet as you called it. Textures are stored in memory in power of 2 dimensions. So if you have a sprite that is 129px by 132px it is stored in memory as 256px by 256px which is the nearest power of 2 size. If you have many sprites that is quite a lot of extra memory used up.
By using a texture atlas you only have one texture in memory and then it pulls the pieces out of it that it needs for your sprites. These sprites can be whatever size you want without having to worry about power of 2 sizes.
You can read more details about it on this tutorial
http://www.raywenderlich.com/2361/how-to-create-and-optimize-sprite-sheets-in-cocos2d-with-texture-packer-and-pixel-formats