前回予告した通り、今回は64 bit 分のデータを mmx のレジスタを 8 つ( 実際には 7つですが)使って一気に処理する方法を書いてみます。 その処理を素直に書くと下の様になります。 ただし 64bit 分を一回で処理しますので画像のサイズは 8 byte 境界に 合わせなければなりません。
// α合成 MMX で 2+2/3 画素まとめて計算版(64 bit) // ただしサイズが 8 の倍数である必要あり // // コピー先 = コピー元1 * α + コピー元1 * (1-α) // VOID AlphaBlending(LPBYTE lpDest, // コピー先 LPBYTE lpSrc1, // コピー元1 LPBYTE lpSrc2, // コピー元2 DWORD dwLength, // コピーする長さ WORD wAlpha){ // α値 DWORD dwAlpha = (DWORD)wAlpha; DWORD dwAlpha2 = (256 - dwAlpha); _asm{ mov eax,dwLength // eax = カウンタ mov ebx,lpDest // ebx = コピー先アドレス mov ecx,lpSrc1 // ecx = コピー元1 アドレス mov edx,lpSrc2 // edx = コピー元2 アドレス shr eax,3 // eax/=8 movd mm4,dwAlpha // mm4 = 0α0α0α0α punpcklwd mm4,mm4 punpckldq mm4,mm4 movd mm5,dwAlpha2 // mm5 = 0(1-α)0(1-α)0(1-α)0(1-α) punpcklwd mm5,mm5 punpckldq mm5,mm5 pxor mm6,mm6 // mm6 = パック用ダミー = 0 LOOP1: // データ読み込み(64 bit 分) movq mm0,[ecx] movq mm1,[edx] // コピー movq mm2,mm0 movq mm3,mm1 // byte -> word にアンパック punpckhbw mm0,mm6 // High punpckhbw mm1,mm6 punpcklbw mm2,mm6 // Low punpcklbw mm3,mm6 // パック掛け算 pmullw mm0,mm4 pmullw mm1,mm5 pmullw mm2,mm4 pmullw mm3,mm5 // パック足し算して256で割る paddw mm0,mm1 paddw mm2,mm3 psrlw mm0,8 psrlw mm2,8 // word->byte にパックして転送 packuswb mm2,mm0 movq [ebx],mm2 // ポインタアップ add ecx,8 add edx,8 add ebx,8 // カウンタダウンしてループ dec eax jne LOOP1 emms } }さて結果ですが、MMX ペンティアム 150 で 460x320 のビットマップ 2 枚を混合させる計算速度は平均 60 回/秒 になりました。前回は 49 回/秒でしたので速くなったことが分かります。もちろん今回も上のソースは 全く最適化を行っていないので最適化を行えばもう少し速くなると思います。
という訳で MMX を使ってα合成をする方法を書いてきましたが、最終的には 60 回/秒までは計算できるようになりました。ただ 30 FPS 位のゲームならこれ 位の計算速度でも良いと思いますが 60 FPS まで出そうとするときついと思います。 結局、リアルタイムで半透明を実現するには Direct X を使ってビデオボードに やってもらうのが一番てっとりばやいでしょうね(^^;