關於壓縮紋理的格式的思考

常見的圖像格式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創建紋理時自行解碼。


ETC1 Texture

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
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章