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