rgb24轉rgb555/rgb565優化
真彩色轉成高彩色的快速算法
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
這裏我不談減低色彩深度時, 採用抖動減少誤差的方法. 因爲本文將着力於找到儘可能快的算法 (雖然最快的方法一定存在, 但我們只能去接近它, 而無法達到, 因爲優化是無至盡的, 而且隨着 CPU 而變化)實時轉化 24bit (或32bit) 的真彩色位圖到16bit(15bit)的高彩色.
爲什麼要實時轉換顏色深度?
通常, 2D 遊戲中的位圖, 無論在外存中按什麼顏色深度存放, 加栽後都被轉換成了需要的顏色深度. 我們不太注意顏色深度轉換說需要的時間.
但是, 現在不同了. 雲風未來的計劃中, 最重要的一項是製作一個超級 2D 引擎. 將支持 Voxel 物體和實時光線處理這樣的特性, 而且在光線處理中, 32 級的光線亮度級別也遠遠不夠, 所以, 未來的 2D 遊戲的發展趨勢應該是採用真彩色, 至少是在內部運算時使用. 在某些場合下, 我們可能需要做 15/16bit 高彩色的輸出, 所以有必要找到更快的方法實時處理.
下面, 我們對此做一些探討, 雖然顯卡可以支持 15 或 16 bit 色中的一種, 但這裏全部用 16bit 色舉例:
先來看看 C 版本:
red=(truecolor>>8)&0xf800;
green=(truecolor>>5)&0x7e0;
blue=(truecolor>>3)&0x1f;
hicolor=red|green|blue;
這樣當然是相當慢的, 所以我們還是要藉助彙編. 而彙編能極大的優化它:
lodsd ;RRRRRRRR GGGGGGGG BBBBBBBB
shr eax,3 ;000RRRRR RRRGGGGG GGGBBBBB
shl al,2 ;000RRRRR RRRGGGGG GBBBBBxx
shl ax,3 ;000RRRRR GGGGGGBBB BBxxxxx
dec esi
shr eax,5 ;00000000 RRRRRGGG GGGBBBBB
stosw
是不是精簡了很多? 但不幸的是, 雖然看起來很簡潔, 但由於大量使用部分寄存器, 對流水線的衝擊很大. 代碼幾乎把流水線的效率減到了最低. 優化方案很多, 我們可以在一次循環裏處理兩個點, 分別使用 eax 和 ebx, 然後交錯那些代碼; 又或者將上面代碼的後半部分改爲查表, 相信都能提高速度. 但是下面我還想提出另一種方案, 採用 MMX 指令級:
mm7=F800F800F800F800
mm6=FC00FC00FC00FC00
------------------------------
punpcklbw mm0,[red+edx]
;mm0=RRRRRRRR 00000000 RRRRRRRR 00000000 RRRRRRRR 00000000 RRRRRRRR 00000000
punpcklbw mm1,[green+edx]
;mm1=GGGGGGGG 00000000 GGGGGGGG 00000000 GGGGGGGG 00000000 GGGGGGGG 00000000
punpcklbw mm2,[blue+edx]
;mm2=BBBBBBBB 00000000 BBBBBBBB 00000000 BBBBBBBB 00000000 BBBBBBBB 00000000
pand mm0,mm7
;mm0=RRRRR000 00000000 RRRRR000 00000000 RRRRR000 00000000 RRRRR000 00000000
pand mm1,mm6
;mm1=GGGGGG00 00000000 GGGGGG00 00000000 GGGGGG00 00000000 GGGGGG00 00000000
psrlw mm2,11
;mm2=00000000 000BBBBB 00000000 000BBBBB 00000000 000BBBBB 00000000 000BBBBB
psrlw mm1,5
;mm1=00000GGG GGG00000 00000GGG GGG00000 00000GGG GGG00000 00000GGG GGG00000
por mm0,mm2
por mm0,mm1
;mm0=RRRRRGGG GGGBBBBB RRRRRGGG GGGBBBBB RRRRRGGG GGGBBBBB RRRRRGGG GGGBBBBB
movq [dis+edx*2],mm0
add edx,4
我們對 MMX 的運用是針對它的並行運算, 直接從 RGB888 格式利用並行處理變成 RGB565 似乎不可能, 但是, 如果我們將 RGB 三個色素分開存放, 就將其變爲了可能. 可以同時讀入 4 個色素, 並行處理, 然後合併, 這樣便在一個循環內處理了 4 個點. 考慮到 CACHE 的效率, 最好不要將 RGB 三塊內存分的太開. 我的建議是, 位圖的每一行分成三個部分, 即爲 Red 段, Green 段 和 Blue 段.
上面的方法都是可以繼續優化的, 本文旨在啓發朋友們的靈感, 找出更好的方法.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
這裏我不談減低色彩深度時, 採用抖動減少誤差的方法. 因爲本文將着力於找到儘可能快的算法 (雖然最快的方法一定存在, 但我們只能去接近它, 而無法達到, 因爲優化是無至盡的, 而且隨着 CPU 而變化)實時轉化 24bit (或32bit) 的真彩色位圖到16bit(15bit)的高彩色.
爲什麼要實時轉換顏色深度?
通常, 2D 遊戲中的位圖, 無論在外存中按什麼顏色深度存放, 加栽後都被轉換成了需要的顏色深度. 我們不太注意顏色深度轉換說需要的時間.
但是, 現在不同了. 雲風未來的計劃中, 最重要的一項是製作一個超級 2D 引擎. 將支持 Voxel 物體和實時光線處理這樣的特性, 而且在光線處理中, 32 級的光線亮度級別也遠遠不夠, 所以, 未來的 2D 遊戲的發展趨勢應該是採用真彩色, 至少是在內部運算時使用. 在某些場合下, 我們可能需要做 15/16bit 高彩色的輸出, 所以有必要找到更快的方法實時處理.
下面, 我們對此做一些探討, 雖然顯卡可以支持 15 或 16 bit 色中的一種, 但這裏全部用 16bit 色舉例:
先來看看 C 版本:
red=(truecolor>>8)&0xf800;
green=(truecolor>>5)&0x7e0;
blue=(truecolor>>3)&0x1f;
hicolor=red|green|blue;
這樣當然是相當慢的, 所以我們還是要藉助彙編. 而彙編能極大的優化它:
lodsd ;RRRRRRRR GGGGGGGG BBBBBBBB
shr eax,3 ;000RRRRR RRRGGGGG GGGBBBBB
shl al,2 ;000RRRRR RRRGGGGG GBBBBBxx
shl ax,3 ;000RRRRR GGGGGGBBB BBxxxxx
dec esi
shr eax,5 ;00000000 RRRRRGGG GGGBBBBB
stosw
是不是精簡了很多? 但不幸的是, 雖然看起來很簡潔, 但由於大量使用部分寄存器, 對流水線的衝擊很大. 代碼幾乎把流水線的效率減到了最低. 優化方案很多, 我們可以在一次循環裏處理兩個點, 分別使用 eax 和 ebx, 然後交錯那些代碼; 又或者將上面代碼的後半部分改爲查表, 相信都能提高速度. 但是下面我還想提出另一種方案, 採用 MMX 指令級:
mm7=F800F800F800F800
mm6=FC00FC00FC00FC00
------------------------------
punpcklbw mm0,[red+edx]
;mm0=RRRRRRRR 00000000 RRRRRRRR 00000000 RRRRRRRR 00000000 RRRRRRRR 00000000
punpcklbw mm1,[green+edx]
;mm1=GGGGGGGG 00000000 GGGGGGGG 00000000 GGGGGGGG 00000000 GGGGGGGG 00000000
punpcklbw mm2,[blue+edx]
;mm2=BBBBBBBB 00000000 BBBBBBBB 00000000 BBBBBBBB 00000000 BBBBBBBB 00000000
pand mm0,mm7
;mm0=RRRRR000 00000000 RRRRR000 00000000 RRRRR000 00000000 RRRRR000 00000000
pand mm1,mm6
;mm1=GGGGGG00 00000000 GGGGGG00 00000000 GGGGGG00 00000000 GGGGGG00 00000000
psrlw mm2,11
;mm2=00000000 000BBBBB 00000000 000BBBBB 00000000 000BBBBB 00000000 000BBBBB
psrlw mm1,5
;mm1=00000GGG GGG00000 00000GGG GGG00000 00000GGG GGG00000 00000GGG GGG00000
por mm0,mm2
por mm0,mm1
;mm0=RRRRRGGG GGGBBBBB RRRRRGGG GGGBBBBB RRRRRGGG GGGBBBBB RRRRRGGG GGGBBBBB
movq [dis+edx*2],mm0
add edx,4
我們對 MMX 的運用是針對它的並行運算, 直接從 RGB888 格式利用並行處理變成 RGB565 似乎不可能, 但是, 如果我們將 RGB 三個色素分開存放, 就將其變爲了可能. 可以同時讀入 4 個色素, 並行處理, 然後合併, 這樣便在一個循環內處理了 4 個點. 考慮到 CACHE 的效率, 最好不要將 RGB 三塊內存分的太開. 我的建議是, 位圖的每一行分成三個部分, 即爲 Red 段, Green 段 和 Blue 段.
上面的方法都是可以繼續優化的, 本文旨在啓發朋友們的靈感, 找出更好的方法.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.