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