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