mmx_blend.S revision 7117f1b4
1 ; 2/* 3 * Written by Jos� Fonseca <j_r_fonseca@yahoo.co.uk> 4 */ 5 6 7#ifdef USE_MMX_ASM 8#include "matypes.h" 9 10/* integer multiplication - alpha plus one 11 * 12 * makes the following approximation to the division (Sree) 13 * 14 * rgb*a/255 ~= (rgb*(a+1)) >> 256 15 * 16 * which is the fastest method that satisfies the following OpenGL criteria 17 * 18 * 0*0 = 0 and 255*255 = 255 19 * 20 * note that MX1 is a register with 0xffffffffffffffff constant which can be easily obtained making 21 * 22 * PCMPEQW ( MX1, MX1 ) 23 */ 24#define GMB_MULT_AP1( MP1, MA1, MP2, MA2, MX1 ) \ 25 PSUBW ( MX1, MA1 ) /* a1 + 1 | a1 + 1 | a1 + 1 | a1 + 1 */ ;\ 26 PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\ 27 ;\ 28TWO(PSUBW ( MX1, MA2 )) /* a2 + 1 | a2 + 1 | a2 + 1 | a2 + 1 */ ;\ 29TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\ 30 ;\ 31 PSRLW ( CONST(8), MA1 ) /* t1 >> 8 ~= t1/255 */ ;\ 32TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 ~= t2/255 */ 33 34 35/* integer multiplication - geometric series 36 * 37 * takes the geometric series approximation to the division 38 * 39 * t/255 = (t >> 8) + (t >> 16) + (t >> 24) .. 40 * 41 * in this case just the first two terms to fit in 16bit arithmetic 42 * 43 * t/255 ~= (t + (t >> 8)) >> 8 44 * 45 * note that just by itself it doesn't satisfies the OpenGL criteria, as 255*255 = 254, 46 * so the special case a = 255 must be accounted or roundoff must be used 47 */ 48#define GMB_MULT_GS( MP1, MA1, MP2, MA2 ) \ 49 PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\ 50TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\ 51 ;\ 52 MOVQ ( MA1, MP1 ) ;\ 53 PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\ 54 ;\ 55TWO(MOVQ ( MA2, MP2 )) ;\ 56TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\ 57 ;\ 58 PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\ 59 PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\ 60 ;\ 61TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\ 62TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */ 63 64 65/* integer multiplication - geometric series plus rounding 66 * 67 * when using a geometric series division instead of truncating the result 68 * use roundoff in the approximation (Jim Blinn) 69 * 70 * t = rgb*a + 0x80 71 * 72 * achieving the exact results 73 * 74 * note that M80 is register with the 0x0080008000800080 constant 75 */ 76#define GMB_MULT_GSR( MP1, MA1, MP2, MA2, M80 ) \ 77 PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\ 78 PADDW ( M80, MA1 ) /* t1 += 0x80 */ ;\ 79 ;\ 80TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\ 81TWO(PADDW ( M80, MA2 )) /* t2 += 0x80 */ ;\ 82 ;\ 83 MOVQ ( MA1, MP1 ) ;\ 84 PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\ 85 ;\ 86TWO(MOVQ ( MA2, MP2 )) ;\ 87TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\ 88 ;\ 89 PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\ 90 PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\ 91 ;\ 92TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\ 93TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */ 94 95 96/* linear interpolation - geometric series 97 */ 98#define GMB_LERP_GS( MP1, MQ1, MA1, MP2, MQ2, MA2) \ 99 PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\ 100 PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\ 101 PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\ 102 ;\ 103TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\ 104TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\ 105TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\ 106 ;\ 107 MOVQ ( MA1, MP1 ) ;\ 108 PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\ 109 ;\ 110TWO(MOVQ ( MA2, MP2 )) ;\ 111TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\ 112 ;\ 113 PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\ 114TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\ 115 ;\ 116 PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\ 117TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\ 118 ;\ 119 PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\ 120TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */ 121 122 123/* linear interpolation - geometric series with roundoff 124 * 125 * this is a generalization of Blinn's formula to signed arithmetic 126 * 127 * note that M80 is a register with the 0x0080008000800080 constant 128 */ 129#define GMB_LERP_GSR( MP1, MQ1, MA1, MP2, MQ2, MA2, M80) \ 130 PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\ 131 PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\ 132 PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\ 133 ;\ 134TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\ 135TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\ 136TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\ 137 ;\ 138 PSRLW ( CONST(15), MP1 ) /* q1 > p1 ? 1 : 0 */ ;\ 139TWO(PSRLW ( CONST(15), MP2 )) /* q2 > q2 ? 1 : 0 */ ;\ 140 ;\ 141 PSLLW ( CONST(8), MP1 ) /* q1 > p1 ? 0x100 : 0 */ ;\ 142TWO(PSLLW ( CONST(8), MP2 )) /* q2 > q2 ? 0x100 : 0 */ ;\ 143 ;\ 144 PSUBW ( MP1, MA1 ) /* t1 -=? 0x100 */ ;\ 145TWO(PSUBW ( MP2, MA2 )) /* t2 -=? 0x100 */ ;\ 146 ;\ 147 PADDW ( M80, MA1 ) /* t1 += 0x80 */ ;\ 148TWO(PADDW ( M80, MA2 )) /* t2 += 0x80 */ ;\ 149 ;\ 150 MOVQ ( MA1, MP1 ) ;\ 151 PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\ 152 ;\ 153TWO(MOVQ ( MA2, MP2 )) ;\ 154TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\ 155 ;\ 156 PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\ 157TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\ 158 ;\ 159 PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\ 160TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\ 161 ;\ 162 PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\ 163TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */ 164 165 166/* linear interpolation - geometric series with correction 167 * 168 * instead of the roundoff this adds a small correction to satisfy the OpenGL criteria 169 * 170 * t/255 ~= (t + (t >> 8) + (t >> 15)) >> 8 171 * 172 * note that although is faster than rounding off it doesn't give always the exact results 173 */ 174#define GMB_LERP_GSC( MP1, MQ1, MA1, MP2, MQ2, MA2) \ 175 PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\ 176 PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\ 177 PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\ 178 ;\ 179TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\ 180TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\ 181TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\ 182 ;\ 183 MOVQ ( MA1, MP1 ) ;\ 184 PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\ 185 ;\ 186TWO(MOVQ ( MA2, MP2 )) ;\ 187TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\ 188 ;\ 189 PADDW ( MA1, MP1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\ 190 PSRLW ( CONST(7), MA1 ) /* t1 >> 15 */ ;\ 191 ;\ 192TWO(PADDW ( MA2, MP2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\ 193TWO(PSRLW ( CONST(7), MA2 )) /* t2 >> 15 */ ;\ 194 ;\ 195 PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) + (t1 >>15) ~= (t1/255) << 8 */ ;\ 196TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) + (t2 >>15) ~= (t2/255) << 8 */ ;\ 197 ;\ 198 PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\ 199TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\ 200 ;\ 201 PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\ 202TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */ 203 204 205/* common blending setup code 206 * 207 * note that M00 is a register with 0x0000000000000000 constant which can be easily obtained making 208 * 209 * PXOR ( M00, M00 ) 210 */ 211#define GMB_LOAD(rgba, dest, MPP, MQQ) \ 212ONE(MOVD ( REGIND(rgba), MPP )) /* | | | | qa1 | qb1 | qg1 | qr1 */ ;\ 213ONE(MOVD ( REGIND(dest), MQQ )) /* | | | | pa1 | pb1 | pg1 | pr1 */ ;\ 214 ;\ 215TWO(MOVQ ( REGIND(rgba), MPP )) /* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */ ;\ 216TWO(MOVQ ( REGIND(dest), MQQ )) /* pa2 | pb2 | pg2 | pr2 | pa1 | pb1 | pg1 | pr1 */ 217 218#define GMB_UNPACK(MP1, MQ1, MP2, MQ2, M00) \ 219TWO(MOVQ ( MP1, MP2 )) ;\ 220TWO(MOVQ ( MQ1, MQ2 )) ;\ 221 ;\ 222 PUNPCKLBW ( M00, MQ1 ) /* qa1 | qb1 | qg1 | qr1 */ ;\ 223TWO(PUNPCKHBW ( M00, MQ2 )) /* qa2 | qb2 | qg2 | qr2 */ ;\ 224 PUNPCKLBW ( M00, MP1 ) /* pa1 | pb1 | pg1 | pr1 */ ;\ 225TWO(PUNPCKHBW ( M00, MP2 )) /* pa2 | pb2 | pg2 | pr2 */ 226 227#define GMB_ALPHA(MP1, MA1, MP2, MA2) \ 228 MOVQ ( MP1, MA1 ) ;\ 229TWO(MOVQ ( MP2, MA2 )) ;\ 230 ;\ 231 PUNPCKHWD ( MA1, MA1 ) /* pa1 | pa1 | | */ ;\ 232TWO(PUNPCKHWD ( MA2, MA2 )) /* pa2 | pa2 | | */ ;\ 233 PUNPCKHDQ ( MA1, MA1 ) /* pa1 | pa1 | pa1 | pa1 */ ;\ 234TWO(PUNPCKHDQ ( MA2, MA2 )) /* pa2 | pa2 | pa2 | pa2 */ 235 236#define GMB_PACK( MS1, MS2 ) \ 237 PACKUSWB ( MS2, MS1 ) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ ;\ 238 239#define GMB_STORE(rgba, MSS ) \ 240ONE(MOVD ( MSS, REGIND(rgba) )) /* | | | | sa1 | sb1 | sg1 | sr1 */ ;\ 241TWO(MOVQ ( MSS, REGIND(rgba) )) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ 242 243/* Kevin F. Quinn <kevquinn@gentoo.org> 2 July 2006 244 * Replace data segment constants with text-segment 245 * constants (via pushl/movq) 246 SEG_DATA 247 248ALIGNDATA8 249const_0080: 250 D_LONG 0x00800080, 0x00800080 251 252const_80: 253 D_LONG 0x80808080, 0x80808080 254*/ 255#define const_0080_l 0x00800080 256#define const_0080_h 0x00800080 257#define const_80_l 0x80808080 258#define const_80_h 0x80808080 259 260 SEG_TEXT 261 262 263/* Blend transparency function 264 */ 265 266#define TAG(x) CONCAT(x,_transparency) 267#define LLTAG(x) LLBL2(x,_transparency) 268 269#define INIT \ 270 PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */ 271 272#define MAIN( rgba, dest ) \ 273 GMB_LOAD( rgba, dest, MM1, MM2 ) ;\ 274 GMB_UNPACK( MM1, MM2, MM4, MM5, MM0 ) ;\ 275 GMB_ALPHA( MM1, MM3, MM4, MM6 ) ;\ 276 GMB_LERP_GSC( MM1, MM2, MM3, MM4, MM5, MM6 ) ;\ 277 GMB_PACK( MM3, MM6 ) ;\ 278 GMB_STORE( rgba, MM3 ) 279 280#include "mmx_blendtmp.h" 281 282 283/* Blend add function 284 * 285 * FIXME: Add some loop unrolling here... 286 */ 287 288#define TAG(x) CONCAT(x,_add) 289#define LLTAG(x) LLBL2(x,_add) 290 291#define INIT 292 293#define MAIN( rgba, dest ) \ 294ONE(MOVD ( REGIND(rgba), MM1 )) /* | | | | qa1 | qb1 | qg1 | qr1 */ ;\ 295ONE(MOVD ( REGIND(dest), MM2 )) /* | | | | pa1 | pb1 | pg1 | pr1 */ ;\ 296ONE(PADDUSB ( MM2, MM1 )) ;\ 297ONE(MOVD ( MM1, REGIND(rgba) )) /* | | | | sa1 | sb1 | sg1 | sr1 */ ;\ 298 ;\ 299TWO(MOVQ ( REGIND(rgba), MM1 )) /* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */ ;\ 300TWO(PADDUSB ( REGIND(dest), MM1 )) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ ;\ 301TWO(MOVQ ( MM1, REGIND(rgba) )) 302 303#include "mmx_blendtmp.h" 304 305 306/* Blend min function 307 */ 308 309#define TAG(x) CONCAT(x,_min) 310#define LLTAG(x) LLBL2(x,_min) 311 312/* Kevin F. Quinn 2nd July 2006 313 * Replace data segment constants with text-segment instructions 314#define INIT \ 315 MOVQ ( CONTENT(const_80), MM7 ) 316 */ 317#define INIT \ 318 PUSH_L ( CONST(const_80_h) ) /* 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80*/ ;\ 319 PUSH_L ( CONST(const_80_l) ) ;\ 320 MOVQ ( REGIND(ESP), MM7 ) ;\ 321 ADD_L ( CONST(8), ESP) 322 323#define MAIN( rgba, dest ) \ 324 GMB_LOAD( rgba, dest, MM1, MM2 ) ;\ 325 MOVQ ( MM1, MM3 ) ;\ 326 MOVQ ( MM2, MM4 ) ;\ 327 PXOR ( MM7, MM3 ) /* unsigned -> signed */ ;\ 328 PXOR ( MM7, MM4 ) /* unsigned -> signed */ ;\ 329 PCMPGTB ( MM3, MM4 ) /* q > p ? 0xff : 0x00 */ ;\ 330 PAND ( MM4, MM1 ) /* q > p ? p : 0 */ ;\ 331 PANDN ( MM2, MM4 ) /* q > p ? 0 : q */ ;\ 332 POR ( MM1, MM4 ) /* q > p ? p : q */ ;\ 333 GMB_STORE( rgba, MM4 ) 334 335#include "mmx_blendtmp.h" 336 337 338/* Blend max function 339 */ 340 341#define TAG(x) CONCAT(x,_max) 342#define LLTAG(x) LLBL2(x,_max) 343 344/* Kevin F. Quinn 2nd July 2006 345 * Replace data segment constants with text-segment instructions 346#define INIT \ 347 MOVQ ( CONTENT(const_80), MM7 ) 348 */ 349#define INIT \ 350 PUSH_L ( CONST(const_80_l) ) /* 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80*/ ;\ 351 PUSH_L ( CONST(const_80_h) ) ;\ 352 MOVQ ( REGIND(ESP), MM7 ) ;\ 353 ADD_L ( CONST(8), ESP) 354 355#define MAIN( rgba, dest ) \ 356 GMB_LOAD( rgba, dest, MM1, MM2 ) ;\ 357 MOVQ ( MM1, MM3 ) ;\ 358 MOVQ ( MM2, MM4 ) ;\ 359 PXOR ( MM7, MM3 ) /* unsigned -> signed */ ;\ 360 PXOR ( MM7, MM4 ) /* unsigned -> signed */ ;\ 361 PCMPGTB ( MM3, MM4 ) /* q > p ? 0xff : 0x00 */ ;\ 362 PAND ( MM4, MM2 ) /* q > p ? q : 0 */ ;\ 363 PANDN ( MM1, MM4 ) /* q > p ? 0 : p */ ;\ 364 POR ( MM2, MM4 ) /* q > p ? p : q */ ;\ 365 GMB_STORE( rgba, MM4 ) 366 367#include "mmx_blendtmp.h" 368 369 370/* Blend modulate function 371 */ 372 373#define TAG(x) CONCAT(x,_modulate) 374#define LLTAG(x) LLBL2(x,_modulate) 375 376/* Kevin F. Quinn 2nd July 2006 377 * Replace data segment constants with text-segment instructions 378#define INIT \ 379 MOVQ ( CONTENT(const_0080), MM7 ) 380 */ 381#define INIT \ 382 PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */ ;\ 383 PUSH_L ( CONST(const_0080_l) ) /* 0x0080 | 0x0080 | 0x0080 | 0x0080 */ ;\ 384 PUSH_L ( CONST(const_0080_h) ) ;\ 385 MOVQ ( REGIND(ESP), MM7 ) ;\ 386 ADD_L ( CONST(8), ESP) 387 388#define MAIN( rgba, dest ) \ 389 GMB_LOAD( rgba, dest, MM1, MM2 ) ;\ 390 GMB_UNPACK( MM1, MM2, MM4, MM5, MM0 ) ;\ 391 GMB_MULT_GSR( MM1, MM2, MM4, MM5, MM7 ) ;\ 392 GMB_PACK( MM2, MM5 ) ;\ 393 GMB_STORE( rgba, MM2 ) 394 395#include "mmx_blendtmp.h" 396 397#endif 398 399#if defined (__ELF__) && defined (__linux__) 400 .section .note.GNU-stack,"",%progbits 401#endif 402