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