1001d6f2124818b82e19ae5a36c46bb1552e72cf
[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.BlendEquationRGB==GL_FUNC_ADD);
64 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
65 ASSERT(ctx->Color.BlendSrcRGB==GL_ZERO);
66 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
67 (void) ctx;
68
69 for (i = 0; i < n; i++) {
70 if (mask[i]) {
71 COPY_CHAN4( rgba[i], dest[i] );
72 }
73 }
74 }
75
76
77 /*
78 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
79 */
80 static void _BLENDAPI
81 blend_replace( GLcontext *ctx, GLuint n, const GLubyte mask[],
82 GLchan rgba[][4], CONST GLchan dest[][4] )
83 {
84 ASSERT(ctx->Color.BlendEquationRGB==GL_FUNC_ADD);
85 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
86 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
87 ASSERT(ctx->Color.BlendDstRGB==GL_ZERO);
88 (void) ctx;
89 (void) n;
90 (void) mask;
91 (void) rgba;
92 (void) dest;
93 }
94
95
96 /*
97 * Common transparency blending mode.
98 */
99 static void _BLENDAPI
100 blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
101 GLchan rgba[][4], CONST GLchan dest[][4] )
102 {
103 GLuint i;
104 ASSERT(ctx->Color.BlendEquationRGB==GL_FUNC_ADD);
105 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
106 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
107 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
108 (void) ctx;
109
110 for (i=0;i<n;i++) {
111 if (mask[i]) {
112 const GLchan t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */
113 if (t == 0) {
114 /* 0% alpha */
115 rgba[i][RCOMP] = dest[i][RCOMP];
116 rgba[i][GCOMP] = dest[i][GCOMP];
117 rgba[i][BCOMP] = dest[i][BCOMP];
118 rgba[i][ACOMP] = dest[i][ACOMP];
119 }
120 else if (t == CHAN_MAX) {
121 /* 100% alpha, no-op */
122 }
123 else {
124 #if 0
125 /* This is pretty close, but Glean complains */
126 const GLint s = CHAN_MAX - t;
127 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
128 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
129 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
130 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
131 #elif 0
132 /* This is slower but satisfies Glean */
133 const GLint s = CHAN_MAX - t;
134 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
135 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
136 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
137 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
138 #else
139 #if CHAN_BITS == 8
140 /* This satisfies Glean and should be reasonably fast */
141 /* Contributed by Nathan Hand */
142 #if 0
143 #define DIV255(X) (((X) << 8) + (X) + 256) >> 16
144 #else
145 GLint temp;
146 #define DIV255(X) (temp = (X), ((temp << 8) + temp + 256) >> 16)
147 #endif
148 const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
149 const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
150 const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
151 const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
152
153 #undef DIV255
154 #elif CHAN_BITS == 16
155 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
156 const GLint r = (GLint) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
157 const GLint g = (GLint) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
158 const GLint b = (GLint) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
159 const GLint a = (GLint) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
160 #else /* CHAN_BITS == 32 */
161 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
162 const GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP];
163 const GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP];
164 const GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP];
165 const GLfloat a = CLAMP( rgba[i][ACOMP], 0.0F, CHAN_MAXF ) * t +
166 CLAMP( dest[i][ACOMP], 0.0F, CHAN_MAXF ) * (1.0F - t);
167 #endif
168 #endif
169 ASSERT(r <= CHAN_MAX);
170 ASSERT(g <= CHAN_MAX);
171 ASSERT(b <= CHAN_MAX);
172 ASSERT(a <= CHAN_MAX);
173 rgba[i][RCOMP] = (GLchan) r;
174 rgba[i][GCOMP] = (GLchan) g;
175 rgba[i][BCOMP] = (GLchan) b;
176 rgba[i][ACOMP] = (GLchan) a;
177 }
178 }
179 }
180 }
181
182
183
184 /*
185 * Add src and dest.
186 */
187 static void _BLENDAPI
188 blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
189 GLchan rgba[][4], CONST GLchan dest[][4] )
190 {
191 GLuint i;
192 ASSERT(ctx->Color.BlendEquationRGB==GL_FUNC_ADD);
193 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
194 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
195 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
196 (void) ctx;
197
198 for (i=0;i<n;i++) {
199 if (mask[i]) {
200 #if CHAN_TYPE == GL_FLOAT
201 /* don't RGB clamp to max */
202 GLfloat a = CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF) + dest[i][ACOMP];
203 rgba[i][RCOMP] += dest[i][RCOMP];
204 rgba[i][GCOMP] += dest[i][GCOMP];
205 rgba[i][BCOMP] += dest[i][BCOMP];
206 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAXF );
207 #else
208 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
209 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
210 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
211 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
212 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
213 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
214 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
215 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
216 #endif
217 }
218 }
219 }
220
221
222
223 /*
224 * Blend min function (for GL_EXT_blend_minmax)
225 */
226 static void _BLENDAPI
227 blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
228 GLchan rgba[][4], CONST GLchan dest[][4] )
229 {
230 GLuint i;
231 ASSERT(ctx->Color.BlendEquationRGB==GL_MIN);
232 ASSERT(ctx->Color.BlendEquationA==GL_MIN);
233 (void) ctx;
234
235 for (i=0;i<n;i++) {
236 if (mask[i]) {
237 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
238 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
239 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
240 #if CHAN_TYPE == GL_FLOAT
241 rgba[i][ACOMP] = (GLchan) MIN2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
242 dest[i][ACOMP]);
243 #else
244 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
245 #endif
246 }
247 }
248 }
249
250
251
252 /*
253 * Blend max function (for GL_EXT_blend_minmax)
254 */
255 static void _BLENDAPI
256 blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
257 GLchan rgba[][4], CONST GLchan dest[][4] )
258 {
259 GLuint i;
260 ASSERT(ctx->Color.BlendEquationRGB==GL_MAX);
261 ASSERT(ctx->Color.BlendEquationA==GL_MAX);
262 (void) ctx;
263
264 for (i=0;i<n;i++) {
265 if (mask[i]) {
266 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
267 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
268 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
269 #if CHAN_TYPE == GL_FLOAT
270 rgba[i][ACOMP] = (GLchan) MAX2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
271 dest[i][ACOMP]);
272 #else
273 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
274 #endif
275 }
276 }
277 }
278
279
280
281 /*
282 * Modulate: result = src * dest
283 */
284 static void _BLENDAPI
285 blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
286 GLchan rgba[][4], CONST GLchan dest[][4] )
287 {
288 GLuint i;
289 (void) ctx;
290
291 for (i=0;i<n;i++) {
292 if (mask[i]) {
293 #if CHAN_TYPE == GL_FLOAT
294 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
295 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
296 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
297 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
298 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
299 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
300 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
301 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
302 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
303 rgba[i][RCOMP] = (GLchan) r;
304 rgba[i][GCOMP] = (GLchan) g;
305 rgba[i][BCOMP] = (GLchan) b;
306 rgba[i][ACOMP] = (GLchan) a;
307 #else
308 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 255) >> 8;
309 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 255) >> 8;
310 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 255) >> 8;
311 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 255) >> 8;
312 rgba[i][RCOMP] = (GLchan) r;
313 rgba[i][GCOMP] = (GLchan) g;
314 rgba[i][BCOMP] = (GLchan) b;
315 rgba[i][ACOMP] = (GLchan) a;
316 #endif
317 }
318 }
319 }
320
321
322
323 /*
324 * General case blend pixels.
325 * Input: n - number of pixels
326 * mask - the usual write mask
327 * In/Out: rgba - the incoming and modified pixels
328 * Input: dest - the pixels from the dest color buffer
329 */
330 static void _BLENDAPI
331 blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
332 GLchan rgba[][4], CONST GLchan dest[][4] )
333 {
334 const GLfloat rscale = 1.0F / CHAN_MAXF;
335 const GLfloat gscale = 1.0F / CHAN_MAXF;
336 const GLfloat bscale = 1.0F / CHAN_MAXF;
337 const GLfloat ascale = 1.0F / CHAN_MAXF;
338 GLuint i;
339
340 for (i=0;i<n;i++) {
341 if (mask[i]) {
342 #if CHAN_TYPE == GL_FLOAT
343 GLfloat Rs, Gs, Bs, As; /* Source colors */
344 GLfloat Rd, Gd, Bd, Ad; /* Dest colors */
345 #else
346 GLint Rs, Gs, Bs, As; /* Source colors */
347 GLint Rd, Gd, Bd, Ad; /* Dest colors */
348 #endif
349 GLfloat sR, sG, sB, sA; /* Source scaling */
350 GLfloat dR, dG, dB, dA; /* Dest scaling */
351 GLfloat r, g, b, a; /* result color */
352
353 /* Incoming/source Color */
354 Rs = rgba[i][RCOMP];
355 Gs = rgba[i][GCOMP];
356 Bs = rgba[i][BCOMP];
357 As = rgba[i][ACOMP];
358 #if CHAN_TYPE == GL_FLOAT
359 /* clamp */
360 Rs = MIN2(Rs, CHAN_MAXF);
361 Gs = MIN2(Gs, CHAN_MAXF);
362 Bs = MIN2(Bs, CHAN_MAXF);
363 As = MIN2(As, CHAN_MAXF);
364 #endif
365
366 /* Frame buffer/dest color */
367 Rd = dest[i][RCOMP];
368 Gd = dest[i][GCOMP];
369 Bd = dest[i][BCOMP];
370 Ad = dest[i][ACOMP];
371 #if CHAN_TYPE == GL_FLOAT
372 /* clamp */
373 Rd = MIN2(Rd, CHAN_MAXF);
374 Gd = MIN2(Gd, CHAN_MAXF);
375 Bd = MIN2(Bd, CHAN_MAXF);
376 Ad = MIN2(Ad, CHAN_MAXF);
377 #endif
378
379 /* Source RGB factor */
380 switch (ctx->Color.BlendSrcRGB) {
381 case GL_ZERO:
382 sR = sG = sB = 0.0F;
383 break;
384 case GL_ONE:
385 sR = sG = sB = 1.0F;
386 break;
387 case GL_DST_COLOR:
388 sR = (GLfloat) Rd * rscale;
389 sG = (GLfloat) Gd * gscale;
390 sB = (GLfloat) Bd * bscale;
391 break;
392 case GL_ONE_MINUS_DST_COLOR:
393 sR = 1.0F - (GLfloat) Rd * rscale;
394 sG = 1.0F - (GLfloat) Gd * gscale;
395 sB = 1.0F - (GLfloat) Bd * bscale;
396 break;
397 case GL_SRC_ALPHA:
398 sR = sG = sB = (GLfloat) As * ascale;
399 break;
400 case GL_ONE_MINUS_SRC_ALPHA:
401 sR = sG = sB = 1.0F - (GLfloat) As * ascale;
402 break;
403 case GL_DST_ALPHA:
404 sR = sG = sB = (GLfloat) Ad * ascale;
405 break;
406 case GL_ONE_MINUS_DST_ALPHA:
407 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
408 break;
409 case GL_SRC_ALPHA_SATURATE:
410 if (As < CHAN_MAX - Ad) {
411 sR = sG = sB = (GLfloat) As * ascale;
412 }
413 else {
414 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
415 }
416 break;
417 case GL_CONSTANT_COLOR:
418 sR = ctx->Color.BlendColor[0];
419 sG = ctx->Color.BlendColor[1];
420 sB = ctx->Color.BlendColor[2];
421 break;
422 case GL_ONE_MINUS_CONSTANT_COLOR:
423 sR = 1.0F - ctx->Color.BlendColor[0];
424 sG = 1.0F - ctx->Color.BlendColor[1];
425 sB = 1.0F - ctx->Color.BlendColor[2];
426 break;
427 case GL_CONSTANT_ALPHA:
428 sR = sG = sB = ctx->Color.BlendColor[3];
429 break;
430 case GL_ONE_MINUS_CONSTANT_ALPHA:
431 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
432 break;
433 case GL_SRC_COLOR: /* GL_NV_blend_square */
434 sR = (GLfloat) Rs * rscale;
435 sG = (GLfloat) Gs * gscale;
436 sB = (GLfloat) Bs * bscale;
437 break;
438 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
439 sR = 1.0F - (GLfloat) Rs * rscale;
440 sG = 1.0F - (GLfloat) Gs * gscale;
441 sB = 1.0F - (GLfloat) Bs * bscale;
442 break;
443 default:
444 /* this should never happen */
445 _mesa_problem(ctx, "Bad blend source RGB factor in do_blend");
446 return;
447 }
448
449 /* Source Alpha factor */
450 switch (ctx->Color.BlendSrcA) {
451 case GL_ZERO:
452 sA = 0.0F;
453 break;
454 case GL_ONE:
455 sA = 1.0F;
456 break;
457 case GL_DST_COLOR:
458 sA = (GLfloat) Ad * ascale;
459 break;
460 case GL_ONE_MINUS_DST_COLOR:
461 sA = 1.0F - (GLfloat) Ad * ascale;
462 break;
463 case GL_SRC_ALPHA:
464 sA = (GLfloat) As * ascale;
465 break;
466 case GL_ONE_MINUS_SRC_ALPHA:
467 sA = 1.0F - (GLfloat) As * ascale;
468 break;
469 case GL_DST_ALPHA:
470 sA =(GLfloat) Ad * ascale;
471 break;
472 case GL_ONE_MINUS_DST_ALPHA:
473 sA = 1.0F - (GLfloat) Ad * ascale;
474 break;
475 case GL_SRC_ALPHA_SATURATE:
476 sA = 1.0;
477 break;
478 case GL_CONSTANT_COLOR:
479 sA = ctx->Color.BlendColor[3];
480 break;
481 case GL_ONE_MINUS_CONSTANT_COLOR:
482 sA = 1.0F - ctx->Color.BlendColor[3];
483 break;
484 case GL_CONSTANT_ALPHA:
485 sA = ctx->Color.BlendColor[3];
486 break;
487 case GL_ONE_MINUS_CONSTANT_ALPHA:
488 sA = 1.0F - ctx->Color.BlendColor[3];
489 break;
490 case GL_SRC_COLOR: /* GL_NV_blend_square */
491 sA = (GLfloat) As * ascale;
492 break;
493 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
494 sA = 1.0F - (GLfloat) As * ascale;
495 break;
496 default:
497 /* this should never happen */
498 sA = 0.0F;
499 _mesa_problem(ctx, "Bad blend source A factor in do_blend");
500 }
501
502 /* Dest RGB factor */
503 switch (ctx->Color.BlendDstRGB) {
504 case GL_ZERO:
505 dR = dG = dB = 0.0F;
506 break;
507 case GL_ONE:
508 dR = dG = dB = 1.0F;
509 break;
510 case GL_SRC_COLOR:
511 dR = (GLfloat) Rs * rscale;
512 dG = (GLfloat) Gs * gscale;
513 dB = (GLfloat) Bs * bscale;
514 break;
515 case GL_ONE_MINUS_SRC_COLOR:
516 dR = 1.0F - (GLfloat) Rs * rscale;
517 dG = 1.0F - (GLfloat) Gs * gscale;
518 dB = 1.0F - (GLfloat) Bs * bscale;
519 break;
520 case GL_SRC_ALPHA:
521 dR = dG = dB = (GLfloat) As * ascale;
522 break;
523 case GL_ONE_MINUS_SRC_ALPHA:
524 dR = dG = dB = 1.0F - (GLfloat) As * ascale;
525 break;
526 case GL_DST_ALPHA:
527 dR = dG = dB = (GLfloat) Ad * ascale;
528 break;
529 case GL_ONE_MINUS_DST_ALPHA:
530 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
531 break;
532 case GL_CONSTANT_COLOR:
533 dR = ctx->Color.BlendColor[0];
534 dG = ctx->Color.BlendColor[1];
535 dB = ctx->Color.BlendColor[2];
536 break;
537 case GL_ONE_MINUS_CONSTANT_COLOR:
538 dR = 1.0F - ctx->Color.BlendColor[0];
539 dG = 1.0F - ctx->Color.BlendColor[1];
540 dB = 1.0F - ctx->Color.BlendColor[2];
541 break;
542 case GL_CONSTANT_ALPHA:
543 dR = dG = dB = ctx->Color.BlendColor[3];
544 break;
545 case GL_ONE_MINUS_CONSTANT_ALPHA:
546 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
547 break;
548 case GL_DST_COLOR: /* GL_NV_blend_square */
549 dR = (GLfloat) Rd * rscale;
550 dG = (GLfloat) Gd * gscale;
551 dB = (GLfloat) Bd * bscale;
552 break;
553 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
554 dR = 1.0F - (GLfloat) Rd * rscale;
555 dG = 1.0F - (GLfloat) Gd * gscale;
556 dB = 1.0F - (GLfloat) Bd * bscale;
557 break;
558 default:
559 /* this should never happen */
560 dR = dG = dB = 0.0F;
561 _mesa_problem(ctx, "Bad blend dest RGB factor in do_blend");
562 }
563
564 /* Dest Alpha factor */
565 switch (ctx->Color.BlendDstA) {
566 case GL_ZERO:
567 dA = 0.0F;
568 break;
569 case GL_ONE:
570 dA = 1.0F;
571 break;
572 case GL_SRC_COLOR:
573 dA = (GLfloat) As * ascale;
574 break;
575 case GL_ONE_MINUS_SRC_COLOR:
576 dA = 1.0F - (GLfloat) As * ascale;
577 break;
578 case GL_SRC_ALPHA:
579 dA = (GLfloat) As * ascale;
580 break;
581 case GL_ONE_MINUS_SRC_ALPHA:
582 dA = 1.0F - (GLfloat) As * ascale;
583 break;
584 case GL_DST_ALPHA:
585 dA = (GLfloat) Ad * ascale;
586 break;
587 case GL_ONE_MINUS_DST_ALPHA:
588 dA = 1.0F - (GLfloat) Ad * ascale;
589 break;
590 case GL_CONSTANT_COLOR:
591 dA = ctx->Color.BlendColor[3];
592 break;
593 case GL_ONE_MINUS_CONSTANT_COLOR:
594 dA = 1.0F - ctx->Color.BlendColor[3];
595 break;
596 case GL_CONSTANT_ALPHA:
597 dA = ctx->Color.BlendColor[3];
598 break;
599 case GL_ONE_MINUS_CONSTANT_ALPHA:
600 dA = 1.0F - ctx->Color.BlendColor[3];
601 break;
602 case GL_DST_COLOR: /* GL_NV_blend_square */
603 dA = (GLfloat) Ad * ascale;
604 break;
605 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
606 dA = 1.0F - (GLfloat) Ad * ascale;
607 break;
608 default:
609 /* this should never happen */
610 dA = 0.0F;
611 _mesa_problem(ctx, "Bad blend dest A factor in do_blend");
612 return;
613 }
614
615 /* Due to round-off problems we have to clamp against zero. */
616 /* Optimization: we don't have to do this for all src & dst factors */
617 if (dA < 0.0F) dA = 0.0F;
618 if (dR < 0.0F) dR = 0.0F;
619 if (dG < 0.0F) dG = 0.0F;
620 if (dB < 0.0F) dB = 0.0F;
621 if (sA < 0.0F) sA = 0.0F;
622 if (sR < 0.0F) sR = 0.0F;
623 if (sG < 0.0F) sG = 0.0F;
624 if (sB < 0.0F) sB = 0.0F;
625
626 ASSERT( sR <= 1.0 );
627 ASSERT( sG <= 1.0 );
628 ASSERT( sB <= 1.0 );
629 ASSERT( sA <= 1.0 );
630 ASSERT( dR <= 1.0 );
631 ASSERT( dG <= 1.0 );
632 ASSERT( dB <= 1.0 );
633 ASSERT( dA <= 1.0 );
634
635 /* compute blended color */
636 #if CHAN_TYPE == GL_FLOAT
637 if (ctx->Color.BlendEquationRGB==GL_FUNC_ADD) {
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.BlendEquationRGB==GL_FUNC_SUBTRACT) {
644 r = Rs * sR - Rd * dR;
645 g = Gs * sG - Gd * dG;
646 b = Bs * sB - Bd * dB;
647 a = As * sA - Ad * dA;
648 }
649 else if (ctx->Color.BlendEquationRGB==GL_FUNC_REVERSE_SUBTRACT) {
650 r = Rd * dR - Rs * sR;
651 g = Gd * dG - Gs * sG;
652 b = Bd * dB - Bs * sB;
653 a = Ad * dA - As * sA;
654 }
655 else if (ctx->Color.BlendEquationRGB==GL_MIN) {
656 r = MIN2( Rd, Rs );
657 g = MIN2( Gd, Gs );
658 b = MIN2( Bd, Bs );
659 }
660 else if (ctx->Color.BlendEquationRGB==GL_MAX) {
661 r = MAX2( Rd, Rs );
662 g = MAX2( Gd, Gs );
663 b = MAX2( Bd, Bs );
664 }
665 else {
666 /* should never get here */
667 r = g = b = 0.0F; /* silence uninitialized var warning */
668 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
669 }
670
671 if (ctx->Color.BlendEquationA==GL_FUNC_ADD) {
672 a = As * sA + Ad * dA;
673 }
674 else if (ctx->Color.BlendEquationA==GL_FUNC_SUBTRACT) {
675 a = As * sA - Ad * dA;
676 }
677 else if (ctx->Color.BlendEquationA==GL_FUNC_REVERSE_SUBTRACT) {
678 a = Ad * dA - As * sA;
679 }
680 else if (ctx->Color.BlendEquationA==GL_MIN) {
681 a = MIN2( Ad, As );
682 }
683 else if (ctx->Color.BlendEquationA==GL_MAX) {
684 a = MAX2( Ad, As );
685 }
686 else {
687 /* should never get here */
688 a = 0.0F; /* silence uninitialized var warning */
689 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
690 }
691
692 /* final clamping */
693 rgba[i][RCOMP] = MAX2( r, 0.0F );
694 rgba[i][GCOMP] = MAX2( g, 0.0F );
695 rgba[i][BCOMP] = MAX2( b, 0.0F );
696 rgba[i][ACOMP] = CLAMP( a, 0.0F, CHAN_MAXF );
697 #else
698 if (ctx->Color.BlendEquationRGB==GL_FUNC_ADD) {
699 r = Rs * sR + Rd * dR + 0.5F;
700 g = Gs * sG + Gd * dG + 0.5F;
701 b = Bs * sB + Bd * dB + 0.5F;
702 }
703 else if (ctx->Color.BlendEquationRGB==GL_FUNC_SUBTRACT) {
704 r = Rs * sR - Rd * dR + 0.5F;
705 g = Gs * sG - Gd * dG + 0.5F;
706 b = Bs * sB - Bd * dB + 0.5F;
707 }
708 else if (ctx->Color.BlendEquationRGB==GL_FUNC_REVERSE_SUBTRACT) {
709 r = Rd * dR - Rs * sR + 0.5F;
710 g = Gd * dG - Gs * sG + 0.5F;
711 b = Bd * dB - Bs * sB + 0.5F;
712 }
713 else if (ctx->Color.BlendEquationRGB==GL_MIN) {
714 r = MIN2( Rd, Rs );
715 g = MIN2( Gd, Gs );
716 b = MIN2( Bd, Bs );
717 }
718 else if (ctx->Color.BlendEquationRGB==GL_MAX) {
719 r = MAX2( Rd, Rs );
720 g = MAX2( Gd, Gs );
721 b = MAX2( Bd, Bs );
722 }
723 else {
724 /* should never get here */
725 r = g = b = 0.0F; /* silence uninitialized var warning */
726 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
727 }
728
729 if (ctx->Color.BlendEquationA==GL_FUNC_ADD) {
730 a = As * sA + Ad * dA + 0.5F;
731 }
732 else if (ctx->Color.BlendEquationA==GL_FUNC_SUBTRACT) {
733 a = As * sA - Ad * dA + 0.5F;
734 }
735 else if (ctx->Color.BlendEquationA==GL_FUNC_REVERSE_SUBTRACT) {
736 a = Ad * dA - As * sA + 0.5F;
737 }
738 else if (ctx->Color.BlendEquationA==GL_MIN) {
739 a = MIN2( Ad, As );
740 }
741 else if (ctx->Color.BlendEquationA==GL_MAX) {
742 a = MAX2( Ad, As );
743 }
744 else {
745 /* should never get here */
746 a = 0.0F; /* silence uninitialized var warning */
747 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
748 }
749
750 /* final clamping */
751 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
752 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
753 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
754 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
755 #endif
756 }
757 }
758 }
759
760
761 /*
762 * Analyze current blending parameters to pick fastest blending function.
763 * Result: the ctx->Color.BlendFunc pointer is updated.
764 */
765 void _swrast_choose_blend_func( GLcontext *ctx )
766 {
767 const GLenum eq = ctx->Color.BlendEquationRGB;
768 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
769 const GLenum dstRGB = ctx->Color.BlendDstRGB;
770 const GLenum srcA = ctx->Color.BlendSrcA;
771 const GLenum dstA = ctx->Color.BlendDstA;
772
773 if (ctx->Color.BlendEquationRGB != ctx->Color.BlendEquationA) {
774 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
775 }
776 else if (eq==GL_MIN) {
777 /* Note: GL_MIN ignores the blending weight factors */
778 #if defined(USE_MMX_ASM)
779 if ( cpu_has_mmx ) {
780 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_min;
781 }
782 else
783 #endif
784 SWRAST_CONTEXT(ctx)->BlendFunc = blend_min;
785 }
786 else if (eq==GL_MAX) {
787 /* Note: GL_MAX ignores the blending weight factors */
788 #if defined(USE_MMX_ASM)
789 if ( cpu_has_mmx ) {
790 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_max;
791 }
792 else
793 #endif
794 SWRAST_CONTEXT(ctx)->BlendFunc = blend_max;
795 }
796 else if (srcRGB != srcA || dstRGB != dstA) {
797 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
798 }
799 else if (eq==GL_FUNC_ADD && srcRGB==GL_SRC_ALPHA
800 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
801 #if defined(USE_MMX_ASM)
802 if ( cpu_has_mmx ) {
803 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency;
804 }
805 else
806 #endif
807 SWRAST_CONTEXT(ctx)->BlendFunc = blend_transparency;
808 }
809 else if (eq==GL_FUNC_ADD && srcRGB==GL_ONE && dstRGB==GL_ONE) {
810 #if defined(USE_MMX_ASM)
811 if ( cpu_has_mmx ) {
812 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_add;
813 }
814 else
815 #endif
816 SWRAST_CONTEXT(ctx)->BlendFunc = blend_add;
817 }
818 else if (((eq==GL_FUNC_ADD || eq==GL_FUNC_REVERSE_SUBTRACT)
819 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
820 ||
821 ((eq==GL_FUNC_ADD || eq==GL_FUNC_SUBTRACT)
822 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
823 #if defined(USE_MMX_ASM)
824 if ( cpu_has_mmx ) {
825 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_modulate;
826 }
827 else
828 #endif
829 SWRAST_CONTEXT(ctx)->BlendFunc = blend_modulate;
830 }
831 else if (eq==GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
832 SWRAST_CONTEXT(ctx)->BlendFunc = blend_noop;
833 }
834 else if (eq==GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
835 SWRAST_CONTEXT(ctx)->BlendFunc = blend_replace;
836 }
837 else {
838 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
839 }
840 }
841
842
843
844 /*
845 * Apply the blending operator to a span of pixels.
846 * We can handle horizontal runs of pixels (spans) or arrays of x/y
847 * pixel coordinates.
848 */
849 void
850 _swrast_blend_span( GLcontext *ctx, const struct sw_span *span,
851 GLchan rgba[][4] )
852 {
853 SWcontext *swrast = SWRAST_CONTEXT(ctx);
854 GLchan framebuffer[MAX_WIDTH][4];
855
856 ASSERT(span->end <= MAX_WIDTH);
857 ASSERT(span->arrayMask & SPAN_RGBA);
858 ASSERT(!ctx->Color._LogicOpEnabled);
859
860 /* Read span of current frame buffer pixels */
861 if (span->arrayMask & SPAN_XY) {
862 /* array of x/y pixel coords */
863 (*swrast->Driver.ReadRGBAPixels)( ctx, span->end,
864 span->array->x, span->array->y,
865 framebuffer, span->array->mask );
866 if (swrast->_RasterMask & ALPHABUF_BIT) {
867 _swrast_read_alpha_pixels( ctx, span->end,
868 span->array->x, span->array->y,
869 framebuffer, span->array->mask );
870 }
871 }
872 else {
873 /* horizontal run of pixels */
874 _swrast_read_rgba_span( ctx, ctx->DrawBuffer, span->end,
875 span->x, span->y, framebuffer );
876 }
877
878 SWRAST_CONTEXT(ctx)->BlendFunc( ctx, span->end, span->array->mask, rgba,
879 (const GLchan (*)[4]) framebuffer );
880 }