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