2 * Written by José Fonseca <j_r_fonseca@yahoo.co.uk>
8 * make the following approximation to the division (Sree)
10 * rgb*a/255 ~= (rgb*(a+1)) >> 256
12 * which is the fastest method that satisfies the following OpenGL criteria
14 * 0*0 = 0 and 255*255 = 255
16 * note this one should be used alone
18 #define GMBT_ALPHA_PLUS_ONE 0
21 * take the geometric series approximation to the division
23 * t/255 = (t >> 8) + (t >> 16) + (t >> 24) ..
25 * in this case just the first two terms to fit in 16bit arithmetic
27 * t/255 ~= (t + (t >> 8)) >> 8
29 * note that just by itself it doesn't satisfies the OpenGL criteria, as 255*255 = 254,
30 * so the special case a = 255 must be accounted or roundoff must be used
32 #define GMBT_GEOMETRIC_SERIES 1
35 * when using a geometric series division instead of truncating the result
36 * use roundoff in the approximation (Jim Blinn)
40 * achieving the exact results
42 #define GMBT_ROUNDOFF 0
44 /* instead of the roundoff this adds a small correction to satisfy the OpenGL criteria
46 * t/255 ~= (t + (t >> 8) + (t >> 15)) >> 8
48 * note that although is faster than rounding off it doesn't give always the exact results
50 #define GMBT_GEOMETRIC_CORRECTION 1
61 * this eliminates a multiply at the expense of
62 * complicating the roundoff but is generally worth it
64 #define GMBT_SIGNED_ARITHMETIC 1
71 D_LONG 0x00800080, 0x00800080
77 GLOBL GLNAME(_mesa_mmx_blend_transparency)
80 * void blend_transparency( GLcontext *ctx,
82 * const GLubyte mask[],
84 * CONST GLchan dest[][4] )
86 * Common transparency blending mode.
88 GLNAME( _mesa_mmx_blend_transparency ):
96 MOV_L ( REGOFF(12, EBP), ECX ) /* n */
97 CMP_L ( CONST(0), ECX)
98 JE ( LLBL (GMBT_return) )
100 MOV_L ( REGOFF(16, EBP), EBX ) /* mask */
101 MOV_L ( REGOFF(20, EBP), EDI ) /* rgba */
102 MOV_L ( REGOFF(24, EBP), ESI ) /* dest */
104 TEST_L ( CONST(4), EDI ) /* align rgba on an 8-byte boundary */
105 JZ ( LLBL (GMBT_align_end) )
107 CMP_B ( CONST(0), REGIND(EBX) ) /* *mask == 0 */
108 JE ( LLBL (GMBT_align_continue) )
110 PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */
112 MOVD ( REGIND(ESI), MM1 ) /* | | | | qa1 | qb1 | qg1 | qr1 */
113 MOVD ( REGIND(EDI), MM2 ) /* | | | | pa1 | pb1 | pg1 | pr1 */
115 PUNPCKLBW ( MM0, MM1 ) /* qa1 | qb1 | qg1 | qr1 */
116 PUNPCKLBW ( MM0, MM2 ) /* pa1 | pb1 | pg1 | pr1 */
120 PUNPCKHWD ( MM3, MM3 ) /* pa1 | pa1 | | */
121 PUNPCKHDQ ( MM3, MM3 ) /* pa1 | pa1 | pa1 | pa1 */
123 #if GMBT_ALPHA_PLUS_ONE
124 PCMPEQW ( MM4, MM4 ) /* 0xffff | 0xffff | 0xffff | 0xffff */
126 PSUBW ( MM4, MM3 ) /* pa1 + 1 | pa1 + 1 | pa1 + 1 | pa1 + 1 */
129 #if GMBT_SIGNED_ARITHMETIC
130 PSUBW ( MM1, MM2 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */
132 PSLLW ( CONST(8), MM1 ) /* q1 << 8 */
138 PMULLW ( MM3, MM2 ) /* t1 = (q1 - p1)*pa1 */
141 PSRLW ( CONST(15), MM4 ) /* q1 > p1 ? 1 : 0 */
143 PSLLW ( CONST(8), MM4 ) /* q1 > p1 ? 0x100 : 0 */
145 PSUBW ( MM4, MM2 ) /* t1 -=? 0x100 */
149 PCMPEQW ( MM4, MM4 ) /* 0xffff | 0xffff | 0xffff | 0xffff */
150 PUNPCKLBW ( MM0, MM4 ) /* 0x00ff | 0x00ff | 0x00ff | 0x00ff */
153 PMULLW ( MM3, MM2 ) /* p1*pa1 */
155 PSUBW ( MM3, MM0 ) /* 255 - pa1 | 255 - pa1 | 255 - pa1 | 255 - pa1 */
157 PMULLW ( MM0, MM1 ) /* q1*(255 - pa1) */
159 PADDW ( MM1, MM2 ) /* t1 = p1*pa1 + q1*(255 - pa1) */
163 MOVQ ( CONTENT(const_80), MM4 )
165 PADDW ( MM4, MM2 ) /* t1 += 0x80 */
168 #if GMBT_GEOMETRIC_SERIES
171 PSRLW ( CONST(8), MM3 ) /* t1 >> 8 */
173 PADDW ( MM3, MM2 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */
176 #if GMBT_SIGNED_ARITHMETIC
177 PADDW ( MM1, MM2 ) /* (t1/255 + q1) << 8 */
180 PSRLW ( CONST(8), MM2 ) /* sa1 | sb1 | sg1 | sr1 */
182 PACKUSWB ( MM0, MM2 ) /* | | | | sa1 | sb1 | sg1 | sr1 */
183 MOVD ( MM2, REGIND(EDI) )
185 LLBL (GMBT_align_continue):
187 DEC_L ( ECX ) /* n -= 1 */
188 INC_L ( EBX ) /* mask += 1 */
189 ADD_L ( CONST(4), EDI ) /* rgba += 1 */
190 ADD_L ( CONST(4), ESI ) /* dest += 1 */
192 LLBL (GMBT_align_end):
194 CMP_L ( CONST(2), ECX)
195 JB ( LLBL (GMBT_loop_end) )
198 LLBL (GMBT_loop_begin):
200 CMP_W ( CONST(0), REGIND(EBX) ) /* *mask == 0 && *(mask + 1) == 0 */
201 JE ( LLBL (GMBT_loop_continue) )
203 /* NOTE: the instruction pairing when multiple pipelines are available must be checked */
205 PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */
207 MOVQ ( REGIND(ESI), MM7 ) /* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */
208 MOVQ ( REGIND(EDI), MM6 ) /* pa2 | pb2 | pg2 | pr2 | pa1 | pb1 | pg1 | pr1 */
213 PUNPCKLBW ( MM0, MM1 ) /* qa1 | qb1 | qg1 | qr1 */
214 PUNPCKHBW ( MM0, MM7 ) /* qa2 | qb2 | qg2 | qr2 */
215 PUNPCKLBW ( MM0, MM2 ) /* pa1 | pb1 | pg1 | pr1 */
216 PUNPCKHBW ( MM0, MM6 ) /* pa2 | pb2 | pg2 | pr2 */
221 PUNPCKHWD ( MM3, MM3 ) /* pa1 | pa1 | | */
222 PUNPCKHWD ( MM5, MM5 ) /* pa2 | pa2 | | */
223 PUNPCKHDQ ( MM3, MM3 ) /* pa1 | pa1 | pa1 | pa1 */
224 PUNPCKHDQ ( MM5, MM5 ) /* pa2 | pa2 | pa2 | pa2 */
226 #if GMBT_ALPHA_PLUS_ONE
227 PCMPEQW ( MM4, MM4 ) /* 0xffff | 0xffff | 0xffff | 0xffff */
229 PSUBW ( MM4, MM3 ) /* pa1 + 1 | pa1 + 1 | pa1 + 1 | pa1 + 1 */
230 PSUBW ( MM4, MM5 ) /* pa2 + 1 | pa2 + 1 | pa2 + 1 | pa2 + 1 */
233 #if GMBT_SIGNED_ARITHMETIC
234 PSUBW ( MM1, MM2 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */
235 PSUBW ( MM7, MM6 ) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */
237 PSLLW ( CONST(8), MM1 ) /* q1 << 8 */
238 PSLLW ( CONST(8), MM7 ) /* q2 << 8 */
245 PMULLW ( MM3, MM2 ) /* t1 = (q1 - p1)*pa1 */
246 PMULLW ( MM5, MM6 ) /* t2 = (q2 - p2)*pa2 */
249 PSRLW ( CONST(15), MM0 ) /* q1 > p1 ? 1 : 0 */
250 PSRLW ( CONST(15), MM4 ) /* q2 > q2 ? 1 : 0 */
252 PSLLW ( CONST(8), MM0 ) /* q1 > p1 ? 0x100 : 0 */
253 PSLLW ( CONST(8), MM4 ) /* q2 > q2 ? 0x100 : 0 */
255 PSUBW ( MM0, MM2 ) /* t1 -=? 0x100 */
256 PSUBW ( MM4, MM7 ) /* t2 -=? 0x100 */
260 PCMPEQW ( MM4, MM4 ) /* 0xffff | 0xffff | 0xffff | 0xffff */
261 PUNPCKLBW ( MM0, MM4 ) /* 0x00ff | 0x00ff | 0x00ff | 0x00ff */
264 PMULLW ( MM3, MM2 ) /* p1*pa1 */
265 PMULLW ( MM5, MM6 ) /* p2*pa2 */
267 PSUBW ( MM3, MM0 ) /* 255 - pa1 | 255 - pa1 | 255 - pa1 | 255 - pa1 */
268 PSUBW ( MM5, MM4 ) /* 255 - pa2 | 255 - pa2 | 255 - pa2 | 255 - pa2 */
270 PMULLW ( MM0, MM1 ) /* q1*(255 - pa1) */
271 PMULLW ( MM4, MM7 ) /* q2*(255 - pa2) */
273 PADDW ( MM1, MM2 ) /* t1 = p1*pa1 + q1*(255 - pa1) */
274 PADDW ( MM7, MM6 ) /* t2 = p2*pa2 + q2*(255 - pa2) */
278 MOVQ ( CONTENT(const_80), MM4 )
280 PADDW ( MM4, MM2 ) /* t1 += 0x80 */
281 PADDW ( MM4, MM6 ) /* t2 += 0x80 */
284 #if GMBT_GEOMETRIC_SERIES
288 PSRLW ( CONST(8), MM3 ) /* t1 >> 8 */
289 PSRLW ( CONST(8), MM5 ) /* t2 >> 8 */
291 PADDW ( MM3, MM2 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */
292 PADDW ( MM5, MM6 ) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */
294 #if GMBT_GEOMETRIC_CORRECTION
295 PSRLW ( CONST(7), MM3 ) /* t1 >> 15 */
296 PSRLW ( CONST(7), MM5 ) /* t2 >> 15 */
298 PADDW ( MM3, MM2 ) /* t1 + (t1 >> 8) + (t1 >>15) ~= (t1/255) << 8 */
299 PADDW ( MM5, MM6 ) /* t2 + (t2 >> 8) + (t2 >>15) ~= (t2/255) << 8 */
303 #if GMBT_SIGNED_ARITHMETIC
304 PADDW ( MM1, MM2 ) /* (t1/255 + q1) << 8 */
305 PADDW ( MM7, MM6 ) /* (t2/255 + q2) << 8 */
308 PSRLW ( CONST(8), MM2 ) /* sa1 | sb1 | sg1 | sr1 */
309 PSRLW ( CONST(8), MM6 ) /* sa2 | sb2 | sg2 | sr2 */
311 PACKUSWB ( MM6, MM2 ) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */
312 MOVQ ( MM2, REGIND(EDI) )
314 LLBL (GMBT_loop_continue):
317 DEC_L ( ECX ) /* n -= 2 */
318 ADD_L ( CONST(2), EBX ) /* mask += 2 */
319 ADD_L ( CONST(8), EDI ) /* rgba += 2 */
320 ADD_L ( CONST(8), ESI ) /* dest += 2 */
321 CMP_L ( CONST(2), ECX )
322 JAE ( LLBL (GMBT_loop_begin) )
324 LLBL (GMBT_loop_end):
326 CMP_L ( CONST(1), ECX )
327 JB ( LLBL (GMBT_done) )
329 CMP_B ( CONST(0), REGIND(EBX) ) /* *mask == 0 */
330 JE ( LLBL (GMBT_done) )
332 PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */
334 MOVD ( REGIND(ESI), MM1 ) /* | | | | qa1 | qb1 | qg1 | qr1 */
335 MOVD ( REGIND(EDI), MM2 ) /* | | | | pa1 | pb1 | pg1 | pr1 */
337 PUNPCKLBW ( MM0, MM1 ) /* qa1 | qb1 | qg1 | qr1 */
338 PUNPCKLBW ( MM0, MM2 ) /* pa1 | pb1 | pg1 | pr1 */
342 PUNPCKHWD ( MM3, MM3 ) /* pa1 | pa1 | | */
343 PUNPCKHDQ ( MM3, MM3 ) /* pa1 | pa1 | pa1 | pa1 */
345 #if GMBT_ALPHA_PLUS_ONE
346 PCMPEQW ( MM4, MM4 ) /* 0xffff | 0xffff | 0xffff | 0xffff */
348 PSUBW ( MM4, MM3 ) /* pa1 + 1 | pa1 + 1 | pa1 + 1 | pa1 + 1 */
351 #if GMBT_SIGNED_ARITHMETIC
352 PSUBW ( MM1, MM2 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */
354 PSLLW ( CONST(8), MM1 ) /* q1 << 8 */
360 PMULLW ( MM3, MM2 ) /* t1 = (q1 - p1)*pa1 */
363 PSRLW ( CONST(15), MM4 ) /* q1 > p1 ? 1 : 0 */
365 PSLLW ( CONST(8), MM4 ) /* q1 > p1 ? 0x100 : 0 */
367 PSUBW ( MM4, MM2 ) /* t1 -=? 0x100 */
371 PCMPEQW ( MM4, MM4 ) /* 0xffff | 0xffff | 0xffff | 0xffff */
372 PUNPCKLBW ( MM0, MM4 ) /* 0x00ff | 0x00ff | 0x00ff | 0x00ff */
375 PMULLW ( MM3, MM2 ) /* p1*pa1 */
377 PSUBW ( MM3, MM0 ) /* 255 - pa1 | 255 - pa1 | 255 - pa1 | 255 - pa1 */
379 PMULLW ( MM0, MM1 ) /* q1*(255 - pa1) */
381 PADDW ( MM1, MM2 ) /* t1 = p1*pa1 + q1*(255 - pa1) */
385 MOVQ ( CONTENT(const_80), MM4 )
387 PADDW ( MM4, MM2 ) /* t1 += 0x80 */
390 #if GMBT_GEOMETRIC_SERIES
393 PSRLW ( CONST(8), MM3 ) /* t1 >> 8 */
395 PADDW ( MM3, MM2 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */
398 #if GMBT_SIGNED_ARITHMETIC
399 PADDW ( MM1, MM2 ) /* (t1/255 + q1) << 8 */
402 PSRLW ( CONST(8), MM2 ) /* sa1 | sb1 | sg1 | sr1 */
404 PACKUSWB ( MM0, MM2 ) /* | | | | sa1 | sb1 | sg1 | sr1 */
405 MOVD ( MM2, REGIND(EDI) )