MMX modulate belding function added.
[mesa.git] / src / mesa / swrast / s_blend.c
1 /* $Id: s_blend.c,v 1.20 2002/04/19 10:33:34 jrfonseca Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28
29 #include "glheader.h"
30 #include "context.h"
31 #include "colormac.h"
32 #include "macros.h"
33
34 #include "s_alphabuf.h"
35 #include "s_blend.h"
36 #include "s_context.h"
37 #include "s_span.h"
38
39
40 #if defined(USE_MMX_ASM)
41 #include "X86/mmx.h"
42 #include "X86/common_x86_asm.h"
43 #define _BLENDAPI _ASMAPI
44 #else
45 #define _BLENDAPI
46 #endif
47
48
49 /*
50 * Special case for glBlendFunc(GL_ZERO, GL_ONE)
51 */
52 static void _BLENDAPI
53 blend_noop( GLcontext *ctx, GLuint n, const GLubyte mask[],
54 GLchan rgba[][4], CONST GLchan dest[][4] )
55 {
56 GLuint i;
57 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
58 ASSERT(ctx->Color.BlendSrcRGB==GL_ZERO);
59 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
60 (void) ctx;
61
62 for (i = 0; i < n; i++) {
63 if (mask[i]) {
64 COPY_CHAN4( rgba[i], dest[i] );
65 }
66 }
67 }
68
69
70 /*
71 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
72 */
73 static void _BLENDAPI
74 blend_replace( GLcontext *ctx, GLuint n, const GLubyte mask[],
75 GLchan rgba[][4], CONST GLchan dest[][4] )
76 {
77 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
78 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
79 ASSERT(ctx->Color.BlendDstRGB==GL_ZERO);
80 (void) ctx;
81 (void) n;
82 (void) mask;
83 (void) rgba;
84 (void) dest;
85 }
86
87
88 /*
89 * Common transparency blending mode.
90 */
91 static void _BLENDAPI
92 blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
93 GLchan rgba[][4], CONST GLchan dest[][4] )
94 {
95 GLuint i;
96 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
97 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
98 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
99 (void) ctx;
100
101 for (i=0;i<n;i++) {
102 if (mask[i]) {
103 const GLint t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */
104 if (t == 0) {
105 /* 0% alpha */
106 rgba[i][RCOMP] = dest[i][RCOMP];
107 rgba[i][GCOMP] = dest[i][GCOMP];
108 rgba[i][BCOMP] = dest[i][BCOMP];
109 rgba[i][ACOMP] = dest[i][ACOMP];
110 }
111 else if (t == CHAN_MAX) {
112 /* 100% alpha, no-op */
113 }
114 else {
115 #if 0
116 /* This is pretty close, but Glean complains */
117 const GLint s = CHAN_MAX - t;
118 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
119 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
120 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
121 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
122 #elif 0
123 /* This is slower but satisfies Glean */
124 const GLint s = CHAN_MAX - t;
125 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
126 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
127 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
128 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
129 #else
130 #if CHAN_BITS == 8
131 /* This satisfies Glean and should be reasonably fast */
132 /* Contributed by Nathan Hand */
133 #if 0
134 #define DIV255(X) (((X) << 8) + (X) + 256) >> 16
135 #else
136 GLint temp;
137 #define DIV255(X) (temp = (X), ((temp << 8) + temp + 256) >> 16)
138 #endif
139 const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
140 const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
141 const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
142 const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
143
144 #undef DIV255
145 #elif CHAN_BITS == 16
146 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
147 const GLint r = (GLint) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
148 const GLint g = (GLint) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
149 const GLint b = (GLint) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
150 const GLint a = (GLint) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
151 #else /* CHAN_BITS == 32 */
152 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
153 const GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP];
154 const GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP];
155 const GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP];
156 const GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP];
157 #endif
158 #endif
159 ASSERT(r <= CHAN_MAX);
160 ASSERT(g <= CHAN_MAX);
161 ASSERT(b <= CHAN_MAX);
162 ASSERT(a <= CHAN_MAX);
163 rgba[i][RCOMP] = (GLchan) r;
164 rgba[i][GCOMP] = (GLchan) g;
165 rgba[i][BCOMP] = (GLchan) b;
166 rgba[i][ACOMP] = (GLchan) a;
167 }
168 }
169 }
170 }
171
172
173
174 /*
175 * Add src and dest.
176 */
177 static void _BLENDAPI
178 blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
179 GLchan rgba[][4], CONST GLchan dest[][4] )
180 {
181 GLuint i;
182 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
183 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
184 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
185 (void) ctx;
186
187 for (i=0;i<n;i++) {
188 if (mask[i]) {
189 #if CHAN_TYPE == GL_FLOAT
190 GLfloat r = rgba[i][RCOMP] + dest[i][RCOMP];
191 GLfloat g = rgba[i][GCOMP] + dest[i][GCOMP];
192 GLfloat b = rgba[i][BCOMP] + dest[i][BCOMP];
193 GLfloat a = rgba[i][ACOMP] + dest[i][ACOMP];
194 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAXF );
195 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAXF );
196 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAXF );
197 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAXF );
198 #else
199 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
200 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
201 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
202 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
203 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
204 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
205 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
206 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
207 #endif
208 }
209 }
210 }
211
212
213
214 /*
215 * Blend min function (for GL_EXT_blend_minmax)
216 */
217 static void _BLENDAPI
218 blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
219 GLchan rgba[][4], CONST GLchan dest[][4] )
220 {
221 GLuint i;
222 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
223 (void) ctx;
224
225 for (i=0;i<n;i++) {
226 if (mask[i]) {
227 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
228 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
229 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
230 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
231 }
232 }
233 }
234
235
236
237 /*
238 * Blend max function (for GL_EXT_blend_minmax)
239 */
240 static void _BLENDAPI
241 blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
242 GLchan rgba[][4], CONST GLchan dest[][4] )
243 {
244 GLuint i;
245 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
246 (void) ctx;
247
248 for (i=0;i<n;i++) {
249 if (mask[i]) {
250 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
251 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
252 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
253 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
254 }
255 }
256 }
257
258
259
260 /*
261 * Modulate: result = src * dest
262 */
263 static void _BLENDAPI
264 blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
265 GLchan rgba[][4], CONST GLchan dest[][4] )
266 {
267 GLuint i;
268 (void) ctx;
269
270 for (i=0;i<n;i++) {
271 if (mask[i]) {
272 #if CHAN_TYPE == GL_FLOAT
273 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
274 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
275 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
276 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
277 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
278 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
279 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
280 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
281 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
282 rgba[i][RCOMP] = (GLchan) r;
283 rgba[i][GCOMP] = (GLchan) g;
284 rgba[i][BCOMP] = (GLchan) b;
285 rgba[i][ACOMP] = (GLchan) a;
286 #else
287 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 255) >> 8;
288 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 255) >> 8;
289 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 255) >> 8;
290 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 255) >> 8;
291 rgba[i][RCOMP] = (GLchan) r;
292 rgba[i][GCOMP] = (GLchan) g;
293 rgba[i][BCOMP] = (GLchan) b;
294 rgba[i][ACOMP] = (GLchan) a;
295 #endif
296 }
297 }
298 }
299
300
301
302 /*
303 * General case blend pixels.
304 * Input: n - number of pixels
305 * mask - the usual write mask
306 * In/Out: rgba - the incoming and modified pixels
307 * Input: dest - the pixels from the dest color buffer
308 */
309 static void _BLENDAPI
310 blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
311 GLchan rgba[][4], CONST GLchan dest[][4] )
312 {
313 GLfloat rscale = 1.0F / CHAN_MAXF;
314 GLfloat gscale = 1.0F / CHAN_MAXF;
315 GLfloat bscale = 1.0F / CHAN_MAXF;
316 GLfloat ascale = 1.0F / CHAN_MAXF;
317 GLuint i;
318
319 for (i=0;i<n;i++) {
320 if (mask[i]) {
321 GLint Rs, Gs, Bs, As; /* Source colors */
322 GLint Rd, Gd, Bd, Ad; /* Dest colors */
323 GLfloat sR, sG, sB, sA; /* Source scaling */
324 GLfloat dR, dG, dB, dA; /* Dest scaling */
325 GLfloat r, g, b, a;
326
327 /* Source Color */
328 Rs = rgba[i][RCOMP];
329 Gs = rgba[i][GCOMP];
330 Bs = rgba[i][BCOMP];
331 As = rgba[i][ACOMP];
332
333 /* Frame buffer color */
334 Rd = dest[i][RCOMP];
335 Gd = dest[i][GCOMP];
336 Bd = dest[i][BCOMP];
337 Ad = dest[i][ACOMP];
338
339 /* Source RGB factor */
340 switch (ctx->Color.BlendSrcRGB) {
341 case GL_ZERO:
342 sR = sG = sB = 0.0F;
343 break;
344 case GL_ONE:
345 sR = sG = sB = 1.0F;
346 break;
347 case GL_DST_COLOR:
348 sR = (GLfloat) Rd * rscale;
349 sG = (GLfloat) Gd * gscale;
350 sB = (GLfloat) Bd * bscale;
351 break;
352 case GL_ONE_MINUS_DST_COLOR:
353 sR = 1.0F - (GLfloat) Rd * rscale;
354 sG = 1.0F - (GLfloat) Gd * gscale;
355 sB = 1.0F - (GLfloat) Bd * bscale;
356 break;
357 case GL_SRC_ALPHA:
358 sR = sG = sB = (GLfloat) As * ascale;
359 break;
360 case GL_ONE_MINUS_SRC_ALPHA:
361 sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
362 break;
363 case GL_DST_ALPHA:
364 sR = sG = sB = (GLfloat) Ad * ascale;
365 break;
366 case GL_ONE_MINUS_DST_ALPHA:
367 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
368 break;
369 case GL_SRC_ALPHA_SATURATE:
370 if (As < CHAN_MAX - Ad) {
371 sR = sG = sB = (GLfloat) As * ascale;
372 }
373 else {
374 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
375 }
376 break;
377 case GL_CONSTANT_COLOR:
378 sR = ctx->Color.BlendColor[0];
379 sG = ctx->Color.BlendColor[1];
380 sB = ctx->Color.BlendColor[2];
381 break;
382 case GL_ONE_MINUS_CONSTANT_COLOR:
383 sR = 1.0F - ctx->Color.BlendColor[0];
384 sG = 1.0F - ctx->Color.BlendColor[1];
385 sB = 1.0F - ctx->Color.BlendColor[2];
386 break;
387 case GL_CONSTANT_ALPHA:
388 sR = sG = sB = ctx->Color.BlendColor[3];
389 break;
390 case GL_ONE_MINUS_CONSTANT_ALPHA:
391 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
392 break;
393 case GL_SRC_COLOR: /* GL_NV_blend_square */
394 sR = (GLfloat) Rs * rscale;
395 sG = (GLfloat) Gs * gscale;
396 sB = (GLfloat) Bs * bscale;
397 break;
398 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
399 sR = 1.0F - (GLfloat) Rs * rscale;
400 sG = 1.0F - (GLfloat) Gs * gscale;
401 sB = 1.0F - (GLfloat) Bs * bscale;
402 break;
403 default:
404 /* this should never happen */
405 _mesa_problem(ctx, "Bad blend source RGB factor in do_blend");
406 return;
407 }
408
409 /* Source Alpha factor */
410 switch (ctx->Color.BlendSrcA) {
411 case GL_ZERO:
412 sA = 0.0F;
413 break;
414 case GL_ONE:
415 sA = 1.0F;
416 break;
417 case GL_DST_COLOR:
418 sA = (GLfloat) Ad * ascale;
419 break;
420 case GL_ONE_MINUS_DST_COLOR:
421 sA = 1.0F - (GLfloat) Ad * ascale;
422 break;
423 case GL_SRC_ALPHA:
424 sA = (GLfloat) As * ascale;
425 break;
426 case GL_ONE_MINUS_SRC_ALPHA:
427 sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
428 break;
429 case GL_DST_ALPHA:
430 sA =(GLfloat) Ad * ascale;
431 break;
432 case GL_ONE_MINUS_DST_ALPHA:
433 sA = 1.0F - (GLfloat) Ad * ascale;
434 break;
435 case GL_SRC_ALPHA_SATURATE:
436 sA = 1.0;
437 break;
438 case GL_CONSTANT_COLOR:
439 sA = ctx->Color.BlendColor[3];
440 break;
441 case GL_ONE_MINUS_CONSTANT_COLOR:
442 sA = 1.0F - ctx->Color.BlendColor[3];
443 break;
444 case GL_CONSTANT_ALPHA:
445 sA = ctx->Color.BlendColor[3];
446 break;
447 case GL_ONE_MINUS_CONSTANT_ALPHA:
448 sA = 1.0F - ctx->Color.BlendColor[3];
449 break;
450 case GL_SRC_COLOR: /* GL_NV_blend_square */
451 sA = (GLfloat) As * ascale;
452 break;
453 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
454 sA = 1.0F - (GLfloat) As * ascale;
455 break;
456 default:
457 /* this should never happen */
458 sA = 0.0F;
459 _mesa_problem(ctx, "Bad blend source A factor in do_blend");
460 }
461
462 /* Dest RGB factor */
463 switch (ctx->Color.BlendDstRGB) {
464 case GL_ZERO:
465 dR = dG = dB = 0.0F;
466 break;
467 case GL_ONE:
468 dR = dG = dB = 1.0F;
469 break;
470 case GL_SRC_COLOR:
471 dR = (GLfloat) Rs * rscale;
472 dG = (GLfloat) Gs * gscale;
473 dB = (GLfloat) Bs * bscale;
474 break;
475 case GL_ONE_MINUS_SRC_COLOR:
476 dR = 1.0F - (GLfloat) Rs * rscale;
477 dG = 1.0F - (GLfloat) Gs * gscale;
478 dB = 1.0F - (GLfloat) Bs * bscale;
479 break;
480 case GL_SRC_ALPHA:
481 dR = dG = dB = (GLfloat) As * ascale;
482 break;
483 case GL_ONE_MINUS_SRC_ALPHA:
484 dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
485 break;
486 case GL_DST_ALPHA:
487 dR = dG = dB = (GLfloat) Ad * ascale;
488 break;
489 case GL_ONE_MINUS_DST_ALPHA:
490 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
491 break;
492 case GL_CONSTANT_COLOR:
493 dR = ctx->Color.BlendColor[0];
494 dG = ctx->Color.BlendColor[1];
495 dB = ctx->Color.BlendColor[2];
496 break;
497 case GL_ONE_MINUS_CONSTANT_COLOR:
498 dR = 1.0F - ctx->Color.BlendColor[0];
499 dG = 1.0F - ctx->Color.BlendColor[1];
500 dB = 1.0F - ctx->Color.BlendColor[2];
501 break;
502 case GL_CONSTANT_ALPHA:
503 dR = dG = dB = ctx->Color.BlendColor[3];
504 break;
505 case GL_ONE_MINUS_CONSTANT_ALPHA:
506 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
507 break;
508 case GL_DST_COLOR: /* GL_NV_blend_square */
509 dR = (GLfloat) Rd * rscale;
510 dG = (GLfloat) Gd * gscale;
511 dB = (GLfloat) Bd * bscale;
512 break;
513 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
514 dR = 1.0F - (GLfloat) Rd * rscale;
515 dG = 1.0F - (GLfloat) Gd * gscale;
516 dB = 1.0F - (GLfloat) Bd * bscale;
517 break;
518 default:
519 /* this should never happen */
520 dR = dG = dB = 0.0F;
521 _mesa_problem(ctx, "Bad blend dest RGB factor in do_blend");
522 }
523
524 /* Dest Alpha factor */
525 switch (ctx->Color.BlendDstA) {
526 case GL_ZERO:
527 dA = 0.0F;
528 break;
529 case GL_ONE:
530 dA = 1.0F;
531 break;
532 case GL_SRC_COLOR:
533 dA = (GLfloat) As * ascale;
534 break;
535 case GL_ONE_MINUS_SRC_COLOR:
536 dA = 1.0F - (GLfloat) As * ascale;
537 break;
538 case GL_SRC_ALPHA:
539 dA = (GLfloat) As * ascale;
540 break;
541 case GL_ONE_MINUS_SRC_ALPHA:
542 dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
543 break;
544 case GL_DST_ALPHA:
545 dA = (GLfloat) Ad * ascale;
546 break;
547 case GL_ONE_MINUS_DST_ALPHA:
548 dA = 1.0F - (GLfloat) Ad * ascale;
549 break;
550 case GL_CONSTANT_COLOR:
551 dA = ctx->Color.BlendColor[3];
552 break;
553 case GL_ONE_MINUS_CONSTANT_COLOR:
554 dA = 1.0F - ctx->Color.BlendColor[3];
555 break;
556 case GL_CONSTANT_ALPHA:
557 dA = ctx->Color.BlendColor[3];
558 break;
559 case GL_ONE_MINUS_CONSTANT_ALPHA:
560 dA = 1.0F - ctx->Color.BlendColor[3];
561 break;
562 case GL_DST_COLOR: /* GL_NV_blend_square */
563 dA = (GLfloat) Ad * ascale;
564 break;
565 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
566 dA = 1.0F - (GLfloat) Ad * ascale;
567 break;
568 default:
569 /* this should never happen */
570 dA = 0.0F;
571 _mesa_problem(ctx, "Bad blend dest A factor in do_blend");
572 return;
573 }
574
575 /* Due to round-off problems we have to clamp against zero. */
576 /* Optimization: we don't have to do this for all src & dst factors */
577 if (dA < 0.0F) dA = 0.0F;
578 if (dR < 0.0F) dR = 0.0F;
579 if (dG < 0.0F) dG = 0.0F;
580 if (dB < 0.0F) dB = 0.0F;
581 if (sA < 0.0F) sA = 0.0F;
582 if (sR < 0.0F) sR = 0.0F;
583 if (sG < 0.0F) sG = 0.0F;
584 if (sB < 0.0F) sB = 0.0F;
585
586 ASSERT( sR <= 1.0 );
587 ASSERT( sG <= 1.0 );
588 ASSERT( sB <= 1.0 );
589 ASSERT( sA <= 1.0 );
590 ASSERT( dR <= 1.0 );
591 ASSERT( dG <= 1.0 );
592 ASSERT( dB <= 1.0 );
593 ASSERT( dA <= 1.0 );
594
595 /* compute blended color */
596 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
597 r = Rs * sR + Rd * dR + 0.5F;
598 g = Gs * sG + Gd * dG + 0.5F;
599 b = Bs * sB + Bd * dB + 0.5F;
600 a = As * sA + Ad * dA + 0.5F;
601 }
602 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
603 r = Rs * sR - Rd * dR + 0.5F;
604 g = Gs * sG - Gd * dG + 0.5F;
605 b = Bs * sB - Bd * dB + 0.5F;
606 a = As * sA - Ad * dA + 0.5F;
607 }
608 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
609 r = Rd * dR - Rs * sR + 0.5F;
610 g = Gd * dG - Gs * sG + 0.5F;
611 b = Bd * dB - Bs * sB + 0.5F;
612 a = Ad * dA - As * sA + 0.5F;
613 }
614 else {
615 /* should never get here */
616 r = g = b = a = 0.0F; /* silence uninitialized var warning */
617 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
618 }
619
620 /* final clamping */
621 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
622 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
623 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
624 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
625 }
626 }
627 }
628
629
630
631
632
633 /*
634 * Analyze current blending parameters to pick fastest blending function.
635 * Result: the ctx->Color.BlendFunc pointer is updated.
636 */
637 void _swrast_choose_blend_func( GLcontext *ctx )
638 {
639 const GLenum eq = ctx->Color.BlendEquation;
640 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
641 const GLenum dstRGB = ctx->Color.BlendDstRGB;
642 const GLenum srcA = ctx->Color.BlendSrcA;
643 const GLenum dstA = ctx->Color.BlendDstA;
644
645 if (srcRGB != srcA || dstRGB != dstA) {
646 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
647 }
648 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
649 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
650 #if defined(USE_MMX_ASM)
651 if ( cpu_has_mmx ) {
652 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency;
653 }
654 else
655 #endif
656 SWRAST_CONTEXT(ctx)->BlendFunc = blend_transparency;
657 }
658 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
659 SWRAST_CONTEXT(ctx)->BlendFunc = blend_add;
660 }
661 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
662 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
663 ||
664 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
665 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
666 #if defined(USE_MMX_ASM)
667 if ( cpu_has_mmx ) {
668 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_modulate;
669 }
670 else
671 #endif
672 SWRAST_CONTEXT(ctx)->BlendFunc = blend_modulate;
673 }
674 else if (eq==GL_MIN_EXT) {
675 SWRAST_CONTEXT(ctx)->BlendFunc = blend_min;
676 }
677 else if (eq==GL_MAX_EXT) {
678 SWRAST_CONTEXT(ctx)->BlendFunc = blend_max;
679 }
680 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
681 SWRAST_CONTEXT(ctx)->BlendFunc = blend_noop;
682 }
683 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
684 SWRAST_CONTEXT(ctx)->BlendFunc = blend_replace;
685 }
686 else {
687 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
688 }
689 }
690
691
692
693 /*
694 * Apply the blending operator to a span of pixels.
695 * We can handle horizontal runs of pixels (spans) or arrays of x/y
696 * pixel coordinates.
697 */
698 void
699 _mesa_blend_span( GLcontext *ctx, const struct sw_span *span,
700 GLchan rgba[][4] )
701 {
702 SWcontext *swrast = SWRAST_CONTEXT(ctx);
703 GLchan framebuffer[MAX_WIDTH][4];
704
705 ASSERT(span->end <= MAX_WIDTH);
706 ASSERT(span->arrayMask & SPAN_RGBA);
707 ASSERT(!ctx->Color.ColorLogicOpEnabled);
708
709 /* Read span of current frame buffer pixels */
710 if (span->arrayMask & SPAN_XY) {
711 /* array of x/y pixel coords */
712 (*swrast->Driver.ReadRGBAPixels)( ctx, span->end,
713 span->xArray, span->yArray,
714 framebuffer, span->mask );
715 if (swrast->_RasterMask & ALPHABUF_BIT) {
716 _mesa_read_alpha_pixels( ctx, span->end, span->xArray, span->yArray,
717 framebuffer, span->mask );
718 }
719 }
720 else {
721 /* horizontal run of pixels */
722 _mesa_read_rgba_span( ctx, ctx->DrawBuffer, span->end,
723 span->x, span->y, framebuffer );
724 }
725
726 SWRAST_CONTEXT(ctx)->BlendFunc( ctx, span->end, span->mask, rgba,
727 (const GLchan (*)[4]) framebuffer );
728 }