cocos-js,内存管理1---一张图片的内存

前端之家收集整理的这篇文章主要介绍了cocos-js,内存管理1---一张图片的内存前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一.1张图片内存如何计算

一张图片占用的内存由以下两个因素决定:

  • 图片的像素点个数
  • 单位像素占用的字节数

其中图片的像素点个数是图片的宽度与长度的积,所以一张图片占用的内存值为:

图片长度  *  图片宽度  *  单位像素占用的字节数

单位像素所占用的字节数与图片的解码方式有关。
默认情况下,在cocos里加载一张图片,每一个像素点使用4个byte来表示1个byte(8位)代表red,另外3个byte分别代表green、blue和alpha透明通道。这个就简称RGBA8888.

举例来说,一张1136x640的背景图占用的内存为 1136x640x32/8 = 2840 KB

当然我们也可以改变图片的解码格式:

cc.Texture2D.setDefaultAlphaPixelFormat(cc.Texture2D.PIXEL_FORMAT_RGBA4444)

此时,图片的解码都会使用RGBA4444

举例来说,一张1136x640的背景图占用的内存为 1136x640x16/8 = 1420 KB

这里有个问题:首先,纹理像素格式的改变会影响后面加载的所有纹理。因此,如果你想后面加载纹理使用不同的像素格式的话,必须再调用方法,并且重新设置一遍像素格式。

其次,如果你的CCTexture2D设置的像素格式与图片本身的像素格式不匹配的话,就会导致显示严重失真。比如颜色不对,或者透明度不对等等。


二.cocos支持的纹理像素格式

AUTO 自动检测模式
BGRA8888 32-bit纹理
RGBA8888 32-bit纹理
RGB888 24-bit纹理
RGB565 16-bit纹理,不带Alpha通道
A8 用作遮罩(masks)的8-bit纹理
I8 8-bit intensity纹理
AI88 用作遮罩的16-bit纹理
RGBA4444 16-bit纹理
RGB5A1 16-bit纹理
PVRTC4 4-bit PVRTC压缩纹理 texture
PVRTC4A 4-bit PVRTC压缩纹理: PVRTC4 (has alpha channel)
PVRTC2 2-bit PVRTC压缩纹理: PVRTC2
PVRTC2A 2-bit PVRTC压缩纹理: PVRTC2 (has alpha channel)
ETC ETC压缩纹理
S3TC_DXT1 S3TC压缩纹理
S3TC_DXT3 S3TC压缩纹理
S3TC_DXT5 S3TC压缩纹理
ATC_RGB ATITC压缩纹理
ATC_EXPLICIT_ALPHA ATITC压缩纹理
ATC_INTERPOLATED_ALPHA ATITC压缩纹理

RGBA8888是默认的格式。

对于16位的纹理来说,使用RGB565可以获得最佳颜色质量,因为16位全部用来显示颜色:总共有65536总颜色值。但是,这里有个缺点,除非图片是矩形的,并且没有透明像素。所以RBG565格式比较适合背景图片和一些矩形的用户控件。

RBG5A1格式使用一位颜色来表示alpha通道,因此图片可以拥有透明区域。只是,1位似乎有点不够用,它只能表示32768种可用颜色值。而且图片要么只能全部是透明像素,或者全部是不透明的像素。因为一位的alpha通道的缘故,所以没有中间值。但是你可以使用fade in/out动作来改变纹理的opacity属性

如果你的图片包含有半透明的区域,那么RBGA4444格式很有用。它允许每一个像素值有127个alpha值,因此透明效率与RGBA8888格式的纹理差别不是很大。但是,由于颜色总量减少至4096,所以,RBGA4444是16位图片格式里面颜色质量最差的。

现在,你可以得到16位纹理的不足之处了:它由于颜色总量的减少,有一些图片显示起来可能会失真,而且可能会产生“梯度”。


三.如何优化内存

1.忽视文件图片大小

图片文件大小和纹理内存占用是两码事。假设他们是帐篷。图片文件就相当于帐篷被装在行李箱。但是,如果你想要使用帐篷的话,它必须被撑起来,被“膨胀”。
图片文件和纹理的关系与此类似。图片文件大多是压缩过的,它们被使用的话必须先解压缩,然后才能会GPU所处理,变成我们熟知的纹理。
一个2048*2048的png图片,采用32位颜色深度编码,那么它在磁盘上占用空间只有2MB。但是,如果变成纹理,它将消耗16MB的内存!

2.用SetDefaultAlphaPixelFormat()来实现

