2001-08-16 (木)
*MMXで最適化
昨日,MMX化をした部分を最適かできないか見直してみました.まだ,ちょっと高速化できそうです.
movd mm0, [eax] movd mm1, [ebx] punpcklbw mm0, mm3 punpcklbw mm1, mm3 pmullw mm0, mm4 // *=α pmullw mm1, mm5 // *=(255-α) psrlw mm0, 8 // >>=8 psrlw mm1, 8 // >>=8 paddusw mm0, mm1 // +=mm1 packuswb mm0, mm3 movd [edx], mm0
半透明合成用のループの中が上のようになってます.こうすると,Pentiumなら2命令ずつ同時に実行されるみたいですね.加算の後にシフトした方がコードのサイズが小さくなる分いい気がします.あとは,まだMMXレジスタが余ってるので,64ビットずつ処理した方がよさそうです.
void alpha_brend(BMSCR* des,BMSCR* src1, BMSCR* src2, int alpha) { DWORD *d,*s1,*s2; DWORD alpha2; int siz=(des->sx*3*des->sy)&rt;&rt;3; d=(DWORD*)des->pBit; s1=(DWORD*)src1->pBit; s2=(DWORD*)src2->pBit; alpha*=0x01010101; alpha2=~alpha; _asm{ mov eax, s1 mov ebx, s2 mov edx, d mov ecx,siz //ループ用 pxor mm3, mm3 movd mm4, alpha2 movd mm5, alpha punpcklbw mm4, mm3 punpcklbw mm5, mm3 alpha_loop: //読む movq mm0, [eax] movq mm1, [ebx] //コピー movq mm6, mm0 movq mm7, mm1 //下位32bit punpcklbw mm0, mm3 punpcklbw mm1, mm3 pmullw mm0, mm4 pmullw mm1, mm5 paddusw mm0, mm1 psrlw mm0, 8 //上位32bit punpckhbw mm6, mm3 punpckhbw mm7, mm3 pmullw mm6, mm4 pmullw mm7, mm5 paddusw mm6, mm7 psrlw mm6, 8 //書く packuswb mm0, mm6 movq [edx], mm0 add eax,8 add ebx,8 add edx,8 loop alpha_loop emms//END MMX } }
出来上がったのがこれ.一応,Celeron500MHzで640*480*24ビット画像を(表示なしで)65FPSくらいで処理できてます.ちょっと長くなったけど,コンパイル後のコードは200バイト未満だし,そんなでもないだろう….まだ,最適化の余地があるかもしれませんが…例えば,加算後のシフトは別の場所でやればペアリング出来て同時に処理できる気もします….最適化ってはまると抜け出せなくなります(爆).α合成くらい,その辺のサンプルもってくれば手っ取り早そうですが,とりあえず,MMXの勉強ということで(^^;それにしても暫く見ない間にずいぶん便利になってますね.アセンブラには手を出さないつもりでいましたが,このくらいなら楽に高速化できて良いですね(^^;.