前回アセンブラを使ってα合成を行っても平均 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)に続く)