利用MMX最佳化64K色Alpha混合演算法(轉)
利用MMX最佳化64K色Alpha混合演算法(轉)[@more@] 開始使用MMX CPU後,一直在考慮如何用MMX技術加快Alpha混合的操作,尤其是針對目前常用的高彩模式。而早先在國外一個有關遊戲程式設計的郵件列表討論的結果是MMX不利於對16位色進行Alpha混合操作。讓我們先來看看MMX技術相對於普通指令集的更新,來了解一下這個論點的立論。 MMX技術的優勢在於,它的暫存器是64位的,而提供了分組模式,可以將暫存器內的資料按8個位元組,或4個字,或2個雙字同時進行同一操作,方便了大資料量的資料處理。可以成組資料同時作比較操作,這為透明色點的批次判斷帶來好處。MMX的CPU擁有8個MMX暫存器,在一定程度上緩解了80x86CPU暫存器數量不足的缺陷。 但是它也有諸多不足,比如算術指令不能對四位元組字操作。指令結構都不影響標誌位。不能對常數立即定址。MMX系統指令集的指令相當貧乏(連NOT操作也不能直接實現)。當顏色深度是24/32位時,RGB都佔8位,這樣可以巧妙的利用MMX裡的分組乘法指令達到做Alpha混合運算的效果(MMX的乘法相關指令只有對字操作的PMULHW/PMULLW兩條,分別是成組資料的乘後取高位和取低位)本文旨在探討16位色的快速Alpha混合運算,所以此處略去不提。而16位色,紅綠藍各佔5或6位,難以被分組分開,所以不利於運用MMX的這些特性。當然另外的解決方法是採用aRGB 4444的結構,其中4位是Alpha通道,每個色素佔半個位元組,再採用類似的方法。 看過雲風去年提出的《16位Alpha混合最佳化演算法》的朋友,應該會聯想到這個演算法向MMX的引申,好了,也許你已經明白了大概,本文的理論基本點就在此,唯一的問題是,我們需要面對的是MMX指令集的種種缺陷,這些在實際的程式設計中會逐步的體現出來,下面,雲風將在介紹演算法的同時,附帶的提出一些運用MMX的技巧。先來看看上次的演算法有無可進一步最佳化的可能: 16位下Alpha混合的關鍵在於如何將RGB分離,讓隨後的乘法結果不至於相互干擾。我提出的是將16位的“rrrrrggggggbbbbb”擴充套件到32位變形成“00000gggggg00000rrrrr000000bbbbb”,即將中間的綠色提到高16位,而使色素間隔都有5到6位,而對於5位的顏色,超過5位的Alpha級別是沒有意義的,所以只要設定Alpha值在0~31間,同時算這3個色素的乘法是不會因為進位造成干擾的。而這裡需要多操作一次移位擴充套件16位到32位,然後需要一次與操作, 將中間間隔位置0,而且結果需要同樣複雜的逆操作從32位還原到16位。 改進的思路是直接將兩個點交錯分離,即“rrrrrggggggbbbbbRRRRRGGGGGGBBBBB”分離成“rrrrr000000bbbbb00000GGGGGG00000”及“00000gggggg00000RRRRR000000BBBBB”兩部分,前一部分右移5位後變成“00000rrrrr000000bbbbb00000GGGGGG”,兩個數字就都可以同時運算3個色素,其結果後一組右移5位後可以與前一組合並。這樣就省去了好幾次移位操作,並且資料可以4位元組讀入,和四位元組寫,粗看真的效率很高。但是在傳統的80x86上卻有兩點制約了它的運用: CPU 的暫存器不夠用,這個方法光儲存資料就需要4個32位的暫存器,雖然EAX、EBX、ECX、EDX剛夠用,但是這就使得Alpha混合函式不能直接寫在Blit操作裡面。必須單寫個子程式呼叫。(不過也值得寫嘗試一下,不是嗎?如果有朋友寫好了,希望能給我拜讀一下,我在風魂遊戲程式庫裡留了介面,並在註釋裡提到了函式的具體寫法。) 2D遊戲中,一般都是利用Alpha混合繪製精靈而不是規則的矩形點陣圖,所以這裡面還存在著透明色的判斷,如果是雙點處理,這一步不易實現。(不過也不是沒有好的方法,就是程式碼的長度就長而複雜了) 而MMX卻提供了8個暫存器,同時有分組比較的指令,正好彌補了這兩點不足,而且利用暫存器有64位的優勢可以同時運算4個點。所以我們暫且只用MMX來實現新的想法。(如果你對這個方法用在傳統指令集上有興趣,希望同時操作2個點進行Alpha混合,並寫出實際的程式碼,請和我聯絡,我非常希望看到風魂的非MMX Alpha混合版本能夠進一步最佳化) 用MMX來做這項工作,原理差不多(相當簡單不是?),也是讀入源點和目標點後分離成4個資料放在4個暫存器中。兩對間進行Alpha混合,(這樣6個色素)最後就兩對資料混合的結果合併。不過從現在開始我們就要面對MMX 8個暫存器不夠用的困境了。MMX指令不能和64位立即常數一起使用,所以在進行分裂操作的時候用到的掩碼要常駐在暫存器內。 如果暫存器足夠多的話,可以連掩碼的反值也放一個,可惜現在不能這麼浪費。處理透明色問題方面,可以先將點和透明色比較得到一個掩碼,我們再將混合後的點,及原來的目標圖上的點(這個點應當保留一個備份,哎,又去了一個暫存器)分別與掩碼邏輯運算合併得到最終的資料寫入目標圖。這裡,需要大量運用的NOT操作,Intel竟然沒有在MMX指令集中提供。我們只好用PANDN(取反再與操作)間接完成。(例:可以先用PCMPEQW mm0,mm0(自己和自己比較當然全相等了)生成常數FFFFFFFFFFFFFFFF,用PANDN mm1,mm0就可以將mm1取反。)這裡,不再可以利用MMX的分組乘法,(MMX不能對32位數進行乘法操作)所以我們應該用移位和加減法來實現。這樣,如果有幾級Alpha值,就應該寫幾個混合函式。最後建立一個函式指標陣列,將每級Alpha混合函式依次放入陣列。我們在呼叫時就可以根據需要的Alpha值來呼叫相應的函式了。 在風魂0.07裡,Alpha混合又一次修改了演算法,(0.06使用的上述演算法,0.07 則沒有)這裡要感謝網友T&P的新思路。針對分級數比較少的Alpha混合,比如8級,可以用更簡單的方法。大家可以注意到,50%的 Alpha時,R=(r1+r2)/2,也可以近似的等於r1/2+r2/2。那麼RGB可以方便的同時運算。只需要在移位後做一次簡單的與操作即可(0RRRRRGGGGGGBBBB & 011110111101111 = 0RRRR0GGGGG0BBBB)然後,將兩個移位後的資料相加就完成了Alpha=50%的混合。這個方法避免了切分和還原資料,所以速度更快。風魂的早期版本,對50%的Alpha度就做了此種特殊處理。但是,它是有誤差的,誤差在於移位造成的每色素上1/32或1/64的偏差。 下一步我們可以將50%的Alpha值推廣到25%、12.5%甚至更小。現在來看一下完成R1*25%+R2*75%,它等於R2+R1*25%-R2*25% = R2+R1/4+R2/4。這裡除4的操作和除2原理是一樣的即:(RRRRRGGGGGGBBBBB>>2)&0011100111100111。依次類推,X*37.5%+Y*62.5% = (X+Y)/2+Y/8-X/8等等。我們就只需要利用移位和加減法就可以同時完成N個色素的混合了。 再來看看這個方法的缺陷。首先是誤差問題,每一組移位取與都會造成最大為1/32的誤差,而多次運算有可能使誤差累計,所以alpha級別不能分的太多。而且alpha級別分的太細後,使得運算步驟變的很多,不切分直接運算的優勢有可能損失掉。而且更致命的一點是,如果想用MMX加速,那麼通常AND運算用的掩碼應該放在暫存器中(如果放在記憶體,而MMX不能立即定址,間接定址取記憶體可能不能命中CACHE速度變慢,大規模的混合運算速度損失太多),MMX的暫存器卻只有8個。那麼多個掩碼會使明顯的感覺暫存器不夠用,但這不失為一種好的方法。風魂庫0.07中新的alpha精靈,這一步的演算法更改帶來了10%左右的速度提升,而畫質的損失卻幾乎沒有體現。 最後對關於帶Alpha通道的點陣圖的做一點探討,這裡每一個點將帶有不同的Alpha值,我們應該合理的協調點陣圖的結構。將Alpha值和顏色資訊放在一起是不合算的。這樣不利於高速處理。我們可以將所有點的Alpha值提出來放在一起,對於16位的顏色,合理的Alpha級別應該在16級以下。這樣可以每一個位元組存放兩個Alpha值。用一個暫存器作為指向Alpha值區域的指標,讀入對應點的Alpha值,呼叫相應的混合函式運算。但是,這種點陣圖每個點都有可能是不同的alpha值,如此就不能多點同時運算,雲風找到了另外的加速方法,要知詳情,且看下文分解。 後記 本文提出的方法,都被雲風實踐證明可行,請參閱風魂遊戲程式庫的原始碼。你會發現速度相當的快。測試表明,MMX下帶Alpha混合的點陣圖操作,僅僅比普通的檢查透明色的點陣圖操作慢20%。比不用MMX逐點做Alpha混合快2.7倍。如果採用RLE壓縮掉透明色點,去掉對透明色的特殊處理,速度還會有很大的提高。(達到DirectDraw裡記憶體表面(Surface)間關鍵色檢查的位塊傳送(blit)操作的速度)這個演算法的意義在於,16位色下,軟體Alpha混合的速度已經足夠快,這使遊戲中大量運用光影效果不再有速度上的顧慮。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-952245/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 64K色模式下的快速Alpha混合演算法(轉)模式演算法
- 16位Alpha混合的簡單演算法 (轉)演算法
- MMX Instructions (轉)Struct
- MMX開發文件 (轉)
- 遊戲開發學堂:2D模式下的alpha混合(轉)遊戲開發模式
- yuv 到 32 位 rgb 的 快速轉換演算法基mmx 實現 (轉)演算法
- 利用顏色實現的口令程式(轉)
- 指令集的進步——MMX和SSE (轉)
- 能是最快的演算法alpha blend彙編原始碼 (轉)演算法原始碼
- 檢查CPU是否支援MMX指令的程式碼 (轉)
- RGBa顏色 css3的Alpha通道支援CSSS3
- CSS 顏色混合的N種方式CSS
- Alpha上安裝Linux(轉)Linux
- PS圖層混合演算法之一(不透明度,正片疊底,顏色加深,顏色減淡)演算法
- Shader 中的顏色混合模式(Blend Mode)模式
- 玩轉混合加密加密
- 利用登錄檔最佳化Windows2000(轉)Windows
- dui框架開發系列:32位和565BMP的ALPHA混合和資源打包UI框架
- HexMap學習筆記(二)——單元格顏色混合筆記
- 一文詳解 OpenGL ES 紋理顏色混合
- Mozilla Firefox 2.0 Alpha1 for Linux(轉)FirefoxLinux
- python_pygame_alpha-beta剪枝演算法_玩中國象棋PythonGAM演算法
- 利用Swarmkit構建Windows/Linux混合Docker叢集SwarmWindowsLinuxDocker
- RenderTexture用在RawImage上時要注意的顏色混合問題
- Alpha1
- OpenCV(Alpha通道)OpenCV
- 影象演算法 -- 最全混合圖層演算法(附原始碼)演算法原始碼
- 利用bitmap將圖片部分顏色透明
- 顏色轉換
- 調色原理(轉)
- 05EM演算法-高斯混合模型-GMM演算法模型
- 妙用 CSS 動畫來實現顏色加深、減淡等混合操作CSS動畫
- 顏色空間系列4: RGB和YDbDr顏色空間的轉換及優化演算法優化演算法
- 配置方法數超過 64K 的應用
- 利用CAGradientLayer自定義顏色漸變viewView
- JankStats 推出 alpha 版本
- Alpha-Beta 剪枝
- 影象主題色提取演算法演算法