9f550223ee31d26aea3912e613a368cf09268390
[mesa.git] / src / mesa / swrast / s_blend.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.0
4 *
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /*
26 * Regarding GL_NV_blend_square:
27 *
28 * Portions of this software may use or implement intellectual
29 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
30 * any and all warranties with respect to such intellectual property,
31 * including any use thereof or modifications thereto.
32 */
33
34
35 #include "glheader.h"
36 #include "context.h"
37 #include "colormac.h"
38 #include "macros.h"
39
40 #include "s_alphabuf.h"
41 #include "s_blend.h"
42 #include "s_context.h"
43 #include "s_span.h"
44
45
46 #if defined(USE_MMX_ASM)
47 #include "x86/mmx.h"
48 #include "x86/common_x86_asm.h"
49 #define _BLENDAPI _ASMAPI
50 #else
51 #define _BLENDAPI
52 #endif
53
54
55 /*
56 * Special case for glBlendFunc(GL_ZERO, GL_ONE)
57 */
58 static void _BLENDAPI
59 blend_noop( GLcontext *ctx, GLuint n, const GLubyte mask[],
60 GLchan rgba[][4], CONST GLchan dest[][4] )
61 {
62 GLuint i;
63 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
64 ASSERT(ctx->Color.BlendSrcRGB==GL_ZERO);
65 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
66 (void) ctx;
67
68 for (i = 0; i < n; i++) {
69 if (mask[i]) {
70 COPY_CHAN4( rgba[i], dest[i] );
71 }
72 }
73 }
74
75
76 /*
77 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
78 */
79 static void _BLENDAPI
80 blend_replace( GLcontext *ctx, GLuint n, const GLubyte mask[],
81 GLchan rgba[][4], CONST GLchan dest[][4] )
82 {
83 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
84 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
85 ASSERT(ctx->Color.BlendDstRGB==GL_ZERO);
86 (void) ctx;
87 (void) n;
88 (void) mask;
89 (void) rgba;
90 (void) dest;
91 }
92
93
94 /*
95 * Common transparency blending mode.
96 */
97 static void _BLENDAPI
98 blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
99 GLchan rgba[][4], CONST GLchan dest[][4] )
100 {
101 GLuint i;
102 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
103 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
104 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
105 (void) ctx;
106
107 for (i=0;i<n;i++) {
108 if (mask[i]) {
109 const GLchan t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */
110 if (t == 0) {
111 /* 0% alpha */
112 rgba[i][RCOMP] = dest[i][RCOMP];
113 rgba[i][GCOMP] = dest[i][GCOMP];
114 rgba[i][BCOMP] = dest[i][BCOMP];
115 rgba[i][ACOMP] = dest[i][ACOMP];
116 }
117 else if (t == CHAN_MAX) {
118 /* 100% alpha, no-op */
119 }
120 else {
121 #if 0
122 /* This is pretty close, but Glean complains */
123 const GLint s = CHAN_MAX - t;
124 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
125 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
126 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
127 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
128 #elif 0
129 /* This is slower but satisfies Glean */
130 const GLint s = CHAN_MAX - t;
131 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
132 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
133 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
134 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
135 #else
136 #if CHAN_BITS == 8
137 /* This satisfies Glean and should be reasonably fast */
138 /* Contributed by Nathan Hand */
139 #if 0
140 #define DIV255(X) (((X) << 8) + (X) + 256) >> 16
141 #else
142 GLint temp;
143 #define DIV255(X) (temp = (X), ((temp << 8) + temp + 256) >> 16)
144 #endif
145 const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
146 const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
147 const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
148 const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
149
150 #undef DIV255
151 #elif CHAN_BITS == 16
152 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
153 const GLint r = (GLint) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
154 const GLint g = (GLint) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
155 const GLint b = (GLint) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
156 const GLint a = (GLint) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
157 #else /* CHAN_BITS == 32 */
158 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
159 const GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP];
160 const GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP];
161 const GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP];
162 const GLfloat a = CLAMP( rgba[i][ACOMP], 0.0F, CHAN_MAXF ) * t +
163 CLAMP( dest[i][ACOMP], 0.0F, CHAN_MAXF ) * (1.0F - t);
164 #endif
165 #endif
166 ASSERT(r <= CHAN_MAX);
167 ASSERT(g <= CHAN_MAX);
168 ASSERT(b <= CHAN_MAX);
169 ASSERT(a <= CHAN_MAX);
170 rgba[i][RCOMP] = (GLchan) r;
171 rgba[i][GCOMP] = (GLchan) g;
172 rgba[i][BCOMP] = (GLchan) b;
173 rgba[i][ACOMP] = (GLchan) a;
174 }
175 }
176 }
177 }
178
179
180
181 /*
182 * Add src and dest.
183 */
184 static void _BLENDAPI
185 blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
186 GLchan rgba[][4], CONST GLchan dest[][4] )
187 {
188 GLuint i;
189 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
190 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
191 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
192 (void) ctx;
193
194 for (i=0;i<n;i++) {
195 if (mask[i]) {
196 #if CHAN_TYPE == GL_FLOAT
197 /* don't RGB clamp to max */
198 GLfloat a = CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF) + dest[i][ACOMP];
199 rgba[i][RCOMP] += dest[i][RCOMP];
200 rgba[i][GCOMP] += dest[i][GCOMP];
201 rgba[i][BCOMP] += dest[i][BCOMP];
202 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAXF );
203 #else
204 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
205 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
206 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
207 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
208 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
209 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
210 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
211 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
212 #endif
213 }
214 }
215 }
216
217
218
219 /*
220 * Blend min function (for GL_EXT_blend_minmax)
221 */
222 static void _BLENDAPI
223 blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
224 GLchan rgba[][4], CONST GLchan dest[][4] )
225 {
226 GLuint i;
227 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
228 (void) ctx;
229
230 for (i=0;i<n;i++) {
231 if (mask[i]) {
232 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
233 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
234 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
235 #if CHAN_TYPE == GL_FLOAT
236 rgba[i][ACOMP] = (GLchan) MIN2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
237 dest[i][ACOMP]);
238 #else
239 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
240 #endif
241 }
242 }
243 }
244
245
246
247 /*
248 * Blend max function (for GL_EXT_blend_minmax)
249 */
250 static void _BLENDAPI
251 blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
252 GLchan rgba[][4], CONST GLchan dest[][4] )
253 {
254 GLuint i;
255 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
256 (void) ctx;
257
258 for (i=0;i<n;i++) {
259 if (mask[i]) {
260 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
261 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
262 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
263 #if CHAN_TYPE == GL_FLOAT
264 rgba[i][ACOMP] = (GLchan) MAX2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
265 dest[i][ACOMP]);
266 #else
267 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
268 #endif
269 }
270 }
271 }
272
273
274
275 /*
276 * Modulate: result = src * dest
277 */
278 static void _BLENDAPI
279 blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
280 GLchan rgba[][4], CONST GLchan dest[][4] )
281 {
282 GLuint i;
283 (void) ctx;
284
285 for (i=0;i<n;i++) {
286 if (mask[i]) {
287 #if CHAN_TYPE == GL_FLOAT
288 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
289 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
290 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
291 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
292 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
293 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
294 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
295 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
296 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
297 rgba[i][RCOMP] = (GLchan) r;
298 rgba[i][GCOMP] = (GLchan) g;
299 rgba[i][BCOMP] = (GLchan) b;
300 rgba[i][ACOMP] = (GLchan) a;
301 #else
302 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 255) >> 8;
303 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 255) >> 8;
304 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 255) >> 8;
305 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 255) >> 8;
306 rgba[i][RCOMP] = (GLchan) r;
307 rgba[i][GCOMP] = (GLchan) g;
308 rgba[i][BCOMP] = (GLchan) b;
309 rgba[i][ACOMP] = (GLchan) a;
310 #endif
311 }
312 }
313 }
314
315
316
317 /*
318 * General case blend pixels.
319 * Input: n - number of pixels
320 * mask - the usual write mask
321 * In/Out: rgba - the incoming and modified pixels
322 * Input: dest - the pixels from the dest color buffer
323 */
324 static void _BLENDAPI
325 blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
326 GLchan rgba[][4], CONST GLchan dest[][4] )
327 {
328 const GLfloat rscale = 1.0F / CHAN_MAXF;
329 const GLfloat gscale = 1.0F / CHAN_MAXF;
330 const GLfloat bscale = 1.0F / CHAN_MAXF;
331 const GLfloat ascale = 1.0F / CHAN_MAXF;
332 GLuint i;
333
334 for (i=0;i<n;i++) {
335 if (mask[i]) {
336 #if CHAN_TYPE == GL_FLOAT
337 GLfloat Rs, Gs, Bs, As; /* Source colors */
338 GLfloat Rd, Gd, Bd, Ad; /* Dest colors */
339 #else
340 GLint Rs, Gs, Bs, As; /* Source colors */
341 GLint Rd, Gd, Bd, Ad; /* Dest colors */
342 #endif
343 GLfloat sR, sG, sB, sA; /* Source scaling */
344 GLfloat dR, dG, dB, dA; /* Dest scaling */
345 GLfloat r, g, b, a; /* result color */
346
347 /* Incoming/source Color */
348 Rs = rgba[i][RCOMP];
349 Gs = rgba[i][GCOMP];
350 Bs = rgba[i][BCOMP];
351 As = rgba[i][ACOMP];
352 #if CHAN_TYPE == GL_FLOAT
353 /* clamp */
354 Rs = MIN2(Rs, CHAN_MAXF);
355 Gs = MIN2(Gs, CHAN_MAXF);
356 Bs = MIN2(Bs, CHAN_MAXF);
357 As = MIN2(As, CHAN_MAXF);
358 #endif
359
360 /* Frame buffer/dest color */
361 Rd = dest[i][RCOMP];
362 Gd = dest[i][GCOMP];
363 Bd = dest[i][BCOMP];
364 Ad = dest[i][ACOMP];
365 #if CHAN_TYPE == GL_FLOAT
366 /* clamp */
367 Rd = MIN2(Rd, CHAN_MAXF);
368 Gd = MIN2(Gd, CHAN_MAXF);
369 Bd = MIN2(Bd, CHAN_MAXF);
370 Ad = MIN2(Ad, CHAN_MAXF);
371 #endif
372
373 /* Source RGB factor */
374 switch (ctx->Color.BlendSrcRGB) {
375 case GL_ZERO:
376 sR = sG = sB = 0.0F;
377 break;
378 case GL_ONE:
379 sR = sG = sB = 1.0F;
380 break;
381 case GL_DST_COLOR:
382 sR = (GLfloat) Rd * rscale;
383 sG = (GLfloat) Gd * gscale;
384 sB = (GLfloat) Bd * bscale;
385 break;
386 case GL_ONE_MINUS_DST_COLOR:
387 sR = 1.0F - (GLfloat) Rd * rscale;
388 sG = 1.0F - (GLfloat) Gd * gscale;
389 sB = 1.0F - (GLfloat) Bd * bscale;
390 break;
391 case GL_SRC_ALPHA:
392 sR = sG = sB = (GLfloat) As * ascale;
393 break;
394 case GL_ONE_MINUS_SRC_ALPHA:
395 sR = sG = sB = 1.0F - (GLfloat) As * ascale;
396 break;
397 case GL_DST_ALPHA:
398 sR = sG = sB = (GLfloat) Ad * ascale;
399 break;
400 case GL_ONE_MINUS_DST_ALPHA:
401 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
402 break;
403 case GL_SRC_ALPHA_SATURATE:
404 if (As < CHAN_MAX - Ad) {
405 sR = sG = sB = (GLfloat) As * ascale;
406 }
407 else {
408 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
409 }
410 break;
411 case GL_CONSTANT_COLOR:
412 sR = ctx->Color.BlendColor[0];
413 sG = ctx->Color.BlendColor[1];
414 sB = ctx->Color.BlendColor[2];
415 break;
416 case GL_ONE_MINUS_CONSTANT_COLOR:
417 sR = 1.0F - ctx->Color.BlendColor[0];
418 sG = 1.0F - ctx->Color.BlendColor[1];
419 sB = 1.0F - ctx->Color.BlendColor[2];
420 break;
421 case GL_CONSTANT_ALPHA:
422 sR = sG = sB = ctx->Color.BlendColor[3];
423 break;
424 case GL_ONE_MINUS_CONSTANT_ALPHA:
425 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
426 break;
427 case GL_SRC_COLOR: /* GL_NV_blend_square */
428 sR = (GLfloat) Rs * rscale;
429 sG = (GLfloat) Gs * gscale;
430 sB = (GLfloat) Bs * bscale;
431 break;
432 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
433 sR = 1.0F - (GLfloat) Rs * rscale;
434 sG = 1.0F - (GLfloat) Gs * gscale;
435 sB = 1.0F - (GLfloat) Bs * bscale;
436 break;
437 default:
438 /* this should never happen */
439 _mesa_problem(ctx, "Bad blend source RGB factor in do_blend");
440 return;
441 }
442
443 /* Source Alpha factor */
444 switch (ctx->Color.BlendSrcA) {
445 case GL_ZERO:
446 sA = 0.0F;
447 break;
448 case GL_ONE:
449 sA = 1.0F;
450 break;
451 case GL_DST_COLOR:
452 sA = (GLfloat) Ad * ascale;
453 break;
454 case GL_ONE_MINUS_DST_COLOR:
455 sA = 1.0F - (GLfloat) Ad * ascale;
456 break;
457 case GL_SRC_ALPHA:
458 sA = (GLfloat) As * ascale;
459 break;
460 case GL_ONE_MINUS_SRC_ALPHA:
461 sA = 1.0F - (GLfloat) As * ascale;
462 break;
463 case GL_DST_ALPHA:
464 sA =(GLfloat) Ad * ascale;
465 break;
466 case GL_ONE_MINUS_DST_ALPHA:
467 sA = 1.0F - (GLfloat) Ad * ascale;
468 break;
469 case GL_SRC_ALPHA_SATURATE:
470 sA = 1.0;
471 break;
472 case GL_CONSTANT_COLOR:
473 sA = ctx->Color.BlendColor[3];
474 break;
475 case GL_ONE_MINUS_CONSTANT_COLOR:
476 sA = 1.0F - ctx->Color.BlendColor[3];
477 break;
478 case GL_CONSTANT_ALPHA:
479 sA = ctx->Color.BlendColor[3];
480 break;
481 case GL_ONE_MINUS_CONSTANT_ALPHA:
482 sA = 1.0F - ctx->Color.BlendColor[3];
483 break;
484 case GL_SRC_COLOR: /* GL_NV_blend_square */
485 sA = (GLfloat) As * ascale;
486 break;
487 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
488 sA = 1.0F - (GLfloat) As * ascale;
489 break;
490 default:
491 /* this should never happen */
492 sA = 0.0F;
493 _mesa_problem(ctx, "Bad blend source A factor in do_blend");
494 }
495
496 /* Dest RGB factor */
497 switch (ctx->Color.BlendDstRGB) {
498 case GL_ZERO:
499 dR = dG = dB = 0.0F;
500 break;
501 case GL_ONE:
502 dR = dG = dB = 1.0F;
503 break;
504 case GL_SRC_COLOR:
505 dR = (GLfloat) Rs * rscale;
506 dG = (GLfloat) Gs * gscale;
507 dB = (GLfloat) Bs * bscale;
508 break;
509 case GL_ONE_MINUS_SRC_COLOR:
510 dR = 1.0F - (GLfloat) Rs * rscale;
511 dG = 1.0F - (GLfloat) Gs * gscale;
512 dB = 1.0F - (GLfloat) Bs * bscale;
513 break;
514 case GL_SRC_ALPHA:
515 dR = dG = dB = (GLfloat) As * ascale;
516 break;
517 case GL_ONE_MINUS_SRC_ALPHA:
518 dR = dG = dB = 1.0F - (GLfloat) As * ascale;
519 break;
520 case GL_DST_ALPHA:
521 dR = dG = dB = (GLfloat) Ad * ascale;
522 break;
523 case GL_ONE_MINUS_DST_ALPHA:
524 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
525 break;
526 case GL_CONSTANT_COLOR:
527 dR = ctx->Color.BlendColor[0];
528 dG = ctx->Color.BlendColor[1];
529 dB = ctx->Color.BlendColor[2];
530 break;
531 case GL_ONE_MINUS_CONSTANT_COLOR:
532 dR = 1.0F - ctx->Color.BlendColor[0];
533 dG = 1.0F - ctx->Color.BlendColor[1];
534 dB = 1.0F - ctx->Color.BlendColor[2];
535 break;
536 case GL_CONSTANT_ALPHA:
537 dR = dG = dB = ctx->Color.BlendColor[3];
538 break;
539 case GL_ONE_MINUS_CONSTANT_ALPHA:
540 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
541 break;
542 case GL_DST_COLOR: /* GL_NV_blend_square */
543 dR = (GLfloat) Rd * rscale;
544 dG = (GLfloat) Gd * gscale;
545 dB = (GLfloat) Bd * bscale;
546 break;
547 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
548 dR = 1.0F - (GLfloat) Rd * rscale;
549 dG = 1.0F - (GLfloat) Gd * gscale;
550 dB = 1.0F - (GLfloat) Bd * bscale;
551 break;
552 default:
553 /* this should never happen */
554 dR = dG = dB = 0.0F;
555 _mesa_problem(ctx, "Bad blend dest RGB factor in do_blend");
556 }
557
558 /* Dest Alpha factor */
559 switch (ctx->Color.BlendDstA) {
560 case GL_ZERO:
561 dA = 0.0F;
562 break;
563 case GL_ONE:
564 dA = 1.0F;
565 break;
566 case GL_SRC_COLOR:
567 dA = (GLfloat) As * ascale;
568 break;
569 case GL_ONE_MINUS_SRC_COLOR:
570 dA = 1.0F - (GLfloat) As * ascale;
571 break;
572 case GL_SRC_ALPHA:
573 dA = (GLfloat) As * ascale;
574 break;
575 case GL_ONE_MINUS_SRC_ALPHA:
576 dA = 1.0F - (GLfloat) As * ascale;
577 break;
578 case GL_DST_ALPHA:
579 dA = (GLfloat) Ad * ascale;
580 break;
581 case GL_ONE_MINUS_DST_ALPHA:
582 dA = 1.0F - (GLfloat) Ad * ascale;
583 break;
584 case GL_CONSTANT_COLOR:
585 dA = ctx->Color.BlendColor[3];
586 break;
587 case GL_ONE_MINUS_CONSTANT_COLOR:
588 dA = 1.0F - ctx->Color.BlendColor[3];
589 break;
590 case GL_CONSTANT_ALPHA:
591 dA = ctx->Color.BlendColor[3];
592 break;
593 case GL_ONE_MINUS_CONSTANT_ALPHA:
594 dA = 1.0F - ctx->Color.BlendColor[3];
595 break;
596 case GL_DST_COLOR: /* GL_NV_blend_square */
597 dA = (GLfloat) Ad * ascale;
598 break;
599 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
600 dA = 1.0F - (GLfloat) Ad * ascale;
601 break;
602 default:
603 /* this should never happen */
604 dA = 0.0F;
605 _mesa_problem(ctx, "Bad blend dest A factor in do_blend");
606 return;
607 }
608
609 /* Due to round-off problems we have to clamp against zero. */
610 /* Optimization: we don't have to do this for all src & dst factors */
611 if (dA < 0.0F) dA = 0.0F;
612 if (dR < 0.0F) dR = 0.0F;
613 if (dG < 0.0F) dG = 0.0F;
614 if (dB < 0.0F) dB = 0.0F;
615 if (sA < 0.0F) sA = 0.0F;
616 if (sR < 0.0F) sR = 0.0F;
617 if (sG < 0.0F) sG = 0.0F;
618 if (sB < 0.0F) sB = 0.0F;
619
620 ASSERT( sR <= 1.0 );
621 ASSERT( sG <= 1.0 );
622 ASSERT( sB <= 1.0 );
623 ASSERT( sA <= 1.0 );
624 ASSERT( dR <= 1.0 );
625 ASSERT( dG <= 1.0 );
626 ASSERT( dB <= 1.0 );
627 ASSERT( dA <= 1.0 );
628
629 /* compute blended color */
630 #if CHAN_TYPE == GL_FLOAT
631 if (ctx->Color.BlendEquation==GL_FUNC_ADD_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_SUBTRACT_EXT) {
638 r = Rs * sR - Rd * dR;
639 g = Gs * sG - Gd * dG;
640 b = Bs * sB - Bd * dB;
641 a = As * sA - Ad * dA;
642 }
643 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
644 r = Rd * dR - Rs * sR;
645 g = Gd * dG - Gs * sG;
646 b = Bd * dB - Bs * sB;
647 a = Ad * dA - As * sA;
648 }
649 else {
650 /* should never get here */
651 r = g = b = a = 0.0F; /* silence uninitialized var warning */
652 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
653 }
654
655 /* final clamping */
656 rgba[i][RCOMP] = MAX2( r, 0.0F );
657 rgba[i][GCOMP] = MAX2( g, 0.0F );
658 rgba[i][BCOMP] = MAX2( b, 0.0F );
659 rgba[i][ACOMP] = CLAMP( a, 0.0F, CHAN_MAXF );
660 #else
661 if (ctx->Color.BlendEquation==GL_FUNC_ADD_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_SUBTRACT_EXT) {
668 r = Rs * sR - Rd * dR + 0.5F;
669 g = Gs * sG - Gd * dG + 0.5F;
670 b = Bs * sB - Bd * dB + 0.5F;
671 a = As * sA - Ad * dA + 0.5F;
672 }
673 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
674 r = Rd * dR - Rs * sR + 0.5F;
675 g = Gd * dG - Gs * sG + 0.5F;
676 b = Bd * dB - Bs * sB + 0.5F;
677 a = Ad * dA - As * sA + 0.5F;
678 }
679 else {
680 /* should never get here */
681 r = g = b = a = 0.0F; /* silence uninitialized var warning */
682 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
683 }
684
685 /* final clamping */
686 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
687 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
688 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
689 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
690 #endif
691 }
692 }
693 }
694
695
696 /*
697 * Analyze current blending parameters to pick fastest blending function.
698 * Result: the ctx->Color.BlendFunc pointer is updated.
699 */
700 void _swrast_choose_blend_func( GLcontext *ctx )
701 {
702 const GLenum eq = ctx->Color.BlendEquation;
703 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
704 const GLenum dstRGB = ctx->Color.BlendDstRGB;
705 const GLenum srcA = ctx->Color.BlendSrcA;
706 const GLenum dstA = ctx->Color.BlendDstA;
707
708 if (eq==GL_MIN_EXT) {
709 /* Note: GL_MIN ignores the blending weight factors */
710 #if defined(USE_MMX_ASM)
711 if ( cpu_has_mmx ) {
712 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_min;
713 }
714 else
715 #endif
716 SWRAST_CONTEXT(ctx)->BlendFunc = blend_min;
717 }
718 else if (eq==GL_MAX_EXT) {
719 /* Note: GL_MAX ignores the blending weight factors */
720 #if defined(USE_MMX_ASM)
721 if ( cpu_has_mmx ) {
722 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_max;
723 }
724 else
725 #endif
726 SWRAST_CONTEXT(ctx)->BlendFunc = blend_max;
727 }
728 else if (srcRGB != srcA || dstRGB != dstA) {
729 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
730 }
731 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
732 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
733 #if defined(USE_MMX_ASM)
734 if ( cpu_has_mmx ) {
735 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency;
736 }
737 else
738 #endif
739 SWRAST_CONTEXT(ctx)->BlendFunc = blend_transparency;
740 }
741 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
742 #if defined(USE_MMX_ASM)
743 if ( cpu_has_mmx ) {
744 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_add;
745 }
746 else
747 #endif
748 SWRAST_CONTEXT(ctx)->BlendFunc = blend_add;
749 }
750 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
751 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
752 ||
753 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
754 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
755 #if defined(USE_MMX_ASM)
756 if ( cpu_has_mmx ) {
757 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_modulate;
758 }
759 else
760 #endif
761 SWRAST_CONTEXT(ctx)->BlendFunc = blend_modulate;
762 }
763 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
764 SWRAST_CONTEXT(ctx)->BlendFunc = blend_noop;
765 }
766 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
767 SWRAST_CONTEXT(ctx)->BlendFunc = blend_replace;
768 }
769 else {
770 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
771 }
772 }
773
774
775
776 /*
777 * Apply the blending operator to a span of pixels.
778 * We can handle horizontal runs of pixels (spans) or arrays of x/y
779 * pixel coordinates.
780 */
781 void
782 _swrast_blend_span( GLcontext *ctx, const struct sw_span *span,
783 GLchan rgba[][4] )
784 {
785 SWcontext *swrast = SWRAST_CONTEXT(ctx);
786 GLchan framebuffer[MAX_WIDTH][4];
787
788 ASSERT(span->end <= MAX_WIDTH);
789 ASSERT(span->arrayMask & SPAN_RGBA);
790 ASSERT(!ctx->Color._LogicOpEnabled);
791
792 /* Read span of current frame buffer pixels */
793 if (span->arrayMask & SPAN_XY) {
794 /* array of x/y pixel coords */
795 (*swrast->Driver.ReadRGBAPixels)( ctx, span->end,
796 span->array->x, span->array->y,
797 framebuffer, span->array->mask );
798 if (swrast->_RasterMask & ALPHABUF_BIT) {
799 _swrast_read_alpha_pixels( ctx, span->end,
800 span->array->x, span->array->y,
801 framebuffer, span->array->mask );
802 }
803 }
804 else {
805 /* horizontal run of pixels */
806 _swrast_read_rgba_span( ctx, ctx->DrawBuffer, span->end,
807 span->x, span->y, framebuffer );
808 }
809
810 SWRAST_CONTEXT(ctx)->BlendFunc( ctx, span->end, span->array->mask, rgba,
811 (const GLchan (*)[4]) framebuffer );
812 }