diff options
| author | Brian Paul <brian.paul@tungstengraphics.com> | 2002-04-10 16:32:32 +0000 | 
|---|---|---|
| committer | Brian Paul <brian.paul@tungstengraphics.com> | 2002-04-10 16:32:32 +0000 | 
| commit | 9add9a21d8c51ee4238169265541fa9a40f0a8b0 (patch) | |
| tree | 978d75c2a5b475b19d87348f5e303d54997cfe51 | |
| parent | 0cd8a1ea13f013df8e3fd16793a2a0aea4fed68d (diff) | |
new MMX blend code (Jose Fonseca)
| -rw-r--r-- | src/mesa/swrast/s_blend.c | 8 | ||||
| -rw-r--r-- | src/mesa/x86/mmx_blend.S | 692 | 
2 files changed, 370 insertions, 330 deletions
| diff --git a/src/mesa/swrast/s_blend.c b/src/mesa/swrast/s_blend.c index 3fdb808abf..845709a111 100644 --- a/src/mesa/swrast/s_blend.c +++ b/src/mesa/swrast/s_blend.c @@ -1,4 +1,4 @@ -/* $Id: s_blend.c,v 1.18 2002/04/04 16:53:26 brianp Exp $ */ +/* $Id: s_blend.c,v 1.19 2002/04/10 16:32:32 brianp Exp $ */  /*   * Mesa 3-D graphics library @@ -646,10 +646,8 @@ void _swrast_choose_blend_func( GLcontext *ctx )        SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;     }     else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA -            && dstRGB==GL_ONE_MINUS_SRC_ALPHA) -   { -      /* XXX It looks like the MMX blend code is broken.  Disable for now. */ -#if 0 && defined(USE_MMX_ASM) +            && dstRGB==GL_ONE_MINUS_SRC_ALPHA) { +#if defined(USE_MMX_ASM)        if ( cpu_has_mmx ) {           SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency;        } diff --git a/src/mesa/x86/mmx_blend.S b/src/mesa/x86/mmx_blend.S index c2be6812ec..caf1f17ba4 100644 --- a/src/mesa/x86/mmx_blend.S +++ b/src/mesa/x86/mmx_blend.S @@ -1,8 +1,69 @@ +/* + * Written by José Fonseca <j_r_fonseca@yahoo.co.uk> + */ +  #include "matypes.h" +/* + * make the following approximation to the division (Sree) + * + *   rgb*a/255 ~= (rgb*(a+1)) >> 256 + * + * which is the fastest method that satisfies the following OpenGL criteria + * + *   0*0 = 0 and 255*255 = 255 + * + * note this one should be used alone + */ +#define GMBT_ALPHA_PLUS_ONE	0 -SEG_TEXT +/* + * take the geometric series approximation to the division + * + *   t/255 = (t >> 8) + (t >> 16) + (t >> 24) .. + * + * in this case just the first two terms to fit in 16bit arithmetic + * + *   t/255 ~= (t + (t >> 8)) >> 8 + * + * note that just by itself it doesn't satisfies the OpenGL criteria, as 255*255 = 254,  + * so the special case a = 255 must be accounted or roundoff must be used + */ +#define GMBT_GEOMETRIC_SERIES	1 + +/* + * when using a geometric series division instead of truncating the result  + * use roundoff in the approximation (Jim Blinn) + * + *   t = rgb*a + 0x80 + * + * achieving the exact results + */ +#define GMBT_ROUNDOFF		1 + +/* + * do + * + *   s = (q - p)*a + q + * + * instead of + * + *   s = p*a + q*(1-a) + * + * this eliminates a multiply at the expense of + * complicating the roundoff but is generally worth it + */ +#define GMBT_SIGNED_ARITHMETIC	1 +#if GMBT_ROUNDOFF +    SEG_DATA + +ALIGNDATA8 +const_80: +	D_LONG 0x00800080, 0x00800080 +#endif  + +   SEG_TEXT  ALIGNTEXT16  GLOBL GLNAME(_mesa_mmx_blend_transparency) @@ -17,344 +78,325 @@ GLOBL GLNAME(_mesa_mmx_blend_transparency)   * Common transparency blending mode.   */  GLNAME( _mesa_mmx_blend_transparency ): -    PUSH_L    ( EBP ) -    MOV_L     ( ESP, EBP ) -    SUB_L     ( CONST(52), ESP ) -    PUSH_L    ( EBX ) -    MOV_L     ( CONST(16711680), REGOFF(-8, EBP) ) -    MOV_L     ( CONST(16711680), REGOFF(-4, EBP) ) -    MOV_L     ( CONST(0), REGOFF(-16, EBP) ) -    MOV_L     ( CONST(-1), REGOFF(-12, EBP) ) -    MOV_L     ( CONST(-1), REGOFF(-24, EBP) ) -    MOV_L     ( CONST(0), REGOFF(-20, EBP) ) -    MOV_L     ( REGOFF(24, EBP), EAX )		/* rgba */ -    ADD_L     ( CONST(4), EAX ) -    MOV_L     ( EAX, EDX ) -    AND_L     ( REGOFF(20, EBP), EDX )		/* mask */ -    MOV_L     ( EDX, EAX ) -    AND_L     ( CONST(4), EAX ) -    CMP_L     ( CONST(8), EAX ) -    JNE       ( LLBL(GMBT_skip_runin) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    ADD_L     ( CONST(3), EAX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(EAX), DL ) -    MOV_L     ( EDX, REGOFF(-32, EBP) ) -    MOV_L     ( CONST(255), EAX ) -    MOV_L     ( EAX, EBX ) -    SUB_L     ( REGOFF(-32, EBP), EBX ) -    MOV_L     ( EBX, REGOFF(-36, EBP) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(EAX), DL ) -    MOV_L     ( EDX, EAX ) -    IMUL_L    ( REGOFF(-32, EBP), EAX ) -    MOV_L     ( REGOFF(24, EBP), EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EDX ) -    IMUL_L    ( REGOFF(-36, EBP), EDX ) -    ADD_L     ( EDX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-40, EBP) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    INC_L     ( EAX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(EAX), DL ) -    MOV_L     ( EDX, EAX ) -    IMUL_L    ( REGOFF(-32, EBP), EAX ) -    MOV_L     ( REGOFF(24, EBP), EDX ) -    INC_L     ( EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EDX ) -    IMUL_L    ( REGOFF(-36, EBP), EDX ) -    ADD_L     ( EDX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-44, EBP) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    ADD_L     ( CONST(2), EAX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(EAX), DL ) -    MOV_L     ( EDX, EAX ) -    IMUL_L    ( REGOFF(-32, EBP), EAX ) -    MOV_L     ( REGOFF(24, EBP), EDX ) -    ADD_L     ( CONST(2), EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EDX ) -    IMUL_L    ( REGOFF(-36, EBP), EDX ) -    ADD_L     ( EDX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-48, EBP) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    ADD_L     ( CONST(3), EAX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(EAX), DL ) -    MOV_L     ( EDX, EAX ) -    IMUL_L    ( REGOFF(-32, EBP), EAX ) -    MOV_L     ( REGOFF(24, EBP), EDX ) -    ADD_L     ( CONST(3), EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EDX ) -    IMUL_L    ( REGOFF(-36, EBP), EDX ) -    ADD_L     ( EDX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-52, EBP) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    MOV_B     ( REGOFF(-40, EBP), DL ) -    MOV_B     ( DL, REGIND(EAX) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    INC_L     ( EAX ) -    MOV_B     ( REGOFF(-44, EBP), DL ) -    MOV_B     ( DL, REGIND(EAX) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    ADD_L     ( CONST(2), EAX ) -    MOV_B     ( REGOFF(-48, EBP), DL ) -    MOV_B     ( DL, REGIND(EAX) ) -    MOV_L     ( REGOFF(20, EBP), EAX ) -    ADD_L     ( CONST(3), EAX ) -    MOV_B     ( REGOFF(-52, EBP), DL ) -    MOV_B     ( DL, REGIND(EAX) ) -    INC_L     ( REGOFF(16, EBP) ) -    ADD_L     ( CONST(4), REGOFF(20, EBP) ) -    ADD_L     ( CONST(4), REGOFF(24, EBP) ) -    DEC_L     ( REGOFF(12, EBP) ) +    PUSH_L     ( EBP ) +    MOV_L      ( ESP, EBP ) +    PUSH_L     ( ESI ) +    PUSH_L     ( EDI ) +    PUSH_L     ( EBX ) -LLBL (GMBT_skip_runin): +    MOV_L      ( REGOFF(12, EBP), ECX )		/* n */ +    CMP_L      ( CONST(0), ECX) +    JE         ( LLBL (GMBT_return) ) -    CMP_L     ( CONST(0), REGOFF(12, EBP) )	/* n == 0 */ -    JE        ( LLBL(GMBT_runout) ) -    MOV_L     ( CONST(0), REGOFF(-28, EBP) )	 +    MOV_L      ( REGOFF(16, EBP), EBX )		/* mask */ +    MOV_L      ( REGOFF(20, EBP), EDI )         /* rgba */ +    MOV_L      ( REGOFF(24, EBP), ESI )         /* dest */ +     +    TEST_L     ( CONST(4), EDI )		/* align rgba on an 8-byte boundary */ +    JZ         ( LLBL (GMBT_align_end) ) -ALIGNTEXT4 -LLBL (GMBT_main_loop): +    CMP_B      ( CONST(0), REGIND(EBX) )	/* *mask == 0 */ +    JE         ( LLBL (GMBT_align_continue) ) -    MOV_L     ( REGOFF(12, EBP), EDX ) -    MOV_L     ( EDX, EAX ) -    SHR_L     ( CONST(1), EAX )			/* eax = n/2 */ -    CMP_L     ( EAX, REGOFF(-28, EBP) ) -    JB        ( LLBL(GMBT_no_jump) ) -    JMP       ( LLBL(GMBT_end_loop) ) +    PXOR       ( MM0, MM0 )			/*   0x0000  |   0x0000  |   0x0000  |   0x0000  */ -ALIGNTEXT16 -LLBL (GMBT_no_jump): +    MOVD       ( REGIND(ESI), MM1 )		/*     |     |     |     | qa1 | qb1 | qg1 | qr1 */ +    MOVD       ( REGIND(EDI), MM2 )		/*     |     |     |     | pa1 | pb1 | pg1 | pr1 */ + +    PUNPCKLBW  ( MM0, MM1 )			/*    qa1    |    qb1    |    qg1    |    qr1    */ +    PUNPCKLBW  ( MM0, MM2 )			/*    pa1    |    pb1    |    pg1    |    pr1    */ + +    MOVQ       ( MM2, MM3 ) + +    PUNPCKHWD  ( MM3, MM3 )			/*    pa1    |    pa1    |           |           */ +    PUNPCKHDQ  ( MM3, MM3 )                     /*    pa1    |    pa1    |    pa1    |    pa1    */ + +#if GMBT_ALPHA_PLUS_ONE +    PCMPEQW    ( MM4, MM4 )			/*   0xffff  |   0xffff  |   0xffff  |   0xffff  */ + +    PSUBW      ( MM4, MM3 )                     /*   pa1 + 1 |   pa1 + 1 |   pa1 + 1 |   pa1 + 1 */ +#endif + +#if GMBT_SIGNED_ARITHMETIC +    PSUBW      ( MM1, MM2 )                     /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ + +    PSLLW      ( CONST(8), MM1 )		/*                    q1 << 8                    */ + +#if GMBT_ROUNDOFF +    MOVQ       ( MM2, MM4 ) +#endif + +    PMULLW     ( MM3, MM2 )			/*              t1 = (q1 - p1)*pa1               */ -    MOV_L     ( REGOFF(-28, EBP), EAX )		/* eax = i */ -    LEA_L     ( REGDIS(0,EAX,2), EDX )		/* edx = i*2 */ -    MOV_L     ( REGOFF(16, EBP), EAX )		/* eax = mask */ -    CMP_W     ( CONST(0), REGBI(EAX,EDX) )	/* ((unsigned *) mask)[i] == 0 */ -    JE        ( LLBL(GMBT_masked) ) -    MOV_L     ( REGOFF(-28, EBP), EAX )		/* eax = i */ -    MOV_L     ( EAX, EDX ) -    LEA_L     ( REGDIS(0,EDX,8), ECX )		/* ecx = i*8 */ -    MOV_L     ( ECX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX )		 -    MOV_L     ( REGOFF(-28, EBP), EDX ) -    MOV_L     ( EDX, ECX ) -    LEA_L     ( REGDIS(0,ECX,8), EDX ) -    MOV_L     ( EDX, ECX ) -    ADD_L     ( REGOFF(24, EBP), ECX ) +#if GMBT_ROUNDOFF +    PSRLW      ( CONST(15), MM4 )		/*                 q1 > p1 ? 1 : 0               */ -    MOVQ      ( REGIND(EAX), MM4 ) -    PXOR      ( MM5, MM5 )			/* mm5 = 00 00 00 00 00 00 00 00 */ -    MOVQ      ( MM4, MM1 ) -    MOVQ      ( REGIND(ECX), MM7 ) -    PUNPCKLBW ( MM5, MM1 ) -    MOVQ      ( MM7, MM6 ) -    MOVQ      ( MM1, MM0 ) -    PUNPCKLBW ( MM5, MM6 ) -    MOVQ      ( MM1, MM2 ) -    PSRLQ     ( CONST(48), MM0 ) -    PUNPCKHBW ( MM5, MM4 ) -    PACKSSDW  ( MM0, MM0 ) -    MOVQ      ( MM0, MM3 ) -    PUNPCKHBW ( MM5, MM7 ) -    PSLLQ     ( CONST(16), MM3 ) -    POR       ( REGOFF(-8, EBP), MM0 ) -    PUNPCKLWD ( MM6, MM1 ) -    PSUBW     ( MM3, MM0 ) -    PUNPCKHWD ( MM6, MM2 ) -    MOVQ      ( MM4, MM3 ) -    PSRLQ     ( CONST(48), MM3 ) -    PACKSSDW  ( MM3, MM3 ) -    MOVQ      ( MM3, MM6 ) -    POR       ( REGOFF(-8, EBP), MM3 ) -    PSLLQ     ( CONST(16), MM6 ) -    PSUBW     ( MM6, MM3 ) -    MOVQ      ( MM4, MM5 ) -    PUNPCKLWD ( MM7, MM4 ) -    PUNPCKHWD ( MM7, MM5 ) -    PMADDWD   ( MM0, MM1 ) -    PMADDWD   ( MM3, MM4 ) -    PMADDWD   ( MM0, MM2 ) -    PMADDWD   ( MM3, MM5 ) -    PSRLD     ( CONST(8), MM1 ) -    PSRLD     ( CONST(8), MM2 ) -    PSRLD     ( CONST(8), MM4 ) -    PACKSSDW  ( MM2, MM1 ) -    PSRLD     ( CONST(8), MM5 ) -    PACKUSWB  ( MM1, MM1 ) -    PACKSSDW  ( MM5, MM4 ) -    PAND      ( REGOFF(-24, EBP), MM1 ) -    PACKUSWB  ( MM4, MM4 ) -    PAND      ( REGOFF(-16, EBP), MM4 ) -    POR       ( MM1, MM4 ) -    MOVQ      ( MM4, REGIND(EAX) ) +    PSLLW      ( CONST(8), MM4 )		/*             q1 > p1 ? 0x100 : 0               */ -LLBL (GMBT_masked): +    PSUBW      ( MM4, MM2 )                     /*                  t1 -=? 0x100                 */ +#endif -    INC_L     ( REGOFF(-28, EBP) ) -    JMP       ( LLBL(GMBT_main_loop) ) +#else +    PCMPEQW    ( MM4, MM4 )			/*   0xffff  |   0xffff  |   0xffff  |   0xffff  */ +    PUNPCKLBW  ( MM0, MM4 )			/*   0x00ff  |   0x00ff  |   0x00ff  |   0x00ff  */ +    MOVQ       ( MM4, MM0 ) +     +    PMULLW     ( MM3, MM2 )			/*                     p1*pa1                    */ + +    PSUBW      ( MM3, MM0 )			/* 255 - pa1 | 255 - pa1 | 255 - pa1 | 255 - pa1 */ + +    PMULLW     ( MM0, MM1 )			/*                  q1*(255 - pa1)               */ + +    PADDW      ( MM1, MM2 )			/*           t1 = p1*pa1 + q1*(255 - pa1)        */ +#endif + +#if GMBT_ROUNDOFF +    MOVQ       ( CONTENT(const_80), MM4 ) + +    PADDW      ( MM4, MM2 )                     /*                 t1 += 0x80                    */ +#endif + +#if GMBT_GEOMETRIC_SERIES +    MOVQ       ( MM2, MM3 ) + +    PSRLW      ( CONST(8), MM3 )		/*                    t1 >> 8                    */ + +    PADDW      ( MM3, MM2 )			/*        t1 + (t1 >> 8) ~= (t1/255) << 8        */ +#endif + +#if GMBT_SIGNED_ARITHMETIC +    PADDW      ( MM1, MM2 )			/*              (t1/255 + q1) << 8               */ +#endif + +    PSRLW      ( CONST(8), MM2 )		/*    sa1    |    sb1    |    sg1    |    sr1    */ +     +    PACKUSWB   ( MM0, MM2 )			/*     |     |     |     | sa1 | sb1 | sg1 | sr1 */ +    MOVD       ( MM2, REGIND(EDI) ) + +LLBL (GMBT_align_continue): + +    DEC_L      ( ECX )				/* n -= 1 */ +    INC_L      ( EBX )		                /* mask += 1 */ +    ADD_L      ( CONST(4), EDI )		/* rgba += 1 */ +    ADD_L      ( CONST(4), ESI )		/* dest += 1 */  + +LLBL (GMBT_align_end): + +    CMP_L      ( CONST(2), ECX) +    JB         ( LLBL (GMBT_loop_end) )  ALIGNTEXT16 -LLBL (GMBT_end_loop): -    EMMS +LLBL (GMBT_loop_begin): + +    CMP_W      ( CONST(0), REGIND(EBX) )	/* *mask == 0 && *(mask + 1) == 0 */ +    JE         ( LLBL (GMBT_loop_continue) ) + +    /* NOTE: the instruction pairing when multiple pipelines are available must be checked */ + +    PXOR       ( MM0, MM0 )			/*   0x0000  |   0x0000  |   0x0000  |   0x0000  */ + +    MOVQ       ( REGIND(ESI), MM7 )		/* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */ +    MOVQ       ( REGIND(EDI), MM6 )		/* pa2 | pb2 | pg2 | pr2 | pa1 | pb1 | pg1 | pr1 */ + +    MOVQ       ( MM7, MM1 ) +    MOVQ       ( MM6, MM2 ) + +    PUNPCKLBW  ( MM0, MM1 )			/*    qa1    |    qb1    |    qg1    |    qr1    */ +    PUNPCKHBW  ( MM0, MM7 )                     /*    qa2    |    qb2    |    qg2    |    qr2    */ +    PUNPCKLBW  ( MM0, MM2 )			/*    pa1    |    pb1    |    pg1    |    pr1    */ +    PUNPCKHBW  ( MM0, MM6 )                     /*    pa2    |    pb2    |    pg2    |    pr2    */ + +    MOVQ       ( MM2, MM3 ) +    MOVQ       ( MM6, MM5 ) + +    PUNPCKHWD  ( MM3, MM3 )			/*    pa1    |    pa1    |           |           */ +    PUNPCKHWD  ( MM5, MM5 )			/*    pa2    |    pa2    |           |           */ +    PUNPCKHDQ  ( MM3, MM3 )                     /*    pa1    |    pa1    |    pa1    |    pa1    */ +    PUNPCKHDQ  ( MM5, MM5 )                     /*    pa2    |    pa2    |    pa2    |    pa2    */ + +#if GMBT_ALPHA_PLUS_ONE +    PCMPEQW    ( MM4, MM4 )			/*   0xffff  |   0xffff  |   0xffff  |   0xffff  */ + +    PSUBW      ( MM4, MM3 )                     /*   pa1 + 1 |   pa1 + 1 |   pa1 + 1 |   pa1 + 1 */ +    PSUBW      ( MM4, MM5 )                     /*   pa2 + 1 |   pa2 + 1 |   pa2 + 1 |   pa2 + 1 */ +#endif -LLBL (GMBT_runout): +#if GMBT_SIGNED_ARITHMETIC +    PSUBW      ( MM1, MM2 )                     /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ +    PSUBW      ( MM7, MM6 )                     /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ -    MOV_L     ( REGOFF(12, EBP), EAX ) -    AND_L     ( CONST(1), EAX ) -    TEST_L    ( EAX, EAX ) -    JE        ( LLBL(GMBT_skip_runout) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-1, EAX), EDX ) -    XOR_L     ( EAX, EAX ) -    MOV_B     ( REGIND(EDX), AL ) -    MOV_L     ( EAX, REGOFF(-52, EBP) ) -    MOV_L     ( CONST(255), EAX ) -    MOV_L     ( EAX, EBX ) -    SUB_L     ( REGOFF(-52, EBP), EBX ) -    MOV_L     ( EBX, REGOFF(-48, EBP) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-4, EAX), EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EAX ) -    IMUL_L    ( REGOFF(-52, EBP), EAX ) -    MOV_L     ( REGOFF(12, EBP), EDX ) -    LEA_L     ( REGDIS(0,EDX,4), ECX ) -    MOV_L     ( ECX, EDX ) -    ADD_L     ( REGOFF(24, EBP), EDX ) -    LEA_L     ( REGOFF(-4, EDX), ECX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(ECX), DL ) -    MOV_L     ( EDX, ECX ) -    IMUL_L    ( REGOFF(-48, EBP), ECX ) -    ADD_L     ( ECX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-44, EBP) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-3, EAX), EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EAX ) -    IMUL_L    ( REGOFF(-52, EBP), EAX ) -    MOV_L     ( REGOFF(12, EBP), EDX ) -    LEA_L     ( REGDIS(0,EDX,4), ECX ) -    MOV_L     ( ECX, EDX ) -    ADD_L     ( REGOFF(24, EBP), EDX ) -    LEA_L     ( REGOFF(-3, EDX), ECX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(ECX), DL ) -    MOV_L     ( EDX, ECX ) -    IMUL_L    ( REGOFF(-48, EBP), ECX ) -    ADD_L     ( ECX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-40, EBP) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-2, EAX), EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EAX ) -    IMUL_L    ( REGOFF(-52, EBP), EAX ) -    MOV_L     ( REGOFF(12, EBP), EDX ) -    LEA_L     ( REGDIS(0,EDX,4), ECX ) -    MOV_L     ( ECX, EDX ) -    ADD_L     ( REGOFF(24, EBP), EDX ) -    LEA_L     ( REGOFF(-2, EDX), ECX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(ECX), DL ) -    MOV_L     ( EDX, ECX ) -    IMUL_L    ( REGOFF(-48, EBP), ECX ) -    ADD_L     ( ECX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-36, EBP) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-1, EAX), EDX ) -    XOR_L     ( ECX, ECX ) -    MOV_B     ( REGIND(EDX), CL ) -    MOV_L     ( ECX, EAX ) -    IMUL_L    ( REGOFF(-52, EBP), EAX ) -    MOV_L     ( REGOFF(12, EBP), EDX ) -    LEA_L     ( REGDIS(0,EDX,4), ECX ) -    MOV_L     ( ECX, EDX ) -    ADD_L     ( REGOFF(24, EBP), EDX ) -    LEA_L     ( REGOFF(-1, EDX), ECX ) -    XOR_L     ( EDX, EDX ) -    MOV_B     ( REGIND(ECX), DL ) -    MOV_L     ( EDX, ECX ) -    IMUL_L    ( REGOFF(-48, EBP), ECX ) -    ADD_L     ( ECX, EAX ) -    MOV_L     ( EAX, EBX ) -    SAR_L     ( CONST(8), EBX ) -    MOV_L     ( EBX, REGOFF(-32, EBP) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-4, EAX), EDX ) -    MOV_B     ( REGOFF(-44, EBP), AL ) -    MOV_B     ( AL, REGIND(EDX) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-3, EAX), EDX ) -    MOV_B     ( REGOFF(-40, EBP), AL ) -    MOV_B     ( AL, REGIND(EDX) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-2, EAX), EDX ) -    MOV_B     ( REGOFF(-36, EBP), AL ) -    MOV_B     ( AL, REGIND(EDX) ) -    MOV_L     ( REGOFF(12, EBP), EAX ) -    LEA_L     ( REGDIS(0,EAX,4), EDX ) -    MOV_L     ( EDX, EAX ) -    ADD_L     ( REGOFF(20, EBP), EAX ) -    LEA_L     ( REGOFF(-1, EAX), EDX ) -    MOV_B     ( REGOFF(-32, EBP), AL ) -    MOV_B     ( AL, REGIND(EDX) ) +    PSLLW      ( CONST(8), MM1 )		/*                    q1 << 8                    */ +    PSLLW      ( CONST(8), MM7 )		/*                    q2 << 8                    */ + +#if GMBT_ROUNDOFF +    MOVQ       ( MM2, MM0 ) +    MOVQ       ( MM6, MM4 ) +#endif + +    PMULLW     ( MM3, MM2 )			/*              t1 = (q1 - p1)*pa1               */ +    PMULLW     ( MM5, MM6 )			/*              t2 = (q2 - p2)*pa2               */ + +#if GMBT_ROUNDOFF +    PSRLW      ( CONST(15), MM0 )		/*                 q1 > p1 ? 1 : 0               */ +    PSRLW      ( CONST(15), MM4 )		/*                 q2 > q2 ? 1 : 0               */ + +    PSLLW      ( CONST(8), MM0 )		/*             q1 > p1 ? 0x100 : 0               */ +    PSLLW      ( CONST(8), MM4 )		/*             q2 > q2 ? 0x100 : 0               */ + +    PSUBW      ( MM0, MM2 )                     /*                  t1 -=? 0x100                 */ +    PSUBW      ( MM4, MM7 )                     /*                  t2 -=? 0x100                 */  +#endif + +#else +    PCMPEQW    ( MM4, MM4 )			/*   0xffff  |   0xffff  |   0xffff  |   0xffff  */ +    PUNPCKLBW  ( MM0, MM4 )			/*   0x00ff  |   0x00ff  |   0x00ff  |   0x00ff  */ +    MOVQ       ( MM4, MM0 ) +     +    PMULLW     ( MM3, MM2 )			/*                     p1*pa1                    */ +    PMULLW     ( MM5, MM6 )			/*                     p2*pa2                    */ + +    PSUBW      ( MM3, MM0 )			/* 255 - pa1 | 255 - pa1 | 255 - pa1 | 255 - pa1 */ +    PSUBW      ( MM5, MM4 )			/* 255 - pa2 | 255 - pa2 | 255 - pa2 | 255 - pa2 */ + +    PMULLW     ( MM0, MM1 )			/*                  q1*(255 - pa1)               */ +    PMULLW     ( MM4, MM7 )			/*                  q2*(255 - pa2)               */ + +    PADDW      ( MM1, MM2 )			/*           t1 = p1*pa1 + q1*(255 - pa1)        */ +    PADDW      ( MM7, MM6 )			/*           t2 = p2*pa2 + q2*(255 - pa2)        */ +#endif + +#if GMBT_ROUNDOFF +    MOVQ       ( CONTENT(const_80), MM4 ) + +    PADDW      ( MM4, MM2 )                     /*                 t1 += 0x80                    */ +    PADDW      ( MM4, MM6 )                     /*                 t2 += 0x80                    */ +#endif + +#if GMBT_GEOMETRIC_SERIES +    MOVQ       ( MM2, MM3 ) +    MOVQ       ( MM6, MM5 ) + +    PSRLW      ( CONST(8), MM3 )		/*                    t1 >> 8                    */ +    PSRLW      ( CONST(8), MM5 )		/*                    t2 >> 8                    */ + +    PADDW      ( MM3, MM2 )			/*        t1 + (t1 >> 8) ~= (t1/255) << 8        */ +    PADDW      ( MM5, MM6 )			/*        t2 + (t2 >> 8) ~= (t2/255) << 8        */ +#endif + +#if GMBT_SIGNED_ARITHMETIC +    PADDW      ( MM1, MM2 )			/*              (t1/255 + q1) << 8               */ +    PADDW      ( MM7, MM6 )			/*              (t2/255 + q2) << 8               */ +#endif + +    PSRLW      ( CONST(8), MM2 )		/*    sa1    |    sb1    |    sg1    |    sr1    */ +    PSRLW      ( CONST(8), MM6 )		/*    sa2    |    sb2    |    sg2    |    sr2    */ +     +    PACKUSWB   ( MM6, MM2 )			/* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ +    MOVQ       ( MM2, REGIND(EDI) ) + +LLBL (GMBT_loop_continue): + +    DEC_L      ( ECX ) +    DEC_L      ( ECX )				/* n -= 2 */ +    ADD_L      ( CONST(2), EBX )		/* mask += 2 */ +    ADD_L      ( CONST(8), EDI )		/* rgba += 2 */ +    ADD_L      ( CONST(8), ESI )		/* dest += 2 */  +    CMP_L      ( CONST(2), ECX ) +    JAE        ( LLBL (GMBT_loop_begin) ) + +LLBL (GMBT_loop_end): + +    CMP_L      ( CONST(1), ECX ) +    JB         ( LLBL (GMBT_done) ) + +    CMP_B      ( CONST(0), REGIND(EBX) )	/* *mask == 0 */ +    JE         ( LLBL (GMBT_done) ) + +    PXOR       ( MM0, MM0 )			/*   0x0000  |   0x0000  |   0x0000  |   0x0000  */ + +    MOVD       ( REGIND(ESI), MM1 )		/*     |     |     |     | qa1 | qb1 | qg1 | qr1 */ +    MOVD       ( REGIND(EDI), MM2 )		/*     |     |     |     | pa1 | pb1 | pg1 | pr1 */ + +    PUNPCKLBW  ( MM0, MM1 )			/*    qa1    |    qb1    |    qg1    |    qr1    */ +    PUNPCKLBW  ( MM0, MM2 )			/*    pa1    |    pb1    |    pg1    |    pr1    */ + +    MOVQ       ( MM2, MM3 ) + +    PUNPCKHWD  ( MM3, MM3 )			/*    pa1    |    pa1    |           |           */ +    PUNPCKHDQ  ( MM3, MM3 )                     /*    pa1    |    pa1    |    pa1    |    pa1    */ + +#if GMBT_ALPHA_PLUS_ONE +    PCMPEQW    ( MM4, MM4 )			/*   0xffff  |   0xffff  |   0xffff  |   0xffff  */ + +    PSUBW      ( MM4, MM3 )                     /*   pa1 + 1 |   pa1 + 1 |   pa1 + 1 |   pa1 + 1 */ +#endif + +#if GMBT_SIGNED_ARITHMETIC +    PSUBW      ( MM1, MM2 )                     /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ + +    PSLLW      ( CONST(8), MM1 )		/*                    q1 << 8                    */ + +#if GMBT_ROUNDOFF +    MOVQ       ( MM2, MM4 ) +#endif + +    PMULLW     ( MM3, MM2 )			/*              t1 = (q1 - p1)*pa1               */ + +#if GMBT_ROUNDOFF +    PSRLW      ( CONST(15), MM4 )		/*                 q1 > p1 ? 1 : 0               */ + +    PSLLW      ( CONST(8), MM4 )		/*             q1 > p1 ? 0x100 : 0               */ + +    PSUBW      ( MM4, MM2 )                     /*                  t1 -=? 0x100                 */ +#endif + +#else +    PCMPEQW    ( MM4, MM4 )			/*   0xffff  |   0xffff  |   0xffff  |   0xffff  */ +    PUNPCKLBW  ( MM0, MM4 )			/*   0x00ff  |   0x00ff  |   0x00ff  |   0x00ff  */ +    MOVQ       ( MM4, MM0 ) +     +    PMULLW     ( MM3, MM2 )			/*                     p1*pa1                    */ + +    PSUBW      ( MM3, MM0 )			/* 255 - pa1 | 255 - pa1 | 255 - pa1 | 255 - pa1 */ + +    PMULLW     ( MM0, MM1 )			/*                  q1*(255 - pa1)               */ + +    PADDW      ( MM1, MM2 )			/*           t1 = p1*pa1 + q1*(255 - pa1)        */ +#endif + +#if GMBT_ROUNDOFF +    MOVQ       ( CONTENT(const_80), MM4 ) + +    PADDW      ( MM4, MM2 )                     /*                 t1 += 0x80                    */ +#endif + +#if GMBT_GEOMETRIC_SERIES +    MOVQ       ( MM2, MM3 ) + +    PSRLW      ( CONST(8), MM3 )		/*                    t1 >> 8                    */ + +    PADDW      ( MM3, MM2 )			/*        t1 + (t1 >> 8) ~= (t1/255) << 8        */ +#endif + +#if GMBT_SIGNED_ARITHMETIC +    PADDW      ( MM1, MM2 )			/*              (t1/255 + q1) << 8               */ +#endif + +    PSRLW      ( CONST(8), MM2 )		/*    sa1    |    sb1    |    sg1    |    sr1    */ +     +    PACKUSWB   ( MM0, MM2 )			/*     |     |     |     | sa1 | sb1 | sg1 | sr1 */ +    MOVD       ( MM2, REGIND(EDI) ) + +LLBL (GMBT_done): + +    EMMS -LLBL (GMBT_skip_runout): +LLBL (GMBT_return): -    MOV_L     ( REGOFF(-56, EBP), EBX ) -    MOV_L     ( EBP, ESP ) -    POP_L     ( EBP ) +    POP_L      ( EBX ) +    POP_L      ( EDI ) +    POP_L      ( ESI ) +    MOV_L      ( EBP, ESP ) +    POP_L      ( EBP )      RET | 
