struct sw_span is again allocated on the stack, but the arrays of span
[mesa.git] / src / mesa / swrast / s_blend.c
1 /* $Id: s_blend.c,v 1.24 2002/08/07 00:45:07 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 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 #if CHAN_TYPE == GL_FLOAT
322 GLfloat Rs, Gs, Bs, As; /* Source colors */
323 GLfloat Rd, Gd, Bd, Ad; /* Dest colors */
324 #else
325 GLint Rs, Gs, Bs, As; /* Source colors */
326 GLint Rd, Gd, Bd, Ad; /* Dest colors */
327 #endif
328 GLfloat sR, sG, sB, sA; /* Source scaling */
329 GLfloat dR, dG, dB, dA; /* Dest scaling */
330 GLfloat r, g, b, a;
331
332 /* Source Color */
333 Rs = rgba[i][RCOMP];
334 Gs = rgba[i][GCOMP];
335 Bs = rgba[i][BCOMP];
336 As = rgba[i][ACOMP];
337
338 /* Frame buffer color */
339 Rd = dest[i][RCOMP];
340 Gd = dest[i][GCOMP];
341 Bd = dest[i][BCOMP];
342 Ad = dest[i][ACOMP];
343
344 /* Source RGB factor */
345 switch (ctx->Color.BlendSrcRGB) {
346 case GL_ZERO:
347 sR = sG = sB = 0.0F;
348 break;
349 case GL_ONE:
350 sR = sG = sB = 1.0F;
351 break;
352 case GL_DST_COLOR:
353 sR = (GLfloat) Rd * rscale;
354 sG = (GLfloat) Gd * gscale;
355 sB = (GLfloat) Bd * bscale;
356 break;
357 case GL_ONE_MINUS_DST_COLOR:
358 sR = 1.0F - (GLfloat) Rd * rscale;
359 sG = 1.0F - (GLfloat) Gd * gscale;
360 sB = 1.0F - (GLfloat) Bd * bscale;
361 break;
362 case GL_SRC_ALPHA:
363 sR = sG = sB = (GLfloat) As * ascale;
364 break;
365 case GL_ONE_MINUS_SRC_ALPHA:
366 sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
367 break;
368 case GL_DST_ALPHA:
369 sR = sG = sB = (GLfloat) Ad * ascale;
370 break;
371 case GL_ONE_MINUS_DST_ALPHA:
372 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
373 break;
374 case GL_SRC_ALPHA_SATURATE:
375 if (As < CHAN_MAX - Ad) {
376 sR = sG = sB = (GLfloat) As * ascale;
377 }
378 else {
379 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
380 }
381 break;
382 case GL_CONSTANT_COLOR:
383 sR = ctx->Color.BlendColor[0];
384 sG = ctx->Color.BlendColor[1];
385 sB = ctx->Color.BlendColor[2];
386 break;
387 case GL_ONE_MINUS_CONSTANT_COLOR:
388 sR = 1.0F - ctx->Color.BlendColor[0];
389 sG = 1.0F - ctx->Color.BlendColor[1];
390 sB = 1.0F - ctx->Color.BlendColor[2];
391 break;
392 case GL_CONSTANT_ALPHA:
393 sR = sG = sB = ctx->Color.BlendColor[3];
394 break;
395 case GL_ONE_MINUS_CONSTANT_ALPHA:
396 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
397 break;
398 case GL_SRC_COLOR: /* GL_NV_blend_square */
399 sR = (GLfloat) Rs * rscale;
400 sG = (GLfloat) Gs * gscale;
401 sB = (GLfloat) Bs * bscale;
402 break;
403 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
404 sR = 1.0F - (GLfloat) Rs * rscale;
405 sG = 1.0F - (GLfloat) Gs * gscale;
406 sB = 1.0F - (GLfloat) Bs * bscale;
407 break;
408 default:
409 /* this should never happen */
410 _mesa_problem(ctx, "Bad blend source RGB factor in do_blend");
411 return;
412 }
413
414 /* Source Alpha factor */
415 switch (ctx->Color.BlendSrcA) {
416 case GL_ZERO:
417 sA = 0.0F;
418 break;
419 case GL_ONE:
420 sA = 1.0F;
421 break;
422 case GL_DST_COLOR:
423 sA = (GLfloat) Ad * ascale;
424 break;
425 case GL_ONE_MINUS_DST_COLOR:
426 sA = 1.0F - (GLfloat) Ad * ascale;
427 break;
428 case GL_SRC_ALPHA:
429 sA = (GLfloat) As * ascale;
430 break;
431 case GL_ONE_MINUS_SRC_ALPHA:
432 sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
433 break;
434 case GL_DST_ALPHA:
435 sA =(GLfloat) Ad * ascale;
436 break;
437 case GL_ONE_MINUS_DST_ALPHA:
438 sA = 1.0F - (GLfloat) Ad * ascale;
439 break;
440 case GL_SRC_ALPHA_SATURATE:
441 sA = 1.0;
442 break;
443 case GL_CONSTANT_COLOR:
444 sA = ctx->Color.BlendColor[3];
445 break;
446 case GL_ONE_MINUS_CONSTANT_COLOR:
447 sA = 1.0F - ctx->Color.BlendColor[3];
448 break;
449 case GL_CONSTANT_ALPHA:
450 sA = ctx->Color.BlendColor[3];
451 break;
452 case GL_ONE_MINUS_CONSTANT_ALPHA:
453 sA = 1.0F - ctx->Color.BlendColor[3];
454 break;
455 case GL_SRC_COLOR: /* GL_NV_blend_square */
456 sA = (GLfloat) As * ascale;
457 break;
458 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
459 sA = 1.0F - (GLfloat) As * ascale;
460 break;
461 default:
462 /* this should never happen */
463 sA = 0.0F;
464 _mesa_problem(ctx, "Bad blend source A factor in do_blend");
465 }
466
467 /* Dest RGB factor */
468 switch (ctx->Color.BlendDstRGB) {
469 case GL_ZERO:
470 dR = dG = dB = 0.0F;
471 break;
472 case GL_ONE:
473 dR = dG = dB = 1.0F;
474 break;
475 case GL_SRC_COLOR:
476 dR = (GLfloat) Rs * rscale;
477 dG = (GLfloat) Gs * gscale;
478 dB = (GLfloat) Bs * bscale;
479 break;
480 case GL_ONE_MINUS_SRC_COLOR:
481 dR = 1.0F - (GLfloat) Rs * rscale;
482 dG = 1.0F - (GLfloat) Gs * gscale;
483 dB = 1.0F - (GLfloat) Bs * bscale;
484 break;
485 case GL_SRC_ALPHA:
486 dR = dG = dB = (GLfloat) As * ascale;
487 break;
488 case GL_ONE_MINUS_SRC_ALPHA:
489 dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
490 break;
491 case GL_DST_ALPHA:
492 dR = dG = dB = (GLfloat) Ad * ascale;
493 break;
494 case GL_ONE_MINUS_DST_ALPHA:
495 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
496 break;
497 case GL_CONSTANT_COLOR:
498 dR = ctx->Color.BlendColor[0];
499 dG = ctx->Color.BlendColor[1];
500 dB = ctx->Color.BlendColor[2];
501 break;
502 case GL_ONE_MINUS_CONSTANT_COLOR:
503 dR = 1.0F - ctx->Color.BlendColor[0];
504 dG = 1.0F - ctx->Color.BlendColor[1];
505 dB = 1.0F - ctx->Color.BlendColor[2];
506 break;
507 case GL_CONSTANT_ALPHA:
508 dR = dG = dB = ctx->Color.BlendColor[3];
509 break;
510 case GL_ONE_MINUS_CONSTANT_ALPHA:
511 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
512 break;
513 case GL_DST_COLOR: /* GL_NV_blend_square */
514 dR = (GLfloat) Rd * rscale;
515 dG = (GLfloat) Gd * gscale;
516 dB = (GLfloat) Bd * bscale;
517 break;
518 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
519 dR = 1.0F - (GLfloat) Rd * rscale;
520 dG = 1.0F - (GLfloat) Gd * gscale;
521 dB = 1.0F - (GLfloat) Bd * bscale;
522 break;
523 default:
524 /* this should never happen */
525 dR = dG = dB = 0.0F;
526 _mesa_problem(ctx, "Bad blend dest RGB factor in do_blend");
527 }
528
529 /* Dest Alpha factor */
530 switch (ctx->Color.BlendDstA) {
531 case GL_ZERO:
532 dA = 0.0F;
533 break;
534 case GL_ONE:
535 dA = 1.0F;
536 break;
537 case GL_SRC_COLOR:
538 dA = (GLfloat) As * ascale;
539 break;
540 case GL_ONE_MINUS_SRC_COLOR:
541 dA = 1.0F - (GLfloat) As * ascale;
542 break;
543 case GL_SRC_ALPHA:
544 dA = (GLfloat) As * ascale;
545 break;
546 case GL_ONE_MINUS_SRC_ALPHA:
547 dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
548 break;
549 case GL_DST_ALPHA:
550 dA = (GLfloat) Ad * ascale;
551 break;
552 case GL_ONE_MINUS_DST_ALPHA:
553 dA = 1.0F - (GLfloat) Ad * ascale;
554 break;
555 case GL_CONSTANT_COLOR:
556 dA = ctx->Color.BlendColor[3];
557 break;
558 case GL_ONE_MINUS_CONSTANT_COLOR:
559 dA = 1.0F - ctx->Color.BlendColor[3];
560 break;
561 case GL_CONSTANT_ALPHA:
562 dA = ctx->Color.BlendColor[3];
563 break;
564 case GL_ONE_MINUS_CONSTANT_ALPHA:
565 dA = 1.0F - ctx->Color.BlendColor[3];
566 break;
567 case GL_DST_COLOR: /* GL_NV_blend_square */
568 dA = (GLfloat) Ad * ascale;
569 break;
570 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
571 dA = 1.0F - (GLfloat) Ad * ascale;
572 break;
573 default:
574 /* this should never happen */
575 dA = 0.0F;
576 _mesa_problem(ctx, "Bad blend dest A factor in do_blend");
577 return;
578 }
579
580 /* Due to round-off problems we have to clamp against zero. */
581 /* Optimization: we don't have to do this for all src & dst factors */
582 if (dA < 0.0F) dA = 0.0F;
583 if (dR < 0.0F) dR = 0.0F;
584 if (dG < 0.0F) dG = 0.0F;
585 if (dB < 0.0F) dB = 0.0F;
586 if (sA < 0.0F) sA = 0.0F;
587 if (sR < 0.0F) sR = 0.0F;
588 if (sG < 0.0F) sG = 0.0F;
589 if (sB < 0.0F) sB = 0.0F;
590
591 ASSERT( sR <= 1.0 );
592 ASSERT( sG <= 1.0 );
593 ASSERT( sB <= 1.0 );
594 ASSERT( sA <= 1.0 );
595 ASSERT( dR <= 1.0 );
596 ASSERT( dG <= 1.0 );
597 ASSERT( dB <= 1.0 );
598 ASSERT( dA <= 1.0 );
599
600 /* compute blended color */
601 #if CHAN_TYPE == GL_FLOAT
602 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
603 r = Rs * sR + Rd * dR;
604 g = Gs * sG + Gd * dG;
605 b = Bs * sB + Bd * dB;
606 a = As * sA + Ad * dA;
607 }
608 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
609 r = Rs * sR - Rd * dR;
610 g = Gs * sG - Gd * dG;
611 b = Bs * sB - Bd * dB;
612 a = As * sA - Ad * dA;
613 }
614 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
615 r = Rd * dR - Rs * sR;
616 g = Gd * dG - Gs * sG;
617 b = Bd * dB - Bs * sB;
618 a = Ad * dA - As * sA;
619 }
620 else {
621 /* should never get here */
622 r = g = b = a = 0.0F; /* silence uninitialized var warning */
623 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
624 }
625
626 /* final clamping */
627 rgba[i][RCOMP] = CLAMP( r, 0.0F, CHAN_MAXF );
628 rgba[i][GCOMP] = CLAMP( g, 0.0F, CHAN_MAXF );
629 rgba[i][BCOMP] = CLAMP( b, 0.0F, CHAN_MAXF );
630 rgba[i][ACOMP] = CLAMP( a, 0.0F, CHAN_MAXF );
631 #else
632 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
633 r = Rs * sR + Rd * dR + 0.5F;
634 g = Gs * sG + Gd * dG + 0.5F;
635 b = Bs * sB + Bd * dB + 0.5F;
636 a = As * sA + Ad * dA + 0.5F;
637 }
638 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
639 r = Rs * sR - Rd * dR + 0.5F;
640 g = Gs * sG - Gd * dG + 0.5F;
641 b = Bs * sB - Bd * dB + 0.5F;
642 a = As * sA - Ad * dA + 0.5F;
643 }
644 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
645 r = Rd * dR - Rs * sR + 0.5F;
646 g = Gd * dG - Gs * sG + 0.5F;
647 b = Bd * dB - Bs * sB + 0.5F;
648 a = Ad * dA - As * sA + 0.5F;
649 }
650 else {
651 /* should never get here */
652 r = g = b = a = 0.0F; /* silence uninitialized var warning */
653 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
654 }
655
656 /* final clamping */
657 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
658 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
659 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
660 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
661 #endif
662 }
663 }
664 }
665
666
667
668
669
670 /*
671 * Analyze current blending parameters to pick fastest blending function.
672 * Result: the ctx->Color.BlendFunc pointer is updated.
673 */
674 void _swrast_choose_blend_func( GLcontext *ctx )
675 {
676 const GLenum eq = ctx->Color.BlendEquation;
677 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
678 const GLenum dstRGB = ctx->Color.BlendDstRGB;
679 const GLenum srcA = ctx->Color.BlendSrcA;
680 const GLenum dstA = ctx->Color.BlendDstA;
681
682 if (srcRGB != srcA || dstRGB != dstA) {
683 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
684 }
685 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
686 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
687 #if defined(USE_MMX_ASM)
688 if ( cpu_has_mmx ) {
689 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency;
690 }
691 else
692 #endif
693 SWRAST_CONTEXT(ctx)->BlendFunc = blend_transparency;
694 }
695 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
696 #if defined(USE_MMX_ASM)
697 if ( cpu_has_mmx ) {
698 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_add;
699 }
700 else
701 #endif
702 SWRAST_CONTEXT(ctx)->BlendFunc = blend_add;
703 }
704 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
705 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
706 ||
707 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
708 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
709 #if defined(USE_MMX_ASM)
710 if ( cpu_has_mmx ) {
711 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_modulate;
712 }
713 else
714 #endif
715 SWRAST_CONTEXT(ctx)->BlendFunc = blend_modulate;
716 }
717 else if (eq==GL_MIN_EXT) {
718 #if defined(USE_MMX_ASM)
719 if ( cpu_has_mmx ) {
720 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_min;
721 }
722 else
723 #endif
724 SWRAST_CONTEXT(ctx)->BlendFunc = blend_min;
725 }
726 else if (eq==GL_MAX_EXT) {
727 #if defined(USE_MMX_ASM)
728 if ( cpu_has_mmx ) {
729 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_max;
730 }
731 else
732 #endif
733 SWRAST_CONTEXT(ctx)->BlendFunc = blend_max;
734 }
735 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
736 SWRAST_CONTEXT(ctx)->BlendFunc = blend_noop;
737 }
738 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
739 SWRAST_CONTEXT(ctx)->BlendFunc = blend_replace;
740 }
741 else {
742 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
743 }
744 }
745
746
747
748 /*
749 * Apply the blending operator to a span of pixels.
750 * We can handle horizontal runs of pixels (spans) or arrays of x/y
751 * pixel coordinates.
752 */
753 void
754 _mesa_blend_span( GLcontext *ctx, const struct sw_span *span,
755 GLchan rgba[][4] )
756 {
757 SWcontext *swrast = SWRAST_CONTEXT(ctx);
758 GLchan framebuffer[MAX_WIDTH][4];
759
760 ASSERT(span->end <= MAX_WIDTH);
761 ASSERT(span->arrayMask & SPAN_RGBA);
762 ASSERT(!ctx->Color.ColorLogicOpEnabled);
763
764 /* Read span of current frame buffer pixels */
765 if (span->arrayMask & SPAN_XY) {
766 /* array of x/y pixel coords */
767 (*swrast->Driver.ReadRGBAPixels)( ctx, span->end,
768 span->array->x, span->array->y,
769 framebuffer, span->array->mask );
770 if (swrast->_RasterMask & ALPHABUF_BIT) {
771 _mesa_read_alpha_pixels( ctx, span->end,
772 span->array->x, span->array->y,
773 framebuffer, span->array->mask );
774 }
775 }
776 else {
777 /* horizontal run of pixels */
778 _mesa_read_rgba_span( ctx, ctx->DrawBuffer, span->end,
779 span->x, span->y, framebuffer );
780 }
781
782 SWRAST_CONTEXT(ctx)->BlendFunc( ctx, span->end, span->array->mask, rgba,
783 (const GLchan (*)[4]) framebuffer );
784 }