前回アセンブラを使ってα合成を行っても平均 11 回/秒 しか計算することが 出来ませんでした。そこで今回は MMX を使ってα合成をやってみる事にします。
その前に簡単に MMX について説明します。MMX の特徴を簡単に言えば
// α合成 MMX 版(32 bit) // // コピー先 = コピー元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,2 // eax/=4 movd mm4,dwAlpha punpcklwd mm4,mm4 punpckldq mm4,mm4 // mm4 = 0α0α0α0α movd mm5,dwAlpha2 punpcklwd mm5,mm5 punpckldq mm5,mm5 // mm5 = 0(1-α)0(1-α)0(1-α)0(1-α) pxor mm6,mm6 // mm6 = パック用ダミー = 0 pxor mm7,mm7 // mm7 = パック用ダミー = 0 LOOP1: // データ読み込み(32 bit) movd mm0,[ecx] movd mm1,[edx] // byte -> word にアンパック punpcklbw mm0,mm6 punpcklbw mm1,mm7 // パック掛け算 pmullw mm0,mm4 pmullw mm1,mm5 // word 単位で足して256で割る paddw mm0,mm1 psrlw mm0,8 // word->byte にパックして転送 packuswb mm0,mm6 movd [ebx],mm0 // カウンタアップ add ecx,4 add edx,4 add ebx,4 dec eax jne LOOP1 emms } }さて結果ですが、MMX ペンティアム 150 で 460x320 のビットマップ 2 枚を混合させる計算速度は平均 49 回/秒 で予想通り 4 倍以上の 計算速度になりました。ついでに高橋名人も越えました(笑)。 もちろん上のソースは全く最適化を 行っていないので最適化を行えばもう少し速くなると思います。
ところで MMX のレジスタは 64 bit なのでメモリからデータを 64 bit 分を一回で読み書きする事が出来るのですが、上では 32 bit分しか 一度に読み書きしていません。また 8 つあるレジスタのうち、6 つしか 使って無いのでちょっと勿体無い感じがします。そこで次回は 64 bit 分のデータをレジスタを 8 つ使って一気に処理する方法を書いてみようと 思います。
(第4回(多分最終回) MMX編(その 2)に続く)