2005/10/24(月)MMXでアルファブレンド習作
MMXを用いて 24bppのDIBを24bppのブレンド率マスク画像に従って
24bppのDIBとアルファブレンディングしてみる。
ってか今頃MMXなんて遅すぎるよな。
今頃だから互換性を気にせずにMMX使えるんだけど。
CPUID使って切り分けてもいいけど、さすがにi486は未サポートでいい気がする。
そもそも普通フリーウェアなんて自分のために作るものであって。
で、余談だけど。。
HSPが3になっても結局DIBは24bitのままなのだけど、
DIBは32bppで扱った方がいいんじゃないかなぁ、と思う次第。
確かにメモリ余計に食うデメリットはあっても
メリットの方が大きいと思うんだがにゃー。
MMXを使ったアルファブレンドでもそう。
24bit区切りのデータをQWORDごと処理しようとすると、
Xサイズを8px単位にしないといかんし……。
32bit区切りならXサイズは2px単位でいいし、
プログラムからはとても扱いやすそうな気がするんだけど。
DWORDずつ処理するのなら、24bppでは4px、32bppでは1px単位。
まぁ、人様のライブラリを使わせて頂く以上、文句言っても仕方ないのだけど。
使用式が (src*msk+dst*(255-msk))>>8 だから元画像よりちと暗くなる。
ブレンド率0%を255回繰り返すと真っ黒けになる悪寒w
でもね、でもね。動きのあるシーンならばれないと思うよw
光の処理はほんわかさんの方が綺麗、らしいことをどこかで聞いた。
AddBlendやらSubBlendもMMX使えば結構楽勝ぽ。
以下ソース。
#define DST 0
#define SRC 1
#define MSK 2
typedef struct VRAMSTRUCT{
char* pBit;
int X,Y,W,H;
}VRAMSTRUCT;
int __stdcall AlphaBlend(VRAMSTRUCT *v, int szW, int szH)
{
char* Addr[3]; // DSTとSRCとMSK
int Delt[3];
szW*=3;
const int a[] = {0xff00ff,0xff00ff};
for(int i=0;i<3;i++){ // DSTとSRCとMSK
int scanlinelen = ((v[i].W*3+3)&~3);
Addr[i] = v[i].pBit +
v[i].X*3 +
(v[i].H-szH-v[i].Y)*scanlinelen;
Delt[i] = scanlinelen - szW;
}
_asm{
mov eax,szH
test eax,eax
je END
mov ebx,[Addr+0] // Addr[DST]
mov ecx,[Addr+4] // Addr[SRC]
mov edx,[Addr+8] // Addr[MSK]
LOOP2:
mov eax,szW
shr eax,3
pxor mm7,mm7
LOOP1:
movq mm0,[ebx]
movq mm1,[ecx]
movq mm2,[edx]
movq mm3,mm0
movq mm4,mm1
movq mm5,mm2
punpcklbw mm0,mm7
punpcklbw mm1,mm7
punpcklbw mm2,mm7
punpckhbw mm3,mm7
punpckhbw mm4,mm7
punpckhbw mm5,mm7
movq mm6,[a]
psubw mm6,mm2
pmullw mm1,mm2
pmullw mm0,mm6
movq mm6,[a]
psubw mm6,mm5
pmullw mm4,mm5
pmullw mm3,mm6
paddw mm0,mm1
paddw mm3,mm4
psrlw mm0,8
psrlw mm3,8
packuswb mm0,mm3
movq [ebx], mm0
add ebx,8
add ecx,8
add edx,8
dec eax
jne LOOP1
add ebx,[Delt+0] // Delt[DST]
add ecx,[Delt+4] // Delt[SRC]
add edx,[Delt+8] // Delt[MSK]
mov eax,szH
dec eax
mov szH,eax
jne LOOP2
emms
END:
}
return 0;
}