尽量使用颜色深度为16bit的图片。但是前面也提到了,如果图片本身的颜色深度如果是32位。但是用SetDefaultAlphaPixelFormat()设置成16位。则可能让图片失真.图片看起来就很模糊,这当然是有解决的办法,庆幸我们有TexturePacker(TP)工具.
TP有一个特性叫做“抖动”,它可以使得原本由于颜色数量减少而产生的失真问题得到改善。
特别是在拥有Retina显示的像素密度下,你几乎看不出16位与32位的纹理之间的显示差别。当然,前提是你需要采用“抖动”算法。

抖动算法

3.使用NPOT纹理

NOPT是“non power of two”的缩写,译作“不是2的幂”。如果纹理图集(texture atlas)使用NPOT的纹理,它将有一个具大的优势:它允许TP更好地压缩纹理。因此,我们会更少地浪费纹理图集的空白区域。而且,这样的纹理在加载的时候,会少使用1%到49%左右的内存。而且你可以使用TP强制生成NPOT的纹理。

4.使用pvr格式纹理

因为jpg是没有透明色的,一个像素最多3字节,而png一个像素4字节,jpg纹理应该占用内存更小才对,但是cocos把所有纹理转换成rgba8888格式,所以无论是jpg还是png,占用的都是4字节。正因cocos2d对其他纹理支持不够好,pvr才会显得那么高效。

pvr格式可以被显卡所认可,而不需要开辟临时内存来读取,所以即便同为argb8888格式的图片,pvr也会比png有效率,虽然不会节约程序稳定运行时的内存,但是会避免加载大量图片时的内存暴涨。 并且如果是ios设备的话,可以使用pvrtc4格式的图片,这个格式相当于windows下的dds图片,是可以被显卡直接支持的。它是有损压缩,一个像素只占4位,不过如果不是有渐变半透明色的话,一般效果可以接受,而其节约的内存和cpu时间非常非常显著。

pvr也不是万金油。android设备下虽然可以使用pvr格式,但是不能使用pvrtc4,希望通过pvr像ios设备上一样真正减少游戏内存是不太可行的。

pvr.ccz其实就是pvr图片zip打包下,程序读的时候还是先解压出pvr资源,然后再读取pvr。不过由于压缩下可以极大的减小图片体积,所以虽然多了解压过程也不会有特别多的cpu消耗。

一张jpg图片实际加载过程内存消耗,以一张1024*1024 argb8888 500k的jpg图片为例: a.读取图片文件(消耗图片大小内存,500k) b、解析jpg数据(cgimage,4mb) c、释放500k的图片内存 d、opengl纹理数据(4mb) e、释放cgimage的4mb内存。 注意,这个过程不是必然的顺序执行,释放cgimage内存的实际是有系统决定的,会很快,但是不一定是立即执行。 所以内存会瞬间飙升9mb左右,然后减少5mb,稳定到4mb左右.

png图片的加载过程与此相同.

pvr图片可以节约解析图片数据到纹理这一步的消耗。也就是说读取pvr图片资源(等价于解压pvr.ccz到内存,如果是1024*1024 argb8888格式的话,那么图片大小就是4mb,ccz压缩后图片1mb左右)消耗4mb,将pvr图片数据提交给显卡消耗4mb。然后释放文件数据4mb。这么看似乎跟Png从内存占用上相比也不是非常有优势。(注意这里说的pvr是指pvr封装的argb8888,与pvrtc4的性能有天壤之别)

这里还有一点需要说明,一般我们处理windows下的dds纹理的时候,都习惯将其按2的整次幂对其,虽然图片内容只有900*900,但是图片大小却是1024*1024。那我们读取这个图片所消耗的内存就是4mb,按2的整次幂对其是有助于提高运行效率的,但是不是非常必须的。ios和android的设备都支持非2的整次幂的纹理。所以如果是png图片,那么它该多大就多大。此时消耗的内存就只有900*900*4=3mb。

rgb565和rgb5551的图片所消耗的内存是rgba8888的一半,如果没有透明渐变的话,视觉上也看不出什么区别。一些大的背景图可以优先选择这种格式。

pvr图片加载速度要比png和jpg快3~5倍(同样1024*1024 argb8888),png消耗的时间可能是700ms左右,但是pvr只需要100ms左右。如果是pvr.ccz压缩下,消耗的时间是200ms左右。可见pvr在加载速度上还是有非常大的优势的。这个应该是因为png和jpg需要把图片数据还原为rgba,但是pvr可以直接把图片数据传递给显卡。pvrtc4的图片是可以被powervr显卡直接支持的。

猜你在找的Cocos2d-x相关文章