Replace the flags Mesa was using for ctx->NewState with a new set
[mesa.git] / src / mesa / main / blend.c
1 /* $Id: blend.c,v 1.22 2000/10/30 13:31:59 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2000 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 #ifdef PC_HEADER
30 #include "all.h"
31 #else
32 #include "glheader.h"
33 #include "alphabuf.h"
34 #include "blend.h"
35 #include "context.h"
36 #include "enums.h"
37 #include "macros.h"
38 #include "pb.h"
39 #include "span.h"
40 #include "types.h"
41 #endif
42
43
44 void
45 _mesa_BlendFunc( GLenum sfactor, GLenum dfactor )
46 {
47 GET_CURRENT_CONTEXT(ctx);
48 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFunc");
49
50 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
51 fprintf(stderr, "glBlendFunc %s %s\n",
52 gl_lookup_enum_by_nr(sfactor),
53 gl_lookup_enum_by_nr(dfactor));
54
55 switch (sfactor) {
56 case GL_SRC_COLOR:
57 case GL_ONE_MINUS_SRC_COLOR:
58 if (!ctx->Extensions.NV_blend_square) {
59 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
60 return;
61 }
62 /* fall-through */
63 case GL_ZERO:
64 case GL_ONE:
65 case GL_DST_COLOR:
66 case GL_ONE_MINUS_DST_COLOR:
67 case GL_SRC_ALPHA:
68 case GL_ONE_MINUS_SRC_ALPHA:
69 case GL_DST_ALPHA:
70 case GL_ONE_MINUS_DST_ALPHA:
71 case GL_SRC_ALPHA_SATURATE:
72 case GL_CONSTANT_COLOR:
73 case GL_ONE_MINUS_CONSTANT_COLOR:
74 case GL_CONSTANT_ALPHA:
75 case GL_ONE_MINUS_CONSTANT_ALPHA:
76 ctx->Color.BlendSrcRGB = ctx->Color.BlendSrcA = sfactor;
77 break;
78 default:
79 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
80 return;
81 }
82
83 switch (dfactor) {
84 case GL_DST_COLOR:
85 case GL_ONE_MINUS_DST_COLOR:
86 if (!ctx->Extensions.NV_blend_square) {
87 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
88 return;
89 }
90 /* fall-through */
91 case GL_ZERO:
92 case GL_ONE:
93 case GL_SRC_COLOR:
94 case GL_ONE_MINUS_SRC_COLOR:
95 case GL_SRC_ALPHA:
96 case GL_ONE_MINUS_SRC_ALPHA:
97 case GL_DST_ALPHA:
98 case GL_ONE_MINUS_DST_ALPHA:
99 case GL_CONSTANT_COLOR:
100 case GL_ONE_MINUS_CONSTANT_COLOR:
101 case GL_CONSTANT_ALPHA:
102 case GL_ONE_MINUS_CONSTANT_ALPHA:
103 ctx->Color.BlendDstRGB = ctx->Color.BlendDstA = dfactor;
104 break;
105 default:
106 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
107 return;
108 }
109
110 if (ctx->Driver.BlendFunc) {
111 (*ctx->Driver.BlendFunc)( ctx, sfactor, dfactor );
112 }
113
114 ctx->Color.BlendFunc = NULL;
115 ctx->NewState |= _NEW_COLOR;
116 }
117
118
119 /* GL_EXT_blend_func_separate */
120 void
121 _mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB,
122 GLenum sfactorA, GLenum dfactorA )
123 {
124 GET_CURRENT_CONTEXT(ctx);
125 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFuncSeparate");
126
127 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
128 fprintf(stderr, "glBlendFuncSeperate %s %s %s %s\n",
129 gl_lookup_enum_by_nr(sfactorRGB),
130 gl_lookup_enum_by_nr(dfactorRGB),
131 gl_lookup_enum_by_nr(sfactorA),
132 gl_lookup_enum_by_nr(dfactorA));
133
134 switch (sfactorRGB) {
135 case GL_SRC_COLOR:
136 case GL_ONE_MINUS_SRC_COLOR:
137 if (!ctx->Extensions.NV_blend_square) {
138 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)");
139 return;
140 }
141 /* fall-through */
142 case GL_ZERO:
143 case GL_ONE:
144 case GL_DST_COLOR:
145 case GL_ONE_MINUS_DST_COLOR:
146 case GL_SRC_ALPHA:
147 case GL_ONE_MINUS_SRC_ALPHA:
148 case GL_DST_ALPHA:
149 case GL_ONE_MINUS_DST_ALPHA:
150 case GL_SRC_ALPHA_SATURATE:
151 case GL_CONSTANT_COLOR:
152 case GL_ONE_MINUS_CONSTANT_COLOR:
153 case GL_CONSTANT_ALPHA:
154 case GL_ONE_MINUS_CONSTANT_ALPHA:
155 ctx->Color.BlendSrcRGB = sfactorRGB;
156 break;
157 default:
158 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)");
159 return;
160 }
161
162 switch (dfactorRGB) {
163 case GL_DST_COLOR:
164 case GL_ONE_MINUS_DST_COLOR:
165 if (!ctx->Extensions.NV_blend_square) {
166 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)");
167 return;
168 }
169 /* fall-through */
170 case GL_ZERO:
171 case GL_ONE:
172 case GL_SRC_COLOR:
173 case GL_ONE_MINUS_SRC_COLOR:
174 case GL_SRC_ALPHA:
175 case GL_ONE_MINUS_SRC_ALPHA:
176 case GL_DST_ALPHA:
177 case GL_ONE_MINUS_DST_ALPHA:
178 case GL_CONSTANT_COLOR:
179 case GL_ONE_MINUS_CONSTANT_COLOR:
180 case GL_CONSTANT_ALPHA:
181 case GL_ONE_MINUS_CONSTANT_ALPHA:
182 ctx->Color.BlendDstRGB = dfactorRGB;
183 break;
184 default:
185 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)");
186 return;
187 }
188
189 switch (sfactorA) {
190 case GL_SRC_COLOR:
191 case GL_ONE_MINUS_SRC_COLOR:
192 if (!ctx->Extensions.NV_blend_square) {
193 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)");
194 return;
195 }
196 /* fall-through */
197 case GL_ZERO:
198 case GL_ONE:
199 case GL_DST_COLOR:
200 case GL_ONE_MINUS_DST_COLOR:
201 case GL_SRC_ALPHA:
202 case GL_ONE_MINUS_SRC_ALPHA:
203 case GL_DST_ALPHA:
204 case GL_ONE_MINUS_DST_ALPHA:
205 case GL_SRC_ALPHA_SATURATE:
206 case GL_CONSTANT_COLOR:
207 case GL_ONE_MINUS_CONSTANT_COLOR:
208 case GL_CONSTANT_ALPHA:
209 case GL_ONE_MINUS_CONSTANT_ALPHA:
210 ctx->Color.BlendSrcA = sfactorA;
211 break;
212 default:
213 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)");
214 return;
215 }
216
217 switch (dfactorA) {
218 case GL_DST_COLOR:
219 case GL_ONE_MINUS_DST_COLOR:
220 if (!ctx->Extensions.NV_blend_square) {
221 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)");
222 return;
223 }
224 /* fall-through */
225 case GL_ZERO:
226 case GL_ONE:
227 case GL_SRC_COLOR:
228 case GL_ONE_MINUS_SRC_COLOR:
229 case GL_SRC_ALPHA:
230 case GL_ONE_MINUS_SRC_ALPHA:
231 case GL_DST_ALPHA:
232 case GL_ONE_MINUS_DST_ALPHA:
233 case GL_CONSTANT_COLOR:
234 case GL_ONE_MINUS_CONSTANT_COLOR:
235 case GL_CONSTANT_ALPHA:
236 case GL_ONE_MINUS_CONSTANT_ALPHA:
237 ctx->Color.BlendDstA = dfactorA;
238 break;
239 default:
240 gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)" );
241 return;
242 }
243
244 ctx->Color.BlendFunc = NULL;
245 ctx->NewState |= _NEW_COLOR;
246
247 if (ctx->Driver.BlendFuncSeparate) {
248 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB,
249 sfactorA, dfactorA );
250 }
251 }
252
253
254
255 /* This is really an extension function! */
256 void
257 _mesa_BlendEquation( GLenum mode )
258 {
259 GET_CURRENT_CONTEXT(ctx);
260 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendEquation");
261
262 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
263 fprintf(stderr, "glBlendEquation %s\n",
264 gl_lookup_enum_by_nr(mode));
265
266 switch (mode) {
267 case GL_MIN_EXT:
268 case GL_MAX_EXT:
269 case GL_FUNC_ADD_EXT:
270 if (ctx->Extensions.EXT_blend_minmax) {
271 ctx->Color.BlendEquation = mode;
272 }
273 else {
274 gl_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
275 return;
276 }
277 case GL_LOGIC_OP:
278 ctx->Color.BlendEquation = mode;
279 break;
280 case GL_FUNC_SUBTRACT_EXT:
281 case GL_FUNC_REVERSE_SUBTRACT_EXT:
282 if (ctx->Extensions.EXT_blend_subtract) {
283 ctx->Color.BlendEquation = mode;
284 }
285 else {
286 gl_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
287 return;
288 }
289 break;
290 default:
291 gl_error( ctx, GL_INVALID_ENUM, "glBlendEquation" );
292 return;
293 }
294
295 /* This is needed to support 1.1's RGB logic ops AND
296 * 1.0's blending logicops.
297 */
298 if (mode==GL_LOGIC_OP && ctx->Color.BlendEnabled) {
299 ctx->Color.ColorLogicOpEnabled = GL_TRUE;
300 }
301 else {
302 ctx->Color.ColorLogicOpEnabled = GL_FALSE;
303 }
304
305 ctx->Color.BlendFunc = NULL;
306 ctx->NewState |= _NEW_COLOR;
307
308 if (ctx->Driver.BlendEquation)
309 ctx->Driver.BlendEquation( ctx, mode );
310 }
311
312
313
314 void
315 _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
316 {
317 GET_CURRENT_CONTEXT(ctx);
318 ctx->Color.BlendColor[0] = CLAMP( red, 0.0F, 1.0F );
319 ctx->Color.BlendColor[1] = CLAMP( green, 0.0F, 1.0F );
320 ctx->Color.BlendColor[2] = CLAMP( blue, 0.0F, 1.0F );
321 ctx->Color.BlendColor[3] = CLAMP( alpha, 0.0F, 1.0F );
322 ctx->NewState |= _NEW_COLOR;
323 }
324
325 #ifdef USE_MMX_ASM
326 #define _BLENDAPI _ASMAPI
327 #else
328 #define _BLENDAPI
329 #endif
330
331 /*
332 * Common transparency blending mode.
333 */
334 static void _BLENDAPI
335 blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
336 GLchan rgba[][4], CONST GLchan dest[][4] )
337 {
338 GLuint i;
339 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
340 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
341 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
342 (void) ctx;
343
344 for (i=0;i<n;i++) {
345 if (mask[i]) {
346 const GLint t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */
347 if (t == 0) {
348 /* 0% alpha */
349 rgba[i][RCOMP] = dest[i][RCOMP];
350 rgba[i][GCOMP] = dest[i][GCOMP];
351 rgba[i][BCOMP] = dest[i][BCOMP];
352 rgba[i][ACOMP] = dest[i][ACOMP];
353 }
354 else if (t == CHAN_MAX) {
355 /* 100% alpha, no-op */
356 }
357 else {
358 #if 0
359 /* This is pretty close, but Glean complains */
360 const GLint s = CHAN_MAX - t;
361 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
362 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
363 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
364 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
365 #elif 0
366 /* This is slower but satisfies Glean */
367 const GLint s = CHAN_MAX - t;
368 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
369 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
370 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
371 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
372 #else
373 /* This satisfies Glean and should be reasonably fast */
374 /* Contributed by Nathan Hand */
375 #if CHAN_BITS == 8
376 #define DIV255(X) (((X) << 8) + (X) + 256) >> 16
377 #else
378 XXX todo
379 #endif
380 const GLint s = CHAN_MAX - t;
381 const GLint r = DIV255(rgba[i][RCOMP] * t + dest[i][RCOMP] * s);
382 const GLint g = DIV255(rgba[i][GCOMP] * t + dest[i][GCOMP] * s);
383 const GLint b = DIV255(rgba[i][BCOMP] * t + dest[i][BCOMP] * s);
384 const GLint a = DIV255(rgba[i][ACOMP] * t + dest[i][ACOMP] * s);
385 #undef DIV255
386 #endif
387 ASSERT(r <= CHAN_MAX);
388 ASSERT(g <= CHAN_MAX);
389 ASSERT(b <= CHAN_MAX);
390 ASSERT(a <= CHAN_MAX);
391 rgba[i][RCOMP] = (GLchan) r;
392 rgba[i][GCOMP] = (GLchan) g;
393 rgba[i][BCOMP] = (GLchan) b;
394 rgba[i][ACOMP] = (GLchan) a;
395 }
396 }
397 }
398 }
399
400
401
402 /*
403 * Add src and dest.
404 */
405 static void _BLENDAPI
406 blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
407 GLchan rgba[][4], CONST GLchan dest[][4] )
408 {
409 GLuint i;
410 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
411 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
412 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
413 (void) ctx;
414
415 for (i=0;i<n;i++) {
416 if (mask[i]) {
417 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
418 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
419 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
420 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
421 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
422 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
423 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
424 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
425 }
426 }
427 }
428
429
430
431 /*
432 * Blend min function (for GL_EXT_blend_minmax)
433 */
434 static void _BLENDAPI
435 blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
436 GLchan rgba[][4], CONST GLchan dest[][4] )
437 {
438 GLuint i;
439 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
440 (void) ctx;
441
442 for (i=0;i<n;i++) {
443 if (mask[i]) {
444 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
445 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
446 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
447 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
448 }
449 }
450 }
451
452
453
454 /*
455 * Blend max function (for GL_EXT_blend_minmax)
456 */
457 static void _BLENDAPI
458 blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
459 GLchan rgba[][4], CONST GLchan dest[][4] )
460 {
461 GLuint i;
462 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
463 (void) ctx;
464
465 for (i=0;i<n;i++) {
466 if (mask[i]) {
467 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
468 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
469 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
470 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
471 }
472 }
473 }
474
475
476
477 /*
478 * Modulate: result = src * dest
479 */
480 static void _BLENDAPI
481 blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
482 GLchan rgba[][4], CONST GLchan dest[][4] )
483 {
484 GLuint i;
485 (void) ctx;
486
487 for (i=0;i<n;i++) {
488 if (mask[i]) {
489 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8;
490 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8;
491 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8;
492 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8;
493 rgba[i][RCOMP] = (GLchan) r;
494 rgba[i][GCOMP] = (GLchan) g;
495 rgba[i][BCOMP] = (GLchan) b;
496 rgba[i][ACOMP] = (GLchan) a;
497 }
498 }
499 }
500
501
502
503 /*
504 * General case blend pixels.
505 * Input: n - number of pixels
506 * mask - the usual write mask
507 * In/Out: rgba - the incoming and modified pixels
508 * Input: dest - the pixels from the dest color buffer
509 */
510 static void _BLENDAPI
511 blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
512 GLchan rgba[][4], CONST GLchan dest[][4] )
513 {
514 GLfloat rscale = 1.0F / CHAN_MAXF;
515 GLfloat gscale = 1.0F / CHAN_MAXF;
516 GLfloat bscale = 1.0F / CHAN_MAXF;
517 GLfloat ascale = 1.0F / CHAN_MAXF;
518 GLuint i;
519
520 for (i=0;i<n;i++) {
521 if (mask[i]) {
522 GLint Rs, Gs, Bs, As; /* Source colors */
523 GLint Rd, Gd, Bd, Ad; /* Dest colors */
524 GLfloat sR, sG, sB, sA; /* Source scaling */
525 GLfloat dR, dG, dB, dA; /* Dest scaling */
526 GLfloat r, g, b, a;
527
528 /* Source Color */
529 Rs = rgba[i][RCOMP];
530 Gs = rgba[i][GCOMP];
531 Bs = rgba[i][BCOMP];
532 As = rgba[i][ACOMP];
533
534 /* Frame buffer color */
535 Rd = dest[i][RCOMP];
536 Gd = dest[i][GCOMP];
537 Bd = dest[i][BCOMP];
538 Ad = dest[i][ACOMP];
539
540 /* Source RGB factor */
541 switch (ctx->Color.BlendSrcRGB) {
542 case GL_ZERO:
543 sR = sG = sB = 0.0F;
544 break;
545 case GL_ONE:
546 sR = sG = sB = 1.0F;
547 break;
548 case GL_DST_COLOR:
549 sR = (GLfloat) Rd * rscale;
550 sG = (GLfloat) Gd * gscale;
551 sB = (GLfloat) Bd * bscale;
552 break;
553 case GL_ONE_MINUS_DST_COLOR:
554 sR = 1.0F - (GLfloat) Rd * rscale;
555 sG = 1.0F - (GLfloat) Gd * gscale;
556 sB = 1.0F - (GLfloat) Bd * bscale;
557 break;
558 case GL_SRC_ALPHA:
559 sR = sG = sB = (GLfloat) As * ascale;
560 break;
561 case GL_ONE_MINUS_SRC_ALPHA:
562 sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
563 break;
564 case GL_DST_ALPHA:
565 sR = sG = sB = (GLfloat) Ad * ascale;
566 break;
567 case GL_ONE_MINUS_DST_ALPHA:
568 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
569 break;
570 case GL_SRC_ALPHA_SATURATE:
571 if (As < CHAN_MAX - Ad) {
572 sR = sG = sB = (GLfloat) As * ascale;
573 }
574 else {
575 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
576 }
577 break;
578 case GL_CONSTANT_COLOR:
579 sR = ctx->Color.BlendColor[0];
580 sG = ctx->Color.BlendColor[1];
581 sB = ctx->Color.BlendColor[2];
582 break;
583 case GL_ONE_MINUS_CONSTANT_COLOR:
584 sR = 1.0F - ctx->Color.BlendColor[0];
585 sG = 1.0F - ctx->Color.BlendColor[1];
586 sB = 1.0F - ctx->Color.BlendColor[2];
587 break;
588 case GL_CONSTANT_ALPHA:
589 sR = sG = sB = ctx->Color.BlendColor[3];
590 break;
591 case GL_ONE_MINUS_CONSTANT_ALPHA:
592 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
593 break;
594 case GL_SRC_COLOR: /* GL_NV_blend_square */
595 sR = (GLfloat) Rs * rscale;
596 sG = (GLfloat) Gs * gscale;
597 sB = (GLfloat) Bs * bscale;
598 break;
599 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
600 sR = 1.0F - (GLfloat) Rs * rscale;
601 sG = 1.0F - (GLfloat) Gs * gscale;
602 sB = 1.0F - (GLfloat) Bs * bscale;
603 break;
604 default:
605 /* this should never happen */
606 gl_problem(ctx, "Bad blend source RGB factor in do_blend");
607 return;
608 }
609
610 /* Source Alpha factor */
611 switch (ctx->Color.BlendSrcA) {
612 case GL_ZERO:
613 sA = 0.0F;
614 break;
615 case GL_ONE:
616 sA = 1.0F;
617 break;
618 case GL_DST_COLOR:
619 sA = (GLfloat) Ad * ascale;
620 break;
621 case GL_ONE_MINUS_DST_COLOR:
622 sA = 1.0F - (GLfloat) Ad * ascale;
623 break;
624 case GL_SRC_ALPHA:
625 sA = (GLfloat) As * ascale;
626 break;
627 case GL_ONE_MINUS_SRC_ALPHA:
628 sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
629 break;
630 case GL_DST_ALPHA:
631 sA =(GLfloat) Ad * ascale;
632 break;
633 case GL_ONE_MINUS_DST_ALPHA:
634 sA = 1.0F - (GLfloat) Ad * ascale;
635 break;
636 case GL_SRC_ALPHA_SATURATE:
637 sA = 1.0;
638 break;
639 case GL_CONSTANT_COLOR:
640 sA = ctx->Color.BlendColor[3];
641 break;
642 case GL_ONE_MINUS_CONSTANT_COLOR:
643 sA = 1.0F - ctx->Color.BlendColor[3];
644 break;
645 case GL_CONSTANT_ALPHA:
646 sA = ctx->Color.BlendColor[3];
647 break;
648 case GL_ONE_MINUS_CONSTANT_ALPHA:
649 sA = 1.0F - ctx->Color.BlendColor[3];
650 break;
651 case GL_SRC_COLOR: /* GL_NV_blend_square */
652 sA = (GLfloat) As * ascale;
653 break;
654 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
655 sA = 1.0F - (GLfloat) As * ascale;
656 break;
657 default:
658 /* this should never happen */
659 sA = 0.0F;
660 gl_problem(ctx, "Bad blend source A factor in do_blend");
661 }
662
663 /* Dest RGB factor */
664 switch (ctx->Color.BlendDstRGB) {
665 case GL_ZERO:
666 dR = dG = dB = 0.0F;
667 break;
668 case GL_ONE:
669 dR = dG = dB = 1.0F;
670 break;
671 case GL_SRC_COLOR:
672 dR = (GLfloat) Rs * rscale;
673 dG = (GLfloat) Gs * gscale;
674 dB = (GLfloat) Bs * bscale;
675 break;
676 case GL_ONE_MINUS_SRC_COLOR:
677 dR = 1.0F - (GLfloat) Rs * rscale;
678 dG = 1.0F - (GLfloat) Gs * gscale;
679 dB = 1.0F - (GLfloat) Bs * bscale;
680 break;
681 case GL_SRC_ALPHA:
682 dR = dG = dB = (GLfloat) As * ascale;
683 break;
684 case GL_ONE_MINUS_SRC_ALPHA:
685 dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
686 break;
687 case GL_DST_ALPHA:
688 dR = dG = dB = (GLfloat) Ad * ascale;
689 break;
690 case GL_ONE_MINUS_DST_ALPHA:
691 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
692 break;
693 case GL_CONSTANT_COLOR:
694 dR = ctx->Color.BlendColor[0];
695 dG = ctx->Color.BlendColor[1];
696 dB = ctx->Color.BlendColor[2];
697 break;
698 case GL_ONE_MINUS_CONSTANT_COLOR:
699 dR = 1.0F - ctx->Color.BlendColor[0];
700 dG = 1.0F - ctx->Color.BlendColor[1];
701 dB = 1.0F - ctx->Color.BlendColor[2];
702 break;
703 case GL_CONSTANT_ALPHA:
704 dR = dG = dB = ctx->Color.BlendColor[3];
705 break;
706 case GL_ONE_MINUS_CONSTANT_ALPHA:
707 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
708 break;
709 case GL_DST_COLOR: /* GL_NV_blend_square */
710 dR = (GLfloat) Rd * rscale;
711 dG = (GLfloat) Gd * gscale;
712 dB = (GLfloat) Bd * bscale;
713 break;
714 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
715 dR = 1.0F - (GLfloat) Rd * rscale;
716 dG = 1.0F - (GLfloat) Gd * gscale;
717 dB = 1.0F - (GLfloat) Bd * bscale;
718 break;
719 default:
720 /* this should never happen */
721 dR = dG = dB = 0.0F;
722 gl_problem(ctx, "Bad blend dest RGB factor in do_blend");
723 }
724
725 /* Dest Alpha factor */
726 switch (ctx->Color.BlendDstA) {
727 case GL_ZERO:
728 dA = 0.0F;
729 break;
730 case GL_ONE:
731 dA = 1.0F;
732 break;
733 case GL_SRC_COLOR:
734 dA = (GLfloat) As * ascale;
735 break;
736 case GL_ONE_MINUS_SRC_COLOR:
737 dA = 1.0F - (GLfloat) As * ascale;
738 break;
739 case GL_SRC_ALPHA:
740 dA = (GLfloat) As * ascale;
741 break;
742 case GL_ONE_MINUS_SRC_ALPHA:
743 dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
744 break;
745 case GL_DST_ALPHA:
746 dA = (GLfloat) Ad * ascale;
747 break;
748 case GL_ONE_MINUS_DST_ALPHA:
749 dA = 1.0F - (GLfloat) Ad * ascale;
750 break;
751 case GL_CONSTANT_COLOR:
752 dA = ctx->Color.BlendColor[3];
753 break;
754 case GL_ONE_MINUS_CONSTANT_COLOR:
755 dA = 1.0F - ctx->Color.BlendColor[3];
756 break;
757 case GL_CONSTANT_ALPHA:
758 dA = ctx->Color.BlendColor[3];
759 break;
760 case GL_ONE_MINUS_CONSTANT_ALPHA:
761 dA = 1.0F - ctx->Color.BlendColor[3];
762 break;
763 case GL_DST_COLOR: /* GL_NV_blend_square */
764 dA = (GLfloat) Ad * ascale;
765 break;
766 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
767 dA = 1.0F - (GLfloat) Ad * ascale;
768 break;
769 default:
770 /* this should never happen */
771 dA = 0.0F;
772 gl_problem(ctx, "Bad blend dest A factor in do_blend");
773 return;
774 }
775
776 /* Due to round-off problems we have to clamp against zero. */
777 /* Optimization: we don't have to do this for all src & dst factors */
778 if (dA < 0.0F) dA = 0.0F;
779 if (dR < 0.0F) dR = 0.0F;
780 if (dG < 0.0F) dG = 0.0F;
781 if (dB < 0.0F) dB = 0.0F;
782 if (sA < 0.0F) sA = 0.0F;
783 if (sR < 0.0F) sR = 0.0F;
784 if (sG < 0.0F) sG = 0.0F;
785 if (sB < 0.0F) sB = 0.0F;
786
787 ASSERT( sR <= 1.0 );
788 ASSERT( sG <= 1.0 );
789 ASSERT( sB <= 1.0 );
790 ASSERT( sA <= 1.0 );
791 ASSERT( dR <= 1.0 );
792 ASSERT( dG <= 1.0 );
793 ASSERT( dB <= 1.0 );
794 ASSERT( dA <= 1.0 );
795
796 /* compute blended color */
797 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
798 r = Rs * sR + Rd * dR + 0.5F;
799 g = Gs * sG + Gd * dG + 0.5F;
800 b = Bs * sB + Bd * dB + 0.5F;
801 a = As * sA + Ad * dA + 0.5F;
802 }
803 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
804 r = Rs * sR - Rd * dR + 0.5F;
805 g = Gs * sG - Gd * dG + 0.5F;
806 b = Bs * sB - Bd * dB + 0.5F;
807 a = As * sA - Ad * dA + 0.5F;
808 }
809 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
810 r = Rd * dR - Rs * sR + 0.5F;
811 g = Gd * dG - Gs * sG + 0.5F;
812 b = Bd * dB - Bs * sB + 0.5F;
813 a = Ad * dA - As * sA + 0.5F;
814 }
815 else {
816 /* should never get here */
817 r = g = b = a = 0.0F; /* silence uninitialized var warning */
818 gl_problem(ctx, "unexpected BlendEquation in blend_general()");
819 }
820
821 /* final clamping */
822 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
823 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
824 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
825 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
826 }
827 }
828 }
829
830
831
832 #if defined(USE_MMX_ASM)
833 #include "X86/mmx.h"
834 #include "X86/common_x86_asm.h"
835 #endif
836
837
838 /*
839 * Analyze current blending parameters to pick fastest blending function.
840 * Result: the ctx->Color.BlendFunc pointer is updated.
841 */
842 static void set_blend_function( GLcontext *ctx )
843 {
844 const GLenum eq = ctx->Color.BlendEquation;
845 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
846 const GLenum dstRGB = ctx->Color.BlendDstRGB;
847 const GLenum srcA = ctx->Color.BlendSrcA;
848 const GLenum dstA = ctx->Color.BlendDstA;
849
850 #if defined(USE_MMX_ASM)
851 /* Hmm. A table here would have 12^4 == way too many entries.
852 * Provide a hook for MMX instead.
853 */
854 if ( cpu_has_mmx ) {
855 gl_mmx_set_blend_function( ctx );
856 }
857 else
858 #endif
859 if (srcRGB != srcA || dstRGB != dstA) {
860 ctx->Color.BlendFunc = blend_general;
861 }
862 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
863 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
864 ctx->Color.BlendFunc = blend_transparency;
865 }
866 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
867 ctx->Color.BlendFunc = blend_add;
868 }
869 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
870 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
871 ||
872 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
873 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
874 ctx->Color.BlendFunc = blend_modulate;
875 }
876 else if (eq==GL_MIN_EXT) {
877 ctx->Color.BlendFunc = blend_min;
878 }
879 else if (eq==GL_MAX_EXT) {
880 ctx->Color.BlendFunc = blend_max;
881 }
882 else {
883 ctx->Color.BlendFunc = blend_general;
884 }
885 }
886
887
888
889 /*
890 * Apply the blending operator to a span of pixels.
891 * Input: n - number of pixels in span
892 * x, y - location of leftmost pixel in span in window coords.
893 * mask - boolean mask indicating which pixels to blend.
894 * In/Out: rgba - pixel values
895 */
896 void
897 _mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
898 GLchan rgba[][4], const GLubyte mask[] )
899 {
900 GLchan dest[MAX_WIDTH][4];
901
902 /* Check if device driver can do the work */
903 if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
904 !ctx->Color.ColorLogicOpEnabled) {
905 return;
906 }
907
908 /* Read span of current frame buffer pixels */
909 gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
910
911 if (!ctx->Color.BlendFunc)
912 set_blend_function(ctx);
913
914 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
915 }
916
917
918
919 /*
920 * Apply the blending operator to an array of pixels.
921 * Input: n - number of pixels in span
922 * x, y - array of pixel locations
923 * mask - boolean mask indicating which pixels to blend.
924 * In/Out: rgba - pixel values
925 */
926 void
927 _mesa_blend_pixels( GLcontext *ctx,
928 GLuint n, const GLint x[], const GLint y[],
929 GLchan rgba[][4], const GLchan mask[] )
930 {
931 GLchan dest[PB_SIZE][4];
932
933 /* Check if device driver can do the work */
934 if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
935 !ctx->Color.ColorLogicOpEnabled) {
936 return;
937 }
938
939 /* Read pixels from current color buffer */
940 (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
941 if (ctx->RasterMask & ALPHABUF_BIT) {
942 _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
943 }
944
945 if (!ctx->Color.BlendFunc)
946 set_blend_function(ctx);
947
948 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
949 }