這次我們的目標(biāo)是: 超越普通的CPU玩家,用CPU的母語來優(yōu)化程序!
實(shí)驗(yàn)器材:VC++ 4.2以上的編譯器或C++ Builder 4.0以上編譯器
MMX技術(shù)到現(xiàn)在來說可以算是基本大眾化了,目前大多數(shù)個(gè)人電腦都應(yīng)該能支持它。P55C,K6,PII,PIII...按照慣例,Intel公司將在以后的x86版本永遠(yuǎn)支持它。
要了解MMX指令體系,請一定瀏覽以下URL,獲得系統(tǒng)的MMX體系知識:
http://www.game1st.com/database/mmxd/mmxd.htm
否則將會(huì)對我的講解摸不著北,(象聽最優(yōu)控制或者線性控制理論一樣)
提示:最好自己多寫些Console App來實(shí)驗(yàn)和熟悉MMX指令特性,cout出結(jié)果,不要一來就搞Windows App.
MMX技術(shù)的優(yōu)點(diǎn)是什么?
一言蔽之,就是一個(gè)指令操作多個(gè)整型數(shù)據(jù).并且可以自動(dòng)完成飽和運(yùn)算。
MMX最適合的應(yīng)用領(lǐng)域是數(shù)字圖象處理
,然后是語音,通訊等領(lǐng)域。
寫圖象處理算法時(shí)很影響效率的以下幾點(diǎn)是:
1.不厭其煩的低效鄰域操作: 不厭其煩的寫GfxBuffer[i],GfxBuffer[i+1],GfxBuffer[i+2],...取RGB值等。
2.惱人的環(huán)繞:
像素運(yùn)算溢出,必須拿個(gè)大點(diǎn)的數(shù)據(jù)類型來保存結(jié)果再判斷溢出,否則結(jié)果就是錯(cuò)誤的
short int GfxOut=GfxBuf1[i]+GfxBuf2[i]; ...
if(GfxOut>255)GfxOut=255; if(GfxOut<0)GfxOut=0;
問題是你知道那兩個(gè)判斷回會(huì)生成多少匯編代碼嗎?
3.不必要的高精度: 該死的RGB->YUV運(yùn)算,我們最熟悉的彩色轉(zhuǎn)灰度運(yùn)算: Y=(BYTE)(Red*0.299+Green*0.587+Blue*0.114);
其實(shí)我們關(guān)心的是一個(gè)字節(jié)結(jié)果,誰愿意讓協(xié)處理器做大量運(yùn)算,得到float結(jié)果,還要再轉(zhuǎn)換為byte結(jié)果呢?要知道IEEE浮點(diǎn)轉(zhuǎn)整數(shù)可不象在C程序里看起來那么簡單!(在你為51單片機(jī)這種低級的劣質(zhì)的沒有協(xié)處理器的CPU寫過程序就知道了...)代價(jià)是相當(dāng)大的。
尤其圖面比較大的情況下,你會(huì)在屏幕面前等得生霉,我們不要那么高的精度啊。
而MMX技術(shù)就是黑暗中的燈塔,被老板咒罵的程序員的救命稻草,使圖象處理模式識別和神經(jīng)網(wǎng)絡(luò)專業(yè)方向的研究生不被導(dǎo)師訓(xùn)斥的的葵花寶典...(本人不系Intel中國公司的營銷部經(jīng)理啊..)
以32-bit為例,下面具體講下用簡單的例子講解MMX技術(shù)優(yōu)化北航老王頭提供的Alpha Blend算法:
絕對為本人在某個(gè)深夜所原創(chuàng),不抄襲自任何資料
char *pSrc,*pOvr; { pSrc=pScanline1+j; pOvr=pScanLine2+j; j+=4; .....
假定我們的源像素在pSrc,覆蓋圖Overlay在pOvr,各指向一個(gè)32 bit像素。
( 為什么要以32bit像素?因?yàn)槔虾沼袃赡曜鲎帜豢ǔ绦虻谋尘?電視字幕是32 bit圖文層嘛! )
如果你閱讀了開始我提供的URL文檔,你就清楚,MMX有八個(gè)64bitRegister,叫MM0->MM7,是浮點(diǎn)處理器的別名,也是他們的低64位映象。
__asm{ pxor mm2,mm2 //把MM2清0
mov edx,dword ptr [pSrc] //取32bit像素地址到edx
movd mm0,dword ptr [edx] //把Source像素取到mm0低32bit
mov edx,dword ptr [pOvr]
movd mm1,dword ptr [edx] //把32 bit Overlay像素取到mm1低32bit
punpcklbw mm0,mm2 //Source:8 bit到16 bit以容納結(jié)果,32bit expand to 64 bit
punpcklbw mm1,mm2 //Overlay:8 bit到16 bit以容納結(jié)果.32bit expand to 64 bit
movq mm3,mm1 // 因?yàn)橐肙verlay的Alpha值
punpckhwd mm3,mm3 // 高字移動(dòng)到雙字
punpckhdq mm3,mm3 // 雙字移動(dòng)到四字,現(xiàn)在有八個(gè)像素的Alpha了!
movq mm4,mm0 //Source->mm4
movq mm5,mm1 //Overlay->mm5
psubusw mm4,mm1 //Source-Overlay,飽和減,小于0為0
psubusw mm5,mm0 //Overlay-Source,飽和減,小于0為0
pmullw mm4,mm3 //Alpha * (Source-Overlay)
pmullw mm5,mm3 //Alpha * (Overlay-Source)
psrlw mm4,8 //除以256,now mm4 get the result,(Source-Overlay)<0 部分
psrlw mm5,8 //除以256,now mm5 get the result,(Overlay-Source)>0 部分
paddusw mm0,mm5 //飽和加到原圖象:D=Alpha*(O-S)+S,(Source-Overlay)<0 部分
psubusw mm0,mm4 //飽和加到原圖象D=S-Alpha*(S-O),(Overlay-Source)>0 部分
packuswb mm0,mm0 //緊縮到低32bit
mov edx,dword ptr [pSrc]
movd dword ptr [edx],mm0 //保存結(jié)果
emms ///必要的!Empty MMX Status
} 以上算法和常規(guī)算法比較:
Legend PII 400 With damnble,extremely Slow Sis6326 Video Card: 640*480*32bit bitmap:
Normal algorithm:170-180 ms
This algorithm:Below 40 ms
均包含拷貝內(nèi)存時(shí)間,純處理時(shí)間只要20ms, 就是說如果用DirectX,Blt,BltFast通常比memcpy快很多.就小于40ms了
總結(jié): 反復(fù)使用緊縮移位,緊縮擴(kuò)展,緊縮壓縮指令,并施加飽和運(yùn)算等,是用MMX寫算法的核心。
程序員必須對數(shù)制,內(nèi)存結(jié)構(gòu),定點(diǎn)數(shù)很熟悉才能寫出高效率的MMX加速的子程序。
|