Committing in .
[mesa.git] / src / mesa / swrast / s_blend.c
1 /* $Id: s_blend.c,v 1.25 2002/10/17 15:26:39 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 "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 GLchan 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 = CLAMP( rgba[i][ACOMP], 0.0F, CHAN_MAXF ) * t +
157 CLAMP( dest[i][ACOMP], 0.0F, CHAN_MAXF ) * (1.0F - t);
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 #if CHAN_TYPE == GL_FLOAT
191 /* don't RGB clamp to max */
192 GLfloat a = CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF) + dest[i][ACOMP];
193 rgba[i][RCOMP] += dest[i][RCOMP];
194 rgba[i][GCOMP] += dest[i][GCOMP];
195 rgba[i][BCOMP] += dest[i][BCOMP];
196 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAXF );
197 #else
198 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
199 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
200 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
201 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
202 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
203 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
204 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
205 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
206 #endif
207 }
208 }
209 }
210
211
212
213 /*
214 * Blend min function (for GL_EXT_blend_minmax)
215 */
216 static void _BLENDAPI
217 blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
218 GLchan rgba[][4], CONST GLchan dest[][4] )
219 {
220 GLuint i;
221 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
222 (void) ctx;
223
224 for (i=0;i<n;i++) {
225 if (mask[i]) {
226 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
227 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
228 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
229 #if CHAN_TYPE == GL_FLOAT
230 rgba[i][ACOMP] = (GLchan) MIN2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
231 dest[i][ACOMP]);
232 #else
233 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
234 #endif
235 }
236 }
237 }
238
239
240
241 /*
242 * Blend max function (for GL_EXT_blend_minmax)
243 */
244 static void _BLENDAPI
245 blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
246 GLchan rgba[][4], CONST GLchan dest[][4] )
247 {
248 GLuint i;
249 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
250 (void) ctx;
251
252 for (i=0;i<n;i++) {
253 if (mask[i]) {
254 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
255 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
256 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
257 #if CHAN_TYPE == GL_FLOAT
258 rgba[i][ACOMP] = (GLchan) MAX2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
259 dest[i][ACOMP]);
260 #else
261 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
262 #endif
263 }
264 }
265 }
266
267
268
269 /*
270 * Modulate: result = src * dest
271 */
272 static void _BLENDAPI
273 blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
274 GLchan rgba[][4], CONST GLchan dest[][4] )
275 {
276 GLuint i;
277 (void) ctx;
278
279 for (i=0;i<n;i++) {
280 if (mask[i]) {
281 #if CHAN_TYPE == GL_FLOAT
282 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
283 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
284 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
285 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
286 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
287 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
288 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
289 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
290 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
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 #else
296 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 255) >> 8;
297 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 255) >> 8;
298 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 255) >> 8;
299 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 255) >> 8;
300 rgba[i][RCOMP] = (GLchan) r;
301 rgba[i][GCOMP] = (GLchan) g;
302 rgba[i][BCOMP] = (GLchan) b;
303 rgba[i][ACOMP] = (GLchan) a;
304 #endif
305 }
306 }
307 }
308
309
310
311 /*
312 * General case blend pixels.
313 * Input: n - number of pixels
314 * mask - the usual write mask
315 * In/Out: rgba - the incoming and modified pixels
316 * Input: dest - the pixels from the dest color buffer
317 */
318 static void _BLENDAPI
319 blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
320 GLchan rgba[][4], CONST GLchan dest[][4] )
321 {
322 const GLfloat rscale = 1.0F / CHAN_MAXF;
323 const GLfloat gscale = 1.0F / CHAN_MAXF;
324 const GLfloat bscale = 1.0F / CHAN_MAXF;
325 const GLfloat ascale = 1.0F / CHAN_MAXF;
326 GLuint i;
327
328 for (i=0;i<n;i++) {
329 if (mask[i]) {
330 #if CHAN_TYPE == GL_FLOAT
331 GLfloat Rs, Gs, Bs, As; /* Source colors */
332 GLfloat Rd, Gd, Bd, Ad; /* Dest colors */
333 #else
334 GLint Rs, Gs, Bs, As; /* Source colors */
335 GLint Rd, Gd, Bd, Ad; /* Dest colors */
336 #endif
337 GLfloat sR, sG, sB, sA; /* Source scaling */
338 GLfloat dR, dG, dB, dA; /* Dest scaling */
339 GLfloat r, g, b, a; /* result color */
340
341 /* Incoming/source Color */
342 Rs = rgba[i][RCOMP];
343 Gs = rgba[i][GCOMP];
344 Bs = rgba[i][BCOMP];
345 As = rgba[i][ACOMP];
346 #if CHAN_TYPE == GL_FLOAT
347 /* clamp */
348 Rs = MIN2(Rs, CHAN_MAXF);
349 Gs = MIN2(Gs, CHAN_MAXF);
350 Bs = MIN2(Bs, CHAN_MAXF);
351 As = MIN2(As, CHAN_MAXF);
352 #endif
353
354 /* Frame buffer/dest color */
355 Rd = dest[i][RCOMP];
356 Gd = dest[i][GCOMP];
357 Bd = dest[i][BCOMP];
358 Ad = dest[i][ACOMP];
359 #if CHAN_TYPE == GL_FLOAT
360 /* clamp */
361 Rd = MIN2(Rd, CHAN_MAXF);
362 Gd = MIN2(Gd, CHAN_MAXF);
363 Bd = MIN2(Bd, CHAN_MAXF);
364 Ad = MIN2(Ad, CHAN_MAXF);
365 #endif
366
367 /* Source RGB factor */
368 switch (ctx->Color.BlendSrcRGB) {
369 case GL_ZERO:
370 sR = sG = sB = 0.0F;
371 break;
372 case GL_ONE:
373 sR = sG = sB = 1.0F;
374 break;
375 case GL_DST_COLOR:
376 sR = (GLfloat) Rd * rscale;
377 sG = (GLfloat) Gd * gscale;
378 sB = (GLfloat) Bd * bscale;
379 break;
380 case GL_ONE_MINUS_DST_COLOR:
381 sR = 1.0F - (GLfloat) Rd * rscale;
382 sG = 1.0F - (GLfloat) Gd * gscale;
383 sB = 1.0F - (GLfloat) Bd * bscale;
384 break;
385 case GL_SRC_ALPHA:
386 sR = sG = sB = (GLfloat) As * ascale;
387 break;
388 case GL_ONE_MINUS_SRC_ALPHA:
389 sR = sG = sB = 1.0F - (GLfloat) As * ascale;
390 break;
391 case GL_DST_ALPHA:
392 sR = sG = sB = (GLfloat) Ad * ascale;
393 break;
394 case GL_ONE_MINUS_DST_ALPHA:
395 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
396 break;
397 case GL_SRC_ALPHA_SATURATE:
398 if (As < CHAN_MAX - Ad) {
399 sR = sG = sB = (GLfloat) As * ascale;
400 }
401 else {
402 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
403 }
404 break;
405 case GL_CONSTANT_COLOR:
406 sR = ctx->Color.BlendColor[0];
407 sG = ctx->Color.BlendColor[1];
408 sB = ctx->Color.BlendColor[2];
409 break;
410 case GL_ONE_MINUS_CONSTANT_COLOR:
411 sR = 1.0F - ctx->Color.BlendColor[0];
412 sG = 1.0F - ctx->Color.BlendColor[1];
413 sB = 1.0F - ctx->Color.BlendColor[2];
414 break;
415 case GL_CONSTANT_ALPHA:
416 sR = sG = sB = ctx->Color.BlendColor[3];
417 break;
418 case GL_ONE_MINUS_CONSTANT_ALPHA:
419 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
420 break;
421 case GL_SRC_COLOR: /* GL_NV_blend_square */
422 sR = (GLfloat) Rs * rscale;
423 sG = (GLfloat) Gs * gscale;
424 sB = (GLfloat) Bs * bscale;
425 break;
426 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
427 sR = 1.0F - (GLfloat) Rs * rscale;
428 sG = 1.0F - (GLfloat) Gs * gscale;
429 sB = 1.0F - (GLfloat) Bs * bscale;
430 break;
431 default:
432 /* this should never happen */
433 _mesa_problem(ctx, "Bad blend source RGB factor in do_blend");
434 return;
435 }
436
437 /* Source Alpha factor */
438 switch (ctx->Color.BlendSrcA) {
439 case GL_ZERO:
440 sA = 0.0F;
441 break;
442 case GL_ONE:
443 sA = 1.0F;
444 break;
445 case GL_DST_COLOR:
446 sA = (GLfloat) Ad * ascale;
447 break;
448 case GL_ONE_MINUS_DST_COLOR:
449 sA = 1.0F - (GLfloat) Ad * ascale;
450 break;
451 case GL_SRC_ALPHA:
452 sA = (GLfloat) As * ascale;
453 break;
454 case GL_ONE_MINUS_SRC_ALPHA:
455 sA = 1.0F - (GLfloat) As * ascale;
456 break;
457 case GL_DST_ALPHA:
458 sA =(GLfloat) Ad * ascale;
459 break;
460 case GL_ONE_MINUS_DST_ALPHA:
461 sA = 1.0F - (GLfloat) Ad * ascale;
462 break;
463 case GL_SRC_ALPHA_SATURATE:
464 sA = 1.0;
465 break;
466 case GL_CONSTANT_COLOR:
467 sA = ctx->Color.BlendColor[3];
468 break;
469 case GL_ONE_MINUS_CONSTANT_COLOR:
470 sA = 1.0F - ctx->Color.BlendColor[3];
471 break;
472 case GL_CONSTANT_ALPHA:
473 sA = ctx->Color.BlendColor[3];
474 break;
475 case GL_ONE_MINUS_CONSTANT_ALPHA:
476 sA = 1.0F - ctx->Color.BlendColor[3];
477 break;
478 case GL_SRC_COLOR: /* GL_NV_blend_square */
479 sA = (GLfloat) As * ascale;
480 break;
481 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
482 sA = 1.0F - (GLfloat) As * ascale;
483 break;
484 default:
485 /* this should never happen */
486 sA = 0.0F;
487 _mesa_problem(ctx, "Bad blend source A factor in do_blend");
488 }
489
490 /* Dest RGB factor */
491 switch (ctx->Color.BlendDstRGB) {
492 case GL_ZERO:
493 dR = dG = dB = 0.0F;
494 break;
495 case GL_ONE:
496 dR = dG = dB = 1.0F;
497 break;
498 case GL_SRC_COLOR:
499 dR = (GLfloat) Rs * rscale;
500 dG = (GLfloat) Gs * gscale;
501 dB = (GLfloat) Bs * bscale;
502 break;
503 case GL_ONE_MINUS_SRC_COLOR:
504 dR = 1.0F - (GLfloat) Rs * rscale;
505 dG = 1.0F - (GLfloat) Gs * gscale;
506 dB = 1.0F - (GLfloat) Bs * bscale;
507 break;
508 case GL_SRC_ALPHA:
509 dR = dG = dB = (GLfloat) As * ascale;
510 break;
511 case GL_ONE_MINUS_SRC_ALPHA:
512 dR = dG = dB = 1.0F - (GLfloat) As * ascale;
513 break;
514 case GL_DST_ALPHA:
515 dR = dG = dB = (GLfloat) Ad * ascale;
516 break;
517 case GL_ONE_MINUS_DST_ALPHA:
518 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
519 break;
520 case GL_CONSTANT_COLOR:
521 dR = ctx->Color.BlendColor[0];
522 dG = ctx->Color.BlendColor[1];
523 dB = ctx->Color.BlendColor[2];
524 break;
525 case GL_ONE_MINUS_CONSTANT_COLOR:
526 dR = 1.0F - ctx->Color.BlendColor[0];
527 dG = 1.0F - ctx->Color.BlendColor[1];
528 dB = 1.0F - ctx->Color.BlendColor[2];
529 break;
530 case GL_CONSTANT_ALPHA:
531 dR = dG = dB = ctx->Color.BlendColor[3];
532 break;
533 case GL_ONE_MINUS_CONSTANT_ALPHA:
534 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
535 break;
536 case GL_DST_COLOR: /* GL_NV_blend_square */
537 dR = (GLfloat) Rd * rscale;
538 dG = (GLfloat) Gd * gscale;
539 dB = (GLfloat) Bd * bscale;
540 break;
541 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
542 dR = 1.0F - (GLfloat) Rd * rscale;
543 dG = 1.0F - (GLfloat) Gd * gscale;
544 dB = 1.0F - (GLfloat) Bd * bscale;
545 break;
546 default:
547 /* this should never happen */
548 dR = dG = dB = 0.0F;
549 _mesa_problem(ctx, "Bad blend dest RGB factor in do_blend");
550 }
551
552 /* Dest Alpha factor */
553 switch (ctx->Color.BlendDstA) {
554 case GL_ZERO:
555 dA = 0.0F;
556 break;
557 case GL_ONE:
558 dA = 1.0F;
559 break;
560 case GL_SRC_COLOR:
561 dA = (GLfloat) As * ascale;
562 break;
563 case GL_ONE_MINUS_SRC_COLOR:
564 dA = 1.0F - (GLfloat) As * ascale;
565 break;
566 case GL_SRC_ALPHA:
567 dA = (GLfloat) As * ascale;
568 break;
569 case GL_ONE_MINUS_SRC_ALPHA:
570 dA = 1.0F - (GLfloat) As * ascale;
571 break;
572 case GL_DST_ALPHA:
573 dA = (GLfloat) Ad * ascale;
574 break;
575 case GL_ONE_MINUS_DST_ALPHA:
576 dA = 1.0F - (GLfloat) Ad * ascale;
577 break;
578 case GL_CONSTANT_COLOR:
579 dA = ctx->Color.BlendColor[3];
580 break;
581 case GL_ONE_MINUS_CONSTANT_COLOR:
582 dA = 1.0F - ctx->Color.BlendColor[3];
583 break;
584 case GL_CONSTANT_ALPHA:
585 dA = ctx->Color.BlendColor[3];
586 break;
587 case GL_ONE_MINUS_CONSTANT_ALPHA:
588 dA = 1.0F - ctx->Color.BlendColor[3];
589 break;
590 case GL_DST_COLOR: /* GL_NV_blend_square */
591 dA = (GLfloat) Ad * ascale;
592 break;
593 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
594 dA = 1.0F - (GLfloat) Ad * ascale;
595 break;
596 default:
597 /* this should never happen */
598 dA = 0.0F;
599 _mesa_problem(ctx, "Bad blend dest A factor in do_blend");
600 return;
601 }
602
603 /* Due to round-off problems we have to clamp against zero. */
604 /* Optimization: we don't have to do this for all src & dst factors */
605 if (dA < 0.0F) dA = 0.0F;
606 if (dR < 0.0F) dR = 0.0F;
607 if (dG < 0.0F) dG = 0.0F;
608 if (dB < 0.0F) dB = 0.0F;
609 if (sA < 0.0F) sA = 0.0F;
610 if (sR < 0.0F) sR = 0.0F;
611 if (sG < 0.0F) sG = 0.0F;
612 if (sB < 0.0F) sB = 0.0F;
613
614 ASSERT( sR <= 1.0 );
615 ASSERT( sG <= 1.0 );
616 ASSERT( sB <= 1.0 );
617 ASSERT( sA <= 1.0 );
618 ASSERT( dR <= 1.0 );
619 ASSERT( dG <= 1.0 );
620 ASSERT( dB <= 1.0 );
621 ASSERT( dA <= 1.0 );
622
623 /* compute blended color */
624 #if CHAN_TYPE == GL_FLOAT
625 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
626 r = Rs * sR + Rd * dR;
627 g = Gs * sG + Gd * dG;
628 b = Bs * sB + Bd * dB;
629 a = As * sA + Ad * dA;
630 }
631 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
632 r = Rs * sR - Rd * dR;
633 g = Gs * sG - Gd * dG;
634 b = Bs * sB - Bd * dB;
635 a = As * sA - Ad * dA;
636 }
637 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
638 r = Rd * dR - Rs * sR;
639 g = Gd * dG - Gs * sG;
640 b = Bd * dB - Bs * sB;
641 a = Ad * dA - As * sA;
642 }
643 else {
644 /* should never get here */
645 r = g = b = a = 0.0F; /* silence uninitialized var warning */
646 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
647 }
648
649 /* final clamping */
650 rgba[i][RCOMP] = MAX2( r, 0.0F );
651 rgba[i][GCOMP] = MAX2( g, 0.0F );
652 rgba[i][BCOMP] = MAX2( b, 0.0F );
653 rgba[i][ACOMP] = CLAMP( a, 0.0F, CHAN_MAXF );
654 #else
655 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
656 r = Rs * sR + Rd * dR + 0.5F;
657 g = Gs * sG + Gd * dG + 0.5F;
658 b = Bs * sB + Bd * dB + 0.5F;
659 a = As * sA + Ad * dA + 0.5F;
660 }
661 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
662 r = Rs * sR - Rd * dR + 0.5F;
663 g = Gs * sG - Gd * dG + 0.5F;
664 b = Bs * sB - Bd * dB + 0.5F;
665 a = As * sA - Ad * dA + 0.5F;
666 }
667 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
668 r = Rd * dR - Rs * sR + 0.5F;
669 g = Gd * dG - Gs * sG + 0.5F;
670 b = Bd * dB - Bs * sB + 0.5F;
671 a = Ad * dA - As * sA + 0.5F;
672 }
673 else {
674 /* should never get here */
675 r = g = b = a = 0.0F; /* silence uninitialized var warning */
676 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
677 }
678
679 /* final clamping */
680 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
681 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
682 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
683 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
684 #endif
685 }
686 }
687 }
688
689
690
691
692
693 /*
694 * Analyze current blending parameters to pick fastest blending function.
695 * Result: the ctx->Color.BlendFunc pointer is updated.
696 */
697 void _swrast_choose_blend_func( GLcontext *ctx )
698 {
699 const GLenum eq = ctx->Color.BlendEquation;
700 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
701 const GLenum dstRGB = ctx->Color.BlendDstRGB;
702 const GLenum srcA = ctx->Color.BlendSrcA;
703 const GLenum dstA = ctx->Color.BlendDstA;
704
705 if (srcRGB != srcA || dstRGB != dstA) {
706 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
707 }
708 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
709 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
710 #if defined(USE_MMX_ASM)
711 if ( cpu_has_mmx ) {
712 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency;
713 }
714 else
715 #endif
716 SWRAST_CONTEXT(ctx)->BlendFunc = blend_transparency;
717 }
718 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
719 #if defined(USE_MMX_ASM)
720 if ( cpu_has_mmx ) {
721 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_add;
722 }
723 else
724 #endif
725 SWRAST_CONTEXT(ctx)->BlendFunc = blend_add;
726 }
727 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
728 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
729 ||
730 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
731 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
732 #if defined(USE_MMX_ASM)
733 if ( cpu_has_mmx ) {
734 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_modulate;
735 }
736 else
737 #endif
738 SWRAST_CONTEXT(ctx)->BlendFunc = blend_modulate;
739 }
740 else if (eq==GL_MIN_EXT) {
741 #if defined(USE_MMX_ASM)
742 if ( cpu_has_mmx ) {
743 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_min;
744 }
745 else
746 #endif
747 SWRAST_CONTEXT(ctx)->BlendFunc = blend_min;
748 }
749 else if (eq==GL_MAX_EXT) {
750 #if defined(USE_MMX_ASM)
751 if ( cpu_has_mmx ) {
752 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_max;
753 }
754 else
755 #endif
756 SWRAST_CONTEXT(ctx)->BlendFunc = blend_max;
757 }
758 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
759 SWRAST_CONTEXT(ctx)->BlendFunc = blend_noop;
760 }
761 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
762 SWRAST_CONTEXT(ctx)->BlendFunc = blend_replace;
763 }
764 else {
765 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
766 }
767 }
768
769
770
771 /*
772 * Apply the blending operator to a span of pixels.
773 * We can handle horizontal runs of pixels (spans) or arrays of x/y
774 * pixel coordinates.
775 */
776 void
777 _mesa_blend_span( GLcontext *ctx, const struct sw_span *span,
778 GLchan rgba[][4] )
779 {
780 SWcontext *swrast = SWRAST_CONTEXT(ctx);
781 GLchan framebuffer[MAX_WIDTH][4];
782
783 ASSERT(span->end <= MAX_WIDTH);
784 ASSERT(span->arrayMask & SPAN_RGBA);
785 ASSERT(!ctx->Color.ColorLogicOpEnabled);
786
787 /* Read span of current frame buffer pixels */
788 if (span->arrayMask & SPAN_XY) {
789 /* array of x/y pixel coords */
790 (*swrast->Driver.ReadRGBAPixels)( ctx, span->end,
791 span->array->x, span->array->y,
792 framebuffer, span->array->mask );
793 if (swrast->_RasterMask & ALPHABUF_BIT) {
794 _mesa_read_alpha_pixels( ctx, span->end,
795 span->array->x, span->array->y,
796 framebuffer, span->array->mask );
797 }
798 }
799 else {
800 /* horizontal run of pixels */
801 _mesa_read_rgba_span( ctx, ctx->DrawBuffer, span->end,
802 span->x, span->y, framebuffer );
803 }
804
805 SWRAST_CONTEXT(ctx)->BlendFunc( ctx, span->end, span->array->mask, rgba,
806 (const GLchan (*)[4]) framebuffer );
807 }