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; }