2013/01/06

アルファブレンドその2

修正版。

__declspec(align(16)) unsigned char alpha_mask[16] = 
{
    0x06, 0x80, 0x06, 0x80, 0x06, 0x80, 0x80, 0x80,
    0x0e, 0x80, 0x0e, 0x80, 0x0e, 0x80, 0x80, 0x80,
};
__declspec(align(16)) unsigned char swap_endian_bl[16] = 
{
    0x80, 0x00, 0x80, 0x02, 0x80, 0x04, 0x80, 0x06,
    0x80, 0x08, 0x80, 0x0a, 0x80, 0x0c, 0x80, 0x0e,
};
__declspec(align(16)) unsigned char swap_endian_lb[16] = 
{
    0x01, 0x80, 0x03, 0x80, 0x05, 0x80, 0x07, 0x80,
    0x09, 0x80, 0x0b, 0x80, 0x0d, 0x80, 0x0f, 0x80,
};
__declspec(align(16)) unsigned int andnot_mask[4] = 
{
    0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00
};

//
// Alpha blending implement optimized with SSE4
//
void alpha_blend_sse4(void* background, void* foreground, int pixels)
{
    int count = pixels / 4;
    __asm 
    {
        mov ecx, count
        mov esi, dword ptr background
        mov edi, dword ptr foreground
        
        movdqa xmm6, dword ptr swap_endian_bl
        movdqa xmm7, dword ptr alpha_mask

L0:
        //-------------------------------------- Get B.rgb
        movdqa xmm0, [esi]    // B.argb
        movhlps xmm1, xmm0

        pmovzxbw xmm2, xmm0 // B.rgb
        pmovzxbw xmm3, xmm1 // B.rgb

        // using: xmm2, xmm3

        //-------------------------------------- Get F.rgb
        movdqa xmm4, [edi] // F.argb
        movhlps xmm5, xmm4

        // escape swap_endian_bl and alpha_mask to xmm0 and xmm1
        movdqa xmm0, xmm6
        movdqa xmm1, xmm7

        pmovzxbw xmm6, xmm4 // F.rgb
        pmovzxbw xmm7, xmm5 // F.rgb

        // using: xmm2, xmm3, xmm6, xmm7

        //-------------------------------------- Get F.a
        movdqa xmm4, xmm6
        movdqa xmm5, xmm7
        pshufb xmm4, xmm1 // F.a   xmm1 = alpha_mask
        pshufb xmm5, xmm1 // F.a
        
        // using: xmm2, xmm3, xmm4, xmm5, xmm6, xmm7

        //-------------------------------------- Flip endianness
        pshufb xmm2, xmm0 // xmm0 = swap_endian_bl
        pshufb xmm3, xmm0
        pshufb xmm4, xmm0
        pshufb xmm5, xmm0
        pshufb xmm6, xmm0
        pshufb xmm7, xmm0

        
        //-------------------------------------- Calc X = F.rgb * F.a
        pmulhuw xmm6, xmm4
        pmulhuw xmm7, xmm5

        //-------------------------------------- Calc Y = 1 - B.a
        pandn xmm4, dword ptr andnot_mask
        pandn xmm5, dword ptr andnot_mask
        
        //-------------------------------------- Calc Z = B.rgb * Y
        pmulhuw xmm4, xmm2
        pmulhuw xmm5, xmm3

        //-------------------------------------- Calc R = X + Z
        paddusw xmm6, xmm4
        paddusw xmm7, xmm5

        //-------------------------------------- Flip endianness
        movdqa xmm2, dword ptr swap_endian_lb
        pshufb xmm6, xmm2
        pshufb xmm7, xmm2

        //-------------------------------------- Pack values
        packuswb xmm6, xmm7

        //-------------------------------------- Write result
        movdqa [esi], xmm6
        
        //-------------------------------------- Restore escaped values
        movdqa xmm6, xmm0
        movdqa xmm7, xmm1
        
        //-------------------------------------- 
        add esi, 16
        add edi, 16
        sub ecx, 1
        jnz L0
    };
}

切り捨てが起こってしまう気がするけど、何枚も重ねないし問題ないぜ!

背景画像
base

前景画像
1

結果
out

コード使いたいという方は MIT ライセンスでどうぞ。

0 件のコメント:

コメントを投稿