I have a problem with memory management in cocos2d project. For my app I need to build all my animations before the interaction beginning. I have three animation.
Each one have like 20 png file with a resolution of 1300 x 1000 px and have a size of 200ko.
So in my initialization i just wrote :
self.animation = [CCAnimation animation];
[_animation setDelayPerUnit:0.04];
for(int i = 1; i <= 20; i++)
{
[_animation addSpriteFrameWithFilename:[NSString stringWithFormat:#"image(%d)#2x.png",i]];
}
[[CCAnimationCache sharedAnimationCache] addAnimation:_animation name:#"animationWin"];
This kind of code is executed three times. If I run my app, it crashes directly. If i just pre-load 2 animations I have no crash.
If I set breakpoints inside my for loops I can see that it crashes inside it.
I don't know how to solve this problem ... do you have an idea ?
Thanks a lot for your help !
Each one have like 20 png file with a resolution of 1300 x 1000 px and
have a size of 200ko.
Let's do some math, shall we?
Under the assumption that the PNG files are 32-bit and you do not have NPOT (non-power-of-two) support enabled, each texture consumes:
1300x1000 => expanded to power of two => 2048x1024 => number of pixels => 2,097,152 => times 32-Bit (4 Bytes) color depth per pixel => 8 Megabytes => times 20 textures => tadaaa … a whopping 160 MB texture memory usage.
Well there's your problem!
The file size of the PNG doesn't matter. It's a compressed format. But textures are uncompressed, unless you switch to PVR which are really well compressed but you also get artifacts and discoloration.
Definitely best solution is to tune down the size and/or amount of artwork you're trying to load.
the following will purge stuff for you.
NSLog(#"AppDelegate<applicationDidReceiveMemoryWarning> : before purging all caches");
[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[[CCDirector sharedDirector] purgeCachedData];
NSLog(#"AppDelegate<applicationDidReceiveMemoryWarning> : after purging all caches");
[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
Changing to PVR format will not help since it is the texture size that dictates the amount of memory (PVR will only benefit on 'disk' size and load time, not RAM required at run time). The depth of each pixel will:
+(void) mediumPixelFormat{
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444];
}
you can change the format at any point. Also i notice 1300x1000, that is very wasteful in POT. This will actually take as much room as a 2048x2048 texture. Any way you could work with your graphic artists to shave that to 1024x1024 , or combine the 3 textures into 2 ?
Well i think you are using too much memory. You should try to use spritesheets/batchnodes, another texture format like PVRTC and try with different pixel formats.
To help with all of the above i recommend Texture Packer
Related
I wish to compress my png sprite textures a bit so they don't take up that much memory as I build for mobile devices. As I use a lot of gif animations this is crucial for my game's performance.
I looked for an answer but the threads I found were more than 1 year old and not about sprites so I figured I ask my version. An image that's 224 KB in size takes up 1.6 MB in Unity with the generate mip maps turned off
So compressing the png sprite textures in my game. How to do that?
Try setting Format to Automatic Compressed.
For this to work on all mobile platforms make sure the initial image has sizes that are power of 2 (actually I think that multiple of 4 should be enough, but just to be on the safe side).
This will lower the quality of the image but should save you some space.
Turning mip map off is again a good idea as mim map increase the size of the image by about 33%.
And one more thing, make sure that Non Power of 2 is set to None, that may be the reason you see an increase in size at the moment.
Importing a set of 80 icons in QML as non-visible images to be used for shader sources (for arbitrary colorization):
property Image action: Image { sourceSize.width: 512; sourceSize.height: 512; source: "icons/action.svg"; mipmap: true; antialiasing: true }
// 79 more of those
I discover that my memory consumption has skyrocketed, from 45 mb to 128 mb, a whooping ~185% increase, thats 83 extra mb for the 80 icons.
It was expected, after all, 512 * 512 * 4 / 1024 / 1024 makes up for exactly 1 mb of memory. However, that cost is not acceptable, especially in the face of targeting mobile phones with the app.
I could reduce the rasterization size, however, I want the icons to be nice and crisp. The icon size itself varies according to the device display, but for optimal user experience it needs to be about an inch or so. Given that most new high end phones are already pushing above 500 dpi, I'd really hate to scale the icons down and have them appear blurry.
Since the SVGs are supposed to be colorized in arbitrary colors, they are in effect simply alpha masks, meaning that all I really need is one of those 4 channels. Unfortunately, QML's Image doesn't seem to offer any sort of control, the SVG is rasterized to a RGBA image.
And indeed, if I
QVector<QImage> imgs;
imgs.reserve(80);
QDirIterator it(":/icons", QDirIterator::Subdirectories);
while (it.hasNext()) {
QSvgRenderer renderer (it.next());
QImage ic(512, 512, QImage::Format_Alpha8);
ic.fill(Qt::transparent);
QPainter pp(&ic);
renderer.render(&pp);
imgs.append(ic);
}
I get the expected modest 20 mb increase in memory usage.
Any ideas how to save on some memory?
2 hours later - good news, first and foremost, a custom QQuickImageProvider works out of the box with QImage::Format_Alpha8, no problems there. Unnecessary channels are eliminated.
But more importantly, I realized that the icons lend themselves very well to distance fields representation. So I now employ 128x128 SDF textures, which scale beautifully to far above 512x512, reducing the memory usage for the icons to the measly 1.25 mb, for a total of 64x reduction of ram usage compared to the initial implementation.
The only downside is the 3-4 seconds (on a Note 3 phone) additional startup, because the distance fields are calculated on startup, but there are remedies for this as well, I might switch to pre-computed SDFs or offload if to shaders, which would be a little more complex, but should reduce the time at least 5-fold.
The thing with the Image component is it appears to render the SVG to a bitmap before it is drawn. Hence the requirement to set sourceSize to force it to render your SVG at different resolutions. This force rendering can lead to poor memory usage and poor performance.
As an alternative, I found a number of components in QML that render SVG perfectly via the icon property.
Item {
width: 256
height: 256
Button {
anchors.centerIn: parent
background: Item { }
icon.source: "https://raw.githubusercontent.com/Esri/calcite-ui-icons/master/icons/biking-32.svg"
icon.width: 256
icon.height: 256
icon.color: "blue"
enabled: false
}
}
Which renders my biking-32.svg at 256x256 resolution in blue:
I am playing through an animation of about 90 images # 480x320 each, and I am wondering with the images not being power of 2, will this be a big performance hit? I am programing for as far back as the iphone 3Gs. Also I am using cocs2d.
Assuming you load all of these images at the start and they are 16 bit images.
Well you will have 512x512x90 = 23,592,960 pixels
With 16 bit images thats 377,487,360 bits.
377,487,360 bits = 45 Megabytes of RAM.
So yes that is a big performance hit.
Let's see...
480x320 image will create a texture of 512x512 (next nearest power of two). 512x512 times 32bit color depth (4 bytes) equals 1 Megabyte. 90 times 1 Megabyte equals 90 Megabytes.
Your biggest problem will be allocating this much memory and caching it. Without caching the animation images, you'll have to load each image every time the animation frame changes. Loading 1 Megabyte from flash memory is pretty darn slow, I'm guessing > 100 milliseconds. So every time a frame changes, your app will stop for a fraction of a second. This will be a problem on the 3GS, and possibly the Retina devices as well if you use Retina images (each 960x640 image then requires 4 Megabytes texture memory).
You can only improve this by using PVR compressed images (use TexturePacker). Even halving texture size to 16 bit will probably not be enough for a smooth animation.
I am working on a gameplay which needs load 27 texture altas (each one 1024 * 1024) before enter the game scene
but sometimes my game crash because receiving memory warning
I know 27 texture altas will use:
4 * 27 * 1024 * 1024 = 108mb memory
which is huge amount, but I really need to load them before entering game.
Is there anyway to solve my issue?
Any ideas will be very appreciated!
BTW:
I am using cocos2d 1.0.1
Best suggestion is to review your design, and the 'need' for preloading all these textures. I tend to pre-load only the textures that are most frequently used (animations and static map objects).
For example, I have textures for animating walks on a map for 16 character classes. I regrouped the 'idle' animations in 4 textures, and preload these, because initially, when a soldier enters the scene, it idles. The moving animations are in separate textures that are loaded in real time, as a function of the direction of travel, for each character class in movement. When the characters stop walking (idle), i remove unused textures from the cache, as well as unused sprite frames.
Also: there are other avenues for memory management. You could use a 16 bit format for certain textures (RGB88888 is the default). You may gain by converting to compressed PVR format (once again this is lossy, but could be fine for some textures)
Look here and there to learn more about picture formats in coco, and the relationship to memory consumption (as well as load, rendering speeds). But once again, before you start optimizing, make certain you have no alternative to the pre-load all approach.
use jpg instead of png it will make that non transparent you can make that transparent by alpha image of that image it will help you reducing size almost half of you are using now.
I am a first time poster. I have a problem that seems very common to a lot of people but I can't seem to find or decipher an answer anywhere.
The game I'm making has 3 rather large sprites on screen (230 high) x various widths.
Each sprite has 3 1024x1024 character sheets where the frames of animations are taken from.
I've experimented with PVR's but at that size they are absolutely horrible so I want to keep PNG's.
From other information I believe that the device can handle 3 1024x1024 PNGs in memory without memory warnings.
My problem is I end up with 9 as if I don't use imagenamed then the time it takes to load the sheet from disk is unacceptable.
I have created a NSMutableDictionary to store the data from the png image sheets into, but here lies my problem.
How do I add uncompressed png data to the NSMutableDictionary without using imagenamed? If I add it in uncompressed (imagewithcontents of file) then there is still a massive loading time when I get the image from the cache.
I need to somehow store it uncompressed in the NSMutableDictionary - Assign it to the image of the sprite (sprites are UIImageViews) so that it doesn't get stored as it does if I use imageNamed.
Completely free the png from texture memeory if I need to change the sheet the sprite is grabbing the frames from. (not from my NSMutableDictionary cache)
thanks in advance -