常见的图像格式bmp、jpeg以及jpeg2000,以及png;甚至最近几年google的webp格式。
bmp格式基本上没有压缩;
jpeg是有损压缩,早已成为图像传输标准,不支持透明通道;jpeg2000最显著增加渐进式传输。jpeg可以任意指定感兴趣区域的压缩质量。
png无损压缩,支持透明通道,android的各种资源都是png。
webp,最近几年google的开源项目,更高的压缩比,更小的图像质量损失。
这么多现成的图像格式,为毛压缩纹理不采用呢?为何很多公司都推出自己的纹理压缩格式呢?原因很简单:jpeg、png这些压缩格式是为CPU解码设计的,不适合GPU的并行特性。
参见 Texture Compression Jacob strom, Ericsson Research
page48 道出了GPU解码图像的三个特点:
1)必须能够随机访问。即对于任意一个像素都能随机地快速算出它在图像数据中的地址(偏移值)。而对于JPEG显然是做不到的,它采用VLC(variable bit length coding)不定长编码方式,为不同区域分配不同的压缩位数,从而达到为不同区域分配不同压缩质量。
上图中,茶壶区域为重要和感兴趣区域,JPEG压缩数据中这块区域占更多的bits。
2)会有很多解压单元并行处理,使得解压算法复杂度必须足够低,足够简单。
3)调色板或者其他全局数据会导致 间接寻址(Indirect addressing),因此这些数据在纹理压缩中应该尽可能避免。jpeg内部也有。
上图为间接寻址模式中获取颜色数据的过程:GPU首先请求加载索引数据14;一旦有了索引数据就可以立即加载实际颜色值,来回四次最终得到颜色值。索引数据可能为FIFO缓冲区引入了性能隐患,芯片端保存颜色表的代价也十分大,颜色表可能和纹理缓存占的空间接近;所以最好避免使用颜色表这些全局数据。
于是显卡厂商推出专为GPU设计的压缩纹理格式应用而生了:
› Texture compression algorithms
– Palettized textures
– BTC
– CCC
– S3TC
– PVR-TC
– PACKMAN
– ETC (Ericsson Texture Compression), ETC1,ETC2。
› Normal map compression
– 3Dc
BTW: 普通jpeg、png图片,从文件加载的时候必须cpu先解码成原始的RGB、RGBA格式数据,然后glTexImage2D生成纹理; ETC这类纹理可以直接将原始数据glCompressTexImage2D传给OpenGL,GPU创建纹理时自行解码。
opengles and ETC:opengle3.0后支持etc2,gles1.1和gles2.0支持etc1。
Android and ETC:android sdk自带的etc1tool.exe,支持从png直接转化成etc的pkm文件。etc1tool的过程在android源码中可以找到,etc1.h, etc1.cpp,两个文件可以单独抽出来,已上传到我的资源中。http://download.csdn.net/detail/dizuo/6708161
压缩性能:在小米1上测试,很慢达不到实时,etc1.cpp中压缩算法复杂度很高,只能离线处理。解码过程是GPU多个processor-单元并行处理速度很快。
测试Code:
int comprSize = etc1_get_encode_image_size(256, 256); etc1_byte* pComprData = new etc1_byte[comprSize]; int width = 256; int height = 256; int pixelSize = 2; // 输入原始图像数据是RGB565,跟RGB888基本类似。 int stride = pixelSize * width; int start = SysGetTickCount(); etc1_encode_image((const etc1_byte*)texBuffer, width, height, pixelSize, stride, pComprData); int end = SysGetTickCount(); __android_log_print(ANDROID_LOG_INFO,"etc1", "%d [ enter ]", (end-start)); glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_ETC1_RGB8_OES, width, height, 0, comprSize, pComprData); delete[] pComprData; // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texBuffer);测试结果输出:
12-13 12:09:18.621: I/etc1(11562): 376067 [ enter ] 12-13 12:09:18.951: I/etc1(11562): 316295 [ enter ] 12-13 12:09:19.471: I/etc1(11562): 306647 [ enter ] 12-13 12:09:19.751: I/etc1(11562): 278829 [ enter ] 12-13 12:09:20.061: I/etc1(11562): 280077 [ enter ] 12-13 12:09:20.321: I/etc1(11562): 262186 [ enter ] 12-13 12:09:20.621: I/etc1(11562): 293347 [ enter ] 12-13 12:09:20.901: I/etc1(11562): 258785 [ enter ] 12-13 12:09:21.161: I/etc1(11562): 260074 [ enter ]单位是GetTickCount的结果。
history - add etc1 texture 2013/12/13