+ ;
/*
- * Written by José Fonseca <j_r_fonseca@yahoo.co.uk>
+ * Written by Jos� Fonseca <j_r_fonseca@yahoo.co.uk>
*/
+
+#ifdef USE_MMX_ASM
+#include "assyntax.h"
#include "matypes.h"
-/*
- * make the following approximation to the division (Sree)
+/* integer multiplication - alpha plus one
+ *
+ * makes the following approximation to the division (Sree)
*
* rgb*a/255 ~= (rgb*(a+1)) >> 256
*
*
* 0*0 = 0 and 255*255 = 255
*
- * note this one should be used alone
+ * note that MX1 is a register with 0xffffffffffffffff constant which can be easily obtained making
+ *
+ * PCMPEQW ( MX1, MX1 )
*/
-#define GMBT_ALPHA_PLUS_ONE 0
-
-/*
- * take the geometric series approximation to the division
+#define GMB_MULT_AP1( MP1, MA1, MP2, MA2, MX1 ) \
+ PSUBW ( MX1, MA1 ) /* a1 + 1 | a1 + 1 | a1 + 1 | a1 + 1 */ ;\
+ PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\
+ ;\
+TWO(PSUBW ( MX1, MA2 )) /* a2 + 1 | a2 + 1 | a2 + 1 | a2 + 1 */ ;\
+TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\
+ ;\
+ PSRLW ( CONST(8), MA1 ) /* t1 >> 8 ~= t1/255 */ ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 ~= t2/255 */
+
+
+/* integer multiplication - geometric series
+ *
+ * takes the geometric series approximation to the division
*
* t/255 = (t >> 8) + (t >> 16) + (t >> 24) ..
*
* 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
-
-/*
+#define GMB_MULT_GS( MP1, MA1, MP2, MA2 ) \
+ PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\
+TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\
+ ;\
+ MOVQ ( MA1, MP1 ) ;\
+ PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
+ ;\
+TWO(MOVQ ( MA2, MP2 )) ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
+ ;\
+ PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
+ PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
+ ;\
+TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
+
+
+/* integer multiplication - geometric series plus rounding
+ *
* 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
+ *
+ * note that M80 is register with the 0x0080008000800080 constant
*/
-#define GMBT_ROUNDOFF 0
-
-/* instead of the roundoff this adds a small correction to satisfy the OpenGL criteria
+#define GMB_MULT_GSR( MP1, MA1, MP2, MA2, M80 ) \
+ PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\
+ PADDW ( M80, MA1 ) /* t1 += 0x80 */ ;\
+ ;\
+TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\
+TWO(PADDW ( M80, MA2 )) /* t2 += 0x80 */ ;\
+ ;\
+ MOVQ ( MA1, MP1 ) ;\
+ PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
+ ;\
+TWO(MOVQ ( MA2, MP2 )) ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
+ ;\
+ PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
+ PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
+ ;\
+TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
+
+
+/* linear interpolation - geometric series
+ */
+#define GMB_LERP_GS( MP1, MQ1, MA1, MP2, MQ2, MA2) \
+ PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\
+ PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\
+ PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\
+ ;\
+TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\
+TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\
+TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\
+ ;\
+ MOVQ ( MA1, MP1 ) ;\
+ PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
+ ;\
+TWO(MOVQ ( MA2, MP2 )) ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
+ ;\
+ PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
+TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
+ ;\
+ PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\
+TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\
+ ;\
+ PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
+
+
+/* linear interpolation - geometric series with roundoff
*
- * t/255 ~= (t + (t >> 8) + (t >> 15)) >> 8
+ * this is a generalization of Blinn's formula to signed arithmetic
*
- * note that although is faster than rounding off it doesn't give always the exact results
+ * note that M80 is a register with the 0x0080008000800080 constant
*/
-#define GMBT_GEOMETRIC_CORRECTION 1
-
-/*
- * do
+#define GMB_LERP_GSR( MP1, MQ1, MA1, MP2, MQ2, MA2, M80) \
+ PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\
+ PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\
+ PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\
+ ;\
+TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\
+TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\
+TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\
+ ;\
+ PSRLW ( CONST(15), MP1 ) /* q1 > p1 ? 1 : 0 */ ;\
+TWO(PSRLW ( CONST(15), MP2 )) /* q2 > q2 ? 1 : 0 */ ;\
+ ;\
+ PSLLW ( CONST(8), MP1 ) /* q1 > p1 ? 0x100 : 0 */ ;\
+TWO(PSLLW ( CONST(8), MP2 )) /* q2 > q2 ? 0x100 : 0 */ ;\
+ ;\
+ PSUBW ( MP1, MA1 ) /* t1 -=? 0x100 */ ;\
+TWO(PSUBW ( MP2, MA2 )) /* t2 -=? 0x100 */ ;\
+ ;\
+ PADDW ( M80, MA1 ) /* t1 += 0x80 */ ;\
+TWO(PADDW ( M80, MA2 )) /* t2 += 0x80 */ ;\
+ ;\
+ MOVQ ( MA1, MP1 ) ;\
+ PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
+ ;\
+TWO(MOVQ ( MA2, MP2 )) ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
+ ;\
+ PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
+TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
+ ;\
+ PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\
+TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\
+ ;\
+ PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
+
+
+/* linear interpolation - geometric series with correction
*
- * s = (q - p)*a + q
+ * instead of the roundoff this adds a small correction to satisfy the OpenGL criteria
*
- * instead of
+ * t/255 ~= (t + (t >> 8) + (t >> 15)) >> 8
*
- * s = p*a + q*(1-a)
+ * note that although is faster than rounding off it doesn't give always the exact results
+ */
+#define GMB_LERP_GSC( MP1, MQ1, MA1, MP2, MQ2, MA2) \
+ PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\
+ PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\
+ PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\
+ ;\
+TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\
+TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\
+TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\
+ ;\
+ MOVQ ( MA1, MP1 ) ;\
+ PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
+ ;\
+TWO(MOVQ ( MA2, MP2 )) ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
+ ;\
+ PADDW ( MA1, MP1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
+ PSRLW ( CONST(7), MA1 ) /* t1 >> 15 */ ;\
+ ;\
+TWO(PADDW ( MA2, MP2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
+TWO(PSRLW ( CONST(7), MA2 )) /* t2 >> 15 */ ;\
+ ;\
+ PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) + (t1 >>15) ~= (t1/255) << 8 */ ;\
+TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) + (t2 >>15) ~= (t2/255) << 8 */ ;\
+ ;\
+ PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\
+TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\
+ ;\
+ PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
+TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
+
+
+/* common blending setup code
*
- * this eliminates a multiply at the expense of
- * complicating the roundoff but is generally worth it
+ * note that M00 is a register with 0x0000000000000000 constant which can be easily obtained making
+ *
+ * PXOR ( M00, M00 )
*/
-#define GMBT_SIGNED_ARITHMETIC 1
-
-#if GMBT_ROUNDOFF
+#define GMB_LOAD(rgba, dest, MPP, MQQ) \
+ONE(MOVD ( REGIND(rgba), MPP )) /* | | | | qa1 | qb1 | qg1 | qr1 */ ;\
+ONE(MOVD ( REGIND(dest), MQQ )) /* | | | | pa1 | pb1 | pg1 | pr1 */ ;\
+ ;\
+TWO(MOVQ ( REGIND(rgba), MPP )) /* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */ ;\
+TWO(MOVQ ( REGIND(dest), MQQ )) /* pa2 | pb2 | pg2 | pr2 | pa1 | pb1 | pg1 | pr1 */
+
+#define GMB_UNPACK(MP1, MQ1, MP2, MQ2, M00) \
+TWO(MOVQ ( MP1, MP2 )) ;\
+TWO(MOVQ ( MQ1, MQ2 )) ;\
+ ;\
+ PUNPCKLBW ( M00, MQ1 ) /* qa1 | qb1 | qg1 | qr1 */ ;\
+TWO(PUNPCKHBW ( M00, MQ2 )) /* qa2 | qb2 | qg2 | qr2 */ ;\
+ PUNPCKLBW ( M00, MP1 ) /* pa1 | pb1 | pg1 | pr1 */ ;\
+TWO(PUNPCKHBW ( M00, MP2 )) /* pa2 | pb2 | pg2 | pr2 */
+
+#define GMB_ALPHA(MP1, MA1, MP2, MA2) \
+ MOVQ ( MP1, MA1 ) ;\
+TWO(MOVQ ( MP2, MA2 )) ;\
+ ;\
+ PUNPCKHWD ( MA1, MA1 ) /* pa1 | pa1 | | */ ;\
+TWO(PUNPCKHWD ( MA2, MA2 )) /* pa2 | pa2 | | */ ;\
+ PUNPCKHDQ ( MA1, MA1 ) /* pa1 | pa1 | pa1 | pa1 */ ;\
+TWO(PUNPCKHDQ ( MA2, MA2 )) /* pa2 | pa2 | pa2 | pa2 */
+
+#define GMB_PACK( MS1, MS2 ) \
+ PACKUSWB ( MS2, MS1 ) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ ;\
+
+#define GMB_STORE(rgba, MSS ) \
+ONE(MOVD ( MSS, REGIND(rgba) )) /* | | | | sa1 | sb1 | sg1 | sr1 */ ;\
+TWO(MOVQ ( MSS, REGIND(rgba) )) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */
+
+/* Kevin F. Quinn <kevquinn@gentoo.org> 2 July 2006
+ * Replace data segment constants with text-segment
+ * constants (via pushl/movq)
SEG_DATA
ALIGNDATA8
+const_0080:
+ D_LONG 0x00800080, 0x00800080
+
const_80:
- D_LONG 0x00800080, 0x00800080
-#endif
+ D_LONG 0x80808080, 0x80808080
+*/
+#define const_0080_l 0x00800080
+#define const_0080_h 0x00800080
+#define const_80_l 0x80808080
+#define const_80_h 0x80808080
- SEG_TEXT
+ SEG_TEXT
-ALIGNTEXT16
-GLOBL GLNAME(_mesa_mmx_blend_transparency)
-/*
- * void blend_transparency( GLcontext *ctx,
- * GLuint n,
- * const GLubyte mask[],
- * GLchan rgba[][4],
- * CONST GLchan dest[][4] )
- *
- * Common transparency blending mode.
+/* Blend transparency function
*/
-GLNAME( _mesa_mmx_blend_transparency ):
-
- PUSH_L ( EBP )
- MOV_L ( ESP, EBP )
- PUSH_L ( ESI )
- PUSH_L ( EDI )
- PUSH_L ( EBX )
-
- MOV_L ( REGOFF(12, EBP), ECX ) /* n */
- CMP_L ( CONST(0), ECX)
- JE ( LLBL (GMBT_return) )
-
- 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) )
-
- CMP_B ( CONST(0), REGIND(EBX) ) /* *mask == 0 */
- JE ( LLBL (GMBT_align_continue) )
-
- 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_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_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 */
+#define TAG(x) CONCAT(x,_transparency)
+#define LLTAG(x) LLBL2(x,_transparency)
+#define INIT \
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 */
+#define MAIN( rgba, dest ) \
+ GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
+ GMB_UNPACK( MM1, MM2, MM4, MM5, MM0 ) ;\
+ GMB_ALPHA( MM1, MM3, MM4, MM6 ) ;\
+ GMB_LERP_GSC( MM1, MM2, MM3, MM4, MM5, MM6 ) ;\
+ GMB_PACK( MM3, MM6 ) ;\
+ GMB_STORE( rgba, MM3 )
- MOVQ ( MM7, MM1 )
- MOVQ ( MM6, MM2 )
+#include "mmx_blendtmp.h"
- 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
-
-#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 */
-
- 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 */
-
-#if GMBT_GEOMETRIC_CORRECTION
- PSRLW ( CONST(7), MM3 ) /* t1 >> 15 */
- PSRLW ( CONST(7), MM5 ) /* t2 >> 15 */
-
- PADDW ( MM3, MM2 ) /* t1 + (t1 >> 8) + (t1 >>15) ~= (t1/255) << 8 */
- PADDW ( MM5, MM6 ) /* t2 + (t2 >> 8) + (t2 >>15) ~= (t2/255) << 8 */
-#endif
-#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
+/* Blend add function
+ *
+ * FIXME: Add some loop unrolling here...
+ */
- PMULLW ( MM3, MM2 ) /* t1 = (q1 - p1)*pa1 */
+#define TAG(x) CONCAT(x,_add)
+#define LLTAG(x) LLBL2(x,_add)
-#if GMBT_ROUNDOFF
- PSRLW ( CONST(15), MM4 ) /* q1 > p1 ? 1 : 0 */
+#define INIT
- PSLLW ( CONST(8), MM4 ) /* q1 > p1 ? 0x100 : 0 */
+#define MAIN( rgba, dest ) \
+ONE(MOVD ( REGIND(rgba), MM1 )) /* | | | | qa1 | qb1 | qg1 | qr1 */ ;\
+ONE(MOVD ( REGIND(dest), MM2 )) /* | | | | pa1 | pb1 | pg1 | pr1 */ ;\
+ONE(PADDUSB ( MM2, MM1 )) ;\
+ONE(MOVD ( MM1, REGIND(rgba) )) /* | | | | sa1 | sb1 | sg1 | sr1 */ ;\
+ ;\
+TWO(MOVQ ( REGIND(rgba), MM1 )) /* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */ ;\
+TWO(PADDUSB ( REGIND(dest), MM1 )) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ ;\
+TWO(MOVQ ( MM1, REGIND(rgba) ))
- PSUBW ( MM4, MM2 ) /* t1 -=? 0x100 */
-#endif
+#include "mmx_blendtmp.h"
-#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 */
+/* Blend min function
+ */
- PMULLW ( MM0, MM1 ) /* q1*(255 - pa1) */
+#define TAG(x) CONCAT(x,_min)
+#define LLTAG(x) LLBL2(x,_min)
- PADDW ( MM1, MM2 ) /* t1 = p1*pa1 + q1*(255 - pa1) */
-#endif
+/* Kevin F. Quinn 2nd July 2006
+ * Replace data segment constants with text-segment instructions
+#define INIT \
+ MOVQ ( CONTENT(const_80), MM7 )
+ */
+#define INIT \
+ PUSH_L ( CONST(const_80_h) ) /* 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80*/ ;\
+ PUSH_L ( CONST(const_80_l) ) ;\
+ MOVQ ( REGIND(ESP), MM7 ) ;\
+ ADD_L ( CONST(8), ESP)
+
+#define MAIN( rgba, dest ) \
+ GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
+ MOVQ ( MM1, MM3 ) ;\
+ MOVQ ( MM2, MM4 ) ;\
+ PXOR ( MM7, MM3 ) /* unsigned -> signed */ ;\
+ PXOR ( MM7, MM4 ) /* unsigned -> signed */ ;\
+ PCMPGTB ( MM3, MM4 ) /* q > p ? 0xff : 0x00 */ ;\
+ PAND ( MM4, MM1 ) /* q > p ? p : 0 */ ;\
+ PANDN ( MM2, MM4 ) /* q > p ? 0 : q */ ;\
+ POR ( MM1, MM4 ) /* q > p ? p : q */ ;\
+ GMB_STORE( rgba, MM4 )
+
+#include "mmx_blendtmp.h"
+
+
+/* Blend max function
+ */
-#if GMBT_ROUNDOFF
- MOVQ ( CONTENT(const_80), MM4 )
+#define TAG(x) CONCAT(x,_max)
+#define LLTAG(x) LLBL2(x,_max)
- PADDW ( MM4, MM2 ) /* t1 += 0x80 */
-#endif
+/* Kevin F. Quinn 2nd July 2006
+ * Replace data segment constants with text-segment instructions
+#define INIT \
+ MOVQ ( CONTENT(const_80), MM7 )
+ */
+#define INIT \
+ PUSH_L ( CONST(const_80_l) ) /* 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80*/ ;\
+ PUSH_L ( CONST(const_80_h) ) ;\
+ MOVQ ( REGIND(ESP), MM7 ) ;\
+ ADD_L ( CONST(8), ESP)
+
+#define MAIN( rgba, dest ) \
+ GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
+ MOVQ ( MM1, MM3 ) ;\
+ MOVQ ( MM2, MM4 ) ;\
+ PXOR ( MM7, MM3 ) /* unsigned -> signed */ ;\
+ PXOR ( MM7, MM4 ) /* unsigned -> signed */ ;\
+ PCMPGTB ( MM3, MM4 ) /* q > p ? 0xff : 0x00 */ ;\
+ PAND ( MM4, MM2 ) /* q > p ? q : 0 */ ;\
+ PANDN ( MM1, MM4 ) /* q > p ? 0 : p */ ;\
+ POR ( MM2, MM4 ) /* q > p ? p : q */ ;\
+ GMB_STORE( rgba, MM4 )
+
+#include "mmx_blendtmp.h"
+
+
+/* Blend modulate function
+ */
-#if GMBT_GEOMETRIC_SERIES
- MOVQ ( MM2, MM3 )
+#define TAG(x) CONCAT(x,_modulate)
+#define LLTAG(x) LLBL2(x,_modulate)
- PSRLW ( CONST(8), MM3 ) /* t1 >> 8 */
+/* Kevin F. Quinn 2nd July 2006
+ * Replace data segment constants with text-segment instructions
+#define INIT \
+ MOVQ ( CONTENT(const_0080), MM7 )
+ */
+#define INIT \
+ PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */ ;\
+ PUSH_L ( CONST(const_0080_l) ) /* 0x0080 | 0x0080 | 0x0080 | 0x0080 */ ;\
+ PUSH_L ( CONST(const_0080_h) ) ;\
+ MOVQ ( REGIND(ESP), MM7 ) ;\
+ ADD_L ( CONST(8), ESP)
+
+#define MAIN( rgba, dest ) \
+ GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
+ GMB_UNPACK( MM1, MM2, MM4, MM5, MM0 ) ;\
+ GMB_MULT_GSR( MM1, MM2, MM4, MM5, MM7 ) ;\
+ GMB_PACK( MM2, MM5 ) ;\
+ GMB_STORE( rgba, MM2 )
+
+#include "mmx_blendtmp.h"
- PADDW ( MM3, MM2 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */
#endif
-
-#if GMBT_SIGNED_ARITHMETIC
- PADDW ( MM1, MM2 ) /* (t1/255 + q1) << 8 */
+
+#if defined (__ELF__) && defined (__linux__)
+ .section .note.GNU-stack,"",%progbits
#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_return):
-
- POP_L ( EBX )
- POP_L ( EDI )
- POP_L ( ESI )
- MOV_L ( EBP, ESP )
- POP_L ( EBP )
- RET