2005/10/24(月)MMXでアルファブレンド習作

はてブ数 2005/10/24 12:50 計算機な日記::ソフト作りつーさ

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