1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2008  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 * \file swrast/s_blend.c
28 * \brief software blending.
29 * \author Brian Paul
30 *
31 * Only a few blend modes have been optimized (min, max, transparency, add)
32 * more optimized cases can easily be added if needed.
33 * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example.
34 */
35
36
37
38#include "main/glheader.h"
39#include "main/context.h"
40#include "main/colormac.h"
41#include "main/macros.h"
42
43#include "s_blend.h"
44#include "s_context.h"
45#include "s_span.h"
46
47
48#if defined(USE_MMX_ASM)
49#include "x86/mmx.h"
50#include "x86/common_x86_asm.h"
51#define _BLENDAPI _ASMAPI
52#else
53#define _BLENDAPI
54#endif
55
56
57/**
58 * Integer divide by 255
59 * Declare "int divtemp" before using.
60 * This satisfies Glean and should be reasonably fast.
61 * Contributed by Nathan Hand.
62 */
63#define DIV255(X)  (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
64
65
66
67/**
68 * Special case for glBlendFunc(GL_ZERO, GL_ONE).
69 * No-op means the framebuffer values remain unchanged.
70 * Any chanType ok.
71 */
72static void _BLENDAPI
73blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
74           GLvoid *src, const GLvoid *dst, GLenum chanType)
75{
76   GLint bytes;
77
78   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
79   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
80   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
81   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
82   (void) ctx;
83
84   /* just memcpy */
85   if (chanType == GL_UNSIGNED_BYTE)
86      bytes = 4 * n * sizeof(GLubyte);
87   else if (chanType == GL_UNSIGNED_SHORT)
88      bytes = 4 * n * sizeof(GLushort);
89   else
90      bytes = 4 * n * sizeof(GLfloat);
91
92   memcpy(src, dst, bytes);
93}
94
95
96/**
97 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
98 * Any chanType ok.
99 */
100static void _BLENDAPI
101blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
102              GLvoid *src, const GLvoid *dst, GLenum chanType)
103{
104   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
105   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
106   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
107   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ZERO);
108   (void) ctx;
109   (void) n;
110   (void) mask;
111   (void) src;
112   (void) dst;
113}
114
115
116/**
117 * Common transparency blending mode:
118 * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
119 */
120static void _BLENDAPI
121blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
122                         GLvoid *src, const GLvoid *dst, GLenum chanType)
123{
124   GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
125   const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
126   GLuint i;
127
128   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
129   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
130   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
131   ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
132   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
133   ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
134   ASSERT(chanType == GL_UNSIGNED_BYTE);
135
136   (void) ctx;
137
138   for (i = 0; i < n; i++) {
139      if (mask[i]) {
140         const GLint t = rgba[i][ACOMP];  /* t is in [0, 255] */
141         if (t == 0) {
142            /* 0% alpha */
143            COPY_4UBV(rgba[i], dest[i]);
144         }
145         else if (t != 255) {
146	    GLint divtemp;
147            const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
148            const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
149            const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
150            const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
151            ASSERT(r <= 255);
152            ASSERT(g <= 255);
153            ASSERT(b <= 255);
154            ASSERT(a <= 255);
155            rgba[i][RCOMP] = (GLubyte) r;
156            rgba[i][GCOMP] = (GLubyte) g;
157            rgba[i][BCOMP] = (GLubyte) b;
158            rgba[i][ACOMP] = (GLubyte) a;
159         }
160      }
161   }
162}
163
164
165static void _BLENDAPI
166blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
167                          GLvoid *src, const GLvoid *dst, GLenum chanType)
168{
169   GLushort (*rgba)[4] = (GLushort (*)[4]) src;
170   const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
171   GLuint i;
172
173   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
174   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
175   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
176   ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
177   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
178   ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
179   ASSERT(chanType == GL_UNSIGNED_SHORT);
180
181   (void) ctx;
182
183   for (i = 0; i < n; i++) {
184      if (mask[i]) {
185         const GLint t = rgba[i][ACOMP];
186         if (t == 0) {
187            /* 0% alpha */
188            COPY_4V(rgba[i], dest[i]);
189         }
190         else if (t != 65535) {
191            const GLfloat tt = (GLfloat) t / 65535.0F;
192            GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
193            GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
194            GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
195            GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
196            ASSIGN_4V(rgba[i], r, g, b, a);
197         }
198      }
199   }
200}
201
202
203static void _BLENDAPI
204blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
205                         GLvoid *src, const GLvoid *dst, GLenum chanType)
206{
207   GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
208   const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
209   GLuint i;
210
211   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
212   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
213   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
214   ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
215   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
216   ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
217   ASSERT(chanType == GL_FLOAT);
218
219   (void) ctx;
220
221   for (i = 0; i < n; i++) {
222      if (mask[i]) {
223         const GLfloat t = rgba[i][ACOMP];  /* t in [0, 1] */
224         if (t == 0.0F) {
225            /* 0% alpha */
226            COPY_4V(rgba[i], dest[i]);
227         }
228         else if (t != 1.0F) {
229            GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP];
230            GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP];
231            GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP];
232            GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP];
233            ASSIGN_4V(rgba[i], r, g, b, a);
234         }
235      }
236   }
237}
238
239
240
241/**
242 * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
243 * Any chanType ok.
244 */
245static void _BLENDAPI
246blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
247          GLvoid *src, const GLvoid *dst, GLenum chanType)
248{
249   GLuint i;
250
251   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
252   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
253   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
254   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
255   (void) ctx;
256
257   if (chanType == GL_UNSIGNED_BYTE) {
258      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
259      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
260      for (i=0;i<n;i++) {
261         if (mask[i]) {
262            GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
263            GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
264            GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
265            GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
266            rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
267            rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
268            rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
269            rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
270         }
271      }
272   }
273   else if (chanType == GL_UNSIGNED_SHORT) {
274      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
275      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
276      for (i=0;i<n;i++) {
277         if (mask[i]) {
278            GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
279            GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
280            GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
281            GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
282            rgba[i][RCOMP] = (GLshort) MIN2( r, 255 );
283            rgba[i][GCOMP] = (GLshort) MIN2( g, 255 );
284            rgba[i][BCOMP] = (GLshort) MIN2( b, 255 );
285            rgba[i][ACOMP] = (GLshort) MIN2( a, 255 );
286         }
287      }
288   }
289   else {
290      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
291      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
292      ASSERT(chanType == GL_FLOAT);
293      for (i=0;i<n;i++) {
294         if (mask[i]) {
295            /* don't RGB clamp to max */
296            rgba[i][RCOMP] += dest[i][RCOMP];
297            rgba[i][GCOMP] += dest[i][GCOMP];
298            rgba[i][BCOMP] += dest[i][BCOMP];
299            rgba[i][ACOMP] += dest[i][ACOMP];
300         }
301      }
302   }
303}
304
305
306
307/**
308 * Blend min function.
309 * Any chanType ok.
310 */
311static void _BLENDAPI
312blend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
313          GLvoid *src, const GLvoid *dst, GLenum chanType)
314{
315   GLuint i;
316   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MIN);
317   ASSERT(ctx->Color.Blend[0].EquationA == GL_MIN);
318   (void) ctx;
319
320   if (chanType == GL_UNSIGNED_BYTE) {
321      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
322      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
323      for (i=0;i<n;i++) {
324         if (mask[i]) {
325            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
326            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
327            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
328            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
329         }
330      }
331   }
332   else if (chanType == GL_UNSIGNED_SHORT) {
333      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
334      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
335      for (i=0;i<n;i++) {
336         if (mask[i]) {
337            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
338            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
339            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
340            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
341         }
342      }
343   }
344   else {
345      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
346      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
347      ASSERT(chanType == GL_FLOAT);
348      for (i=0;i<n;i++) {
349         if (mask[i]) {
350            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
351            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
352            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
353            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
354         }
355      }
356   }
357}
358
359
360/**
361 * Blend max function.
362 * Any chanType ok.
363 */
364static void _BLENDAPI
365blend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
366          GLvoid *src, const GLvoid *dst, GLenum chanType)
367{
368   GLuint i;
369   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MAX);
370   ASSERT(ctx->Color.Blend[0].EquationA == GL_MAX);
371   (void) ctx;
372
373   if (chanType == GL_UNSIGNED_BYTE) {
374      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
375      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
376      for (i=0;i<n;i++) {
377         if (mask[i]) {
378            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
379            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
380            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
381            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
382         }
383      }
384   }
385   else if (chanType == GL_UNSIGNED_SHORT) {
386      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
387      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
388      for (i=0;i<n;i++) {
389         if (mask[i]) {
390            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
391            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
392            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
393            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
394         }
395      }
396   }
397   else {
398      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
399      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
400      ASSERT(chanType == GL_FLOAT);
401      for (i=0;i<n;i++) {
402         if (mask[i]) {
403            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
404            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
405            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
406            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
407         }
408      }
409   }
410}
411
412
413
414/**
415 * Modulate:  result = src * dest
416 * Any chanType ok.
417 */
418static void _BLENDAPI
419blend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
420               GLvoid *src, const GLvoid *dst, GLenum chanType)
421{
422   GLuint i;
423   (void) ctx;
424
425   if (chanType == GL_UNSIGNED_BYTE) {
426      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
427      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
428      for (i=0;i<n;i++) {
429         if (mask[i]) {
430	    GLint divtemp;
431            rgba[i][RCOMP] = DIV255(rgba[i][RCOMP] * dest[i][RCOMP]);
432            rgba[i][GCOMP] = DIV255(rgba[i][GCOMP] * dest[i][GCOMP]);
433            rgba[i][BCOMP] = DIV255(rgba[i][BCOMP] * dest[i][BCOMP]);
434            rgba[i][ACOMP] = DIV255(rgba[i][ACOMP] * dest[i][ACOMP]);
435         }
436      }
437   }
438   else if (chanType == GL_UNSIGNED_SHORT) {
439      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
440      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
441      for (i=0;i<n;i++) {
442         if (mask[i]) {
443            rgba[i][RCOMP] = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
444            rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
445            rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
446            rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
447         }
448      }
449   }
450   else {
451      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
452      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
453      ASSERT(chanType == GL_FLOAT);
454      for (i=0;i<n;i++) {
455         if (mask[i]) {
456            rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
457            rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
458            rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
459            rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
460         }
461      }
462   }
463}
464
465
466/**
467 * Do any blending operation, using floating point.
468 * \param n  number of pixels
469 * \param mask  fragment writemask array
470 * \param rgba  array of incoming (and modified) pixels
471 * \param dest  array of pixels from the dest color buffer
472 */
473static void
474blend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
475                    GLfloat rgba[][4], GLfloat dest[][4],
476                    GLenum chanType)
477{
478   GLuint i;
479
480   for (i = 0; i < n; i++) {
481      if (mask[i]) {
482         /* Incoming/source Color */
483         const GLfloat Rs = rgba[i][RCOMP];
484         const GLfloat Gs = rgba[i][GCOMP];
485         const GLfloat Bs = rgba[i][BCOMP];
486         const GLfloat As = rgba[i][ACOMP];
487
488         /* Frame buffer/dest color */
489         const GLfloat Rd = dest[i][RCOMP];
490         const GLfloat Gd = dest[i][GCOMP];
491         const GLfloat Bd = dest[i][BCOMP];
492         const GLfloat Ad = dest[i][ACOMP];
493
494         GLfloat sR, sG, sB, sA;  /* Source factor */
495         GLfloat dR, dG, dB, dA;  /* Dest factor */
496         GLfloat r, g, b, a;      /* result color */
497
498         /* XXX for the case of constant blend terms we could init
499          * the sX and dX variables just once before the loop.
500          */
501
502         /* Source RGB factor */
503         switch (ctx->Color.Blend[0].SrcRGB) {
504            case GL_ZERO:
505               sR = sG = sB = 0.0F;
506               break;
507            case GL_ONE:
508               sR = sG = sB = 1.0F;
509               break;
510            case GL_DST_COLOR:
511               sR = Rd;
512               sG = Gd;
513               sB = Bd;
514               break;
515            case GL_ONE_MINUS_DST_COLOR:
516               sR = 1.0F - Rd;
517               sG = 1.0F - Gd;
518               sB = 1.0F - Bd;
519               break;
520            case GL_SRC_ALPHA:
521               sR = sG = sB = As;
522               break;
523            case GL_ONE_MINUS_SRC_ALPHA:
524               sR = sG = sB = 1.0F - As;
525               break;
526            case GL_DST_ALPHA:
527               sR = sG = sB = Ad;
528               break;
529            case GL_ONE_MINUS_DST_ALPHA:
530               sR = sG = sB = 1.0F - Ad;
531               break;
532            case GL_SRC_ALPHA_SATURATE:
533               if (As < 1.0F - Ad) {
534                  sR = sG = sB = As;
535               }
536               else {
537                  sR = sG = sB = 1.0F - Ad;
538               }
539               break;
540            case GL_CONSTANT_COLOR:
541               sR = ctx->Color.BlendColor[0];
542               sG = ctx->Color.BlendColor[1];
543               sB = ctx->Color.BlendColor[2];
544               break;
545            case GL_ONE_MINUS_CONSTANT_COLOR:
546               sR = 1.0F - ctx->Color.BlendColor[0];
547               sG = 1.0F - ctx->Color.BlendColor[1];
548               sB = 1.0F - ctx->Color.BlendColor[2];
549               break;
550            case GL_CONSTANT_ALPHA:
551               sR = sG = sB = ctx->Color.BlendColor[3];
552               break;
553            case GL_ONE_MINUS_CONSTANT_ALPHA:
554               sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
555               break;
556            case GL_SRC_COLOR:
557               sR = Rs;
558               sG = Gs;
559               sB = Bs;
560               break;
561            case GL_ONE_MINUS_SRC_COLOR:
562               sR = 1.0F - Rs;
563               sG = 1.0F - Gs;
564               sB = 1.0F - Bs;
565               break;
566            default:
567               /* this should never happen */
568               _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
569               return;
570         }
571
572         /* Source Alpha factor */
573         switch (ctx->Color.Blend[0].SrcA) {
574            case GL_ZERO:
575               sA = 0.0F;
576               break;
577            case GL_ONE:
578               sA = 1.0F;
579               break;
580            case GL_DST_COLOR:
581               sA = Ad;
582               break;
583            case GL_ONE_MINUS_DST_COLOR:
584               sA = 1.0F - Ad;
585               break;
586            case GL_SRC_ALPHA:
587               sA = As;
588               break;
589            case GL_ONE_MINUS_SRC_ALPHA:
590               sA = 1.0F - As;
591               break;
592            case GL_DST_ALPHA:
593               sA = Ad;
594               break;
595            case GL_ONE_MINUS_DST_ALPHA:
596               sA = 1.0F - Ad;
597               break;
598            case GL_SRC_ALPHA_SATURATE:
599               sA = 1.0;
600               break;
601            case GL_CONSTANT_COLOR:
602               sA = ctx->Color.BlendColor[3];
603               break;
604            case GL_ONE_MINUS_CONSTANT_COLOR:
605               sA = 1.0F - ctx->Color.BlendColor[3];
606               break;
607            case GL_CONSTANT_ALPHA:
608               sA = ctx->Color.BlendColor[3];
609               break;
610            case GL_ONE_MINUS_CONSTANT_ALPHA:
611               sA = 1.0F - ctx->Color.BlendColor[3];
612               break;
613            case GL_SRC_COLOR:
614               sA = As;
615               break;
616            case GL_ONE_MINUS_SRC_COLOR:
617               sA = 1.0F - As;
618               break;
619            default:
620               /* this should never happen */
621               sA = 0.0F;
622               _mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
623               return;
624         }
625
626         /* Dest RGB factor */
627         switch (ctx->Color.Blend[0].DstRGB) {
628            case GL_ZERO:
629               dR = dG = dB = 0.0F;
630               break;
631            case GL_ONE:
632               dR = dG = dB = 1.0F;
633               break;
634            case GL_SRC_COLOR:
635               dR = Rs;
636               dG = Gs;
637               dB = Bs;
638               break;
639            case GL_ONE_MINUS_SRC_COLOR:
640               dR = 1.0F - Rs;
641               dG = 1.0F - Gs;
642               dB = 1.0F - Bs;
643               break;
644            case GL_SRC_ALPHA:
645               dR = dG = dB = As;
646               break;
647            case GL_ONE_MINUS_SRC_ALPHA:
648               dR = dG = dB = 1.0F - As;
649               break;
650            case GL_DST_ALPHA:
651               dR = dG = dB = Ad;
652               break;
653            case GL_ONE_MINUS_DST_ALPHA:
654               dR = dG = dB = 1.0F - Ad;
655               break;
656            case GL_CONSTANT_COLOR:
657               dR = ctx->Color.BlendColor[0];
658               dG = ctx->Color.BlendColor[1];
659               dB = ctx->Color.BlendColor[2];
660               break;
661            case GL_ONE_MINUS_CONSTANT_COLOR:
662               dR = 1.0F - ctx->Color.BlendColor[0];
663               dG = 1.0F - ctx->Color.BlendColor[1];
664               dB = 1.0F - ctx->Color.BlendColor[2];
665               break;
666            case GL_CONSTANT_ALPHA:
667               dR = dG = dB = ctx->Color.BlendColor[3];
668               break;
669            case GL_ONE_MINUS_CONSTANT_ALPHA:
670               dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
671               break;
672            case GL_DST_COLOR:
673               dR = Rd;
674               dG = Gd;
675               dB = Bd;
676               break;
677            case GL_ONE_MINUS_DST_COLOR:
678               dR = 1.0F - Rd;
679               dG = 1.0F - Gd;
680               dB = 1.0F - Bd;
681               break;
682            default:
683               /* this should never happen */
684               dR = dG = dB = 0.0F;
685               _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
686               return;
687         }
688
689         /* Dest Alpha factor */
690         switch (ctx->Color.Blend[0].DstA) {
691            case GL_ZERO:
692               dA = 0.0F;
693               break;
694            case GL_ONE:
695               dA = 1.0F;
696               break;
697            case GL_SRC_COLOR:
698               dA = As;
699               break;
700            case GL_ONE_MINUS_SRC_COLOR:
701               dA = 1.0F - As;
702               break;
703            case GL_SRC_ALPHA:
704               dA = As;
705               break;
706            case GL_ONE_MINUS_SRC_ALPHA:
707               dA = 1.0F - As;
708               break;
709            case GL_DST_ALPHA:
710               dA = Ad;
711               break;
712            case GL_ONE_MINUS_DST_ALPHA:
713               dA = 1.0F - Ad;
714               break;
715            case GL_CONSTANT_COLOR:
716               dA = ctx->Color.BlendColor[3];
717               break;
718            case GL_ONE_MINUS_CONSTANT_COLOR:
719               dA = 1.0F - ctx->Color.BlendColor[3];
720               break;
721            case GL_CONSTANT_ALPHA:
722               dA = ctx->Color.BlendColor[3];
723               break;
724            case GL_ONE_MINUS_CONSTANT_ALPHA:
725               dA = 1.0F - ctx->Color.BlendColor[3];
726               break;
727            case GL_DST_COLOR:
728               dA = Ad;
729               break;
730            case GL_ONE_MINUS_DST_COLOR:
731               dA = 1.0F - Ad;
732               break;
733            default:
734               /* this should never happen */
735               dA = 0.0F;
736               _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
737               return;
738         }
739
740         /* compute the blended RGB */
741         switch (ctx->Color.Blend[0].EquationRGB) {
742         case GL_FUNC_ADD:
743            r = Rs * sR + Rd * dR;
744            g = Gs * sG + Gd * dG;
745            b = Bs * sB + Bd * dB;
746            a = As * sA + Ad * dA;
747            break;
748         case GL_FUNC_SUBTRACT:
749            r = Rs * sR - Rd * dR;
750            g = Gs * sG - Gd * dG;
751            b = Bs * sB - Bd * dB;
752            a = As * sA - Ad * dA;
753            break;
754         case GL_FUNC_REVERSE_SUBTRACT:
755            r = Rd * dR - Rs * sR;
756            g = Gd * dG - Gs * sG;
757            b = Bd * dB - Bs * sB;
758            a = Ad * dA - As * sA;
759            break;
760         case GL_MIN:
761	    r = MIN2( Rd, Rs );
762	    g = MIN2( Gd, Gs );
763	    b = MIN2( Bd, Bs );
764            break;
765         case GL_MAX:
766	    r = MAX2( Rd, Rs );
767	    g = MAX2( Gd, Gs );
768	    b = MAX2( Bd, Bs );
769            break;
770	 default:
771            /* should never get here */
772            r = g = b = 0.0F;  /* silence uninitialized var warning */
773            _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
774            return;
775         }
776
777         /* compute the blended alpha */
778         switch (ctx->Color.Blend[0].EquationA) {
779         case GL_FUNC_ADD:
780            a = As * sA + Ad * dA;
781            break;
782         case GL_FUNC_SUBTRACT:
783            a = As * sA - Ad * dA;
784            break;
785         case GL_FUNC_REVERSE_SUBTRACT:
786            a = Ad * dA - As * sA;
787            break;
788         case GL_MIN:
789	    a = MIN2( Ad, As );
790            break;
791         case GL_MAX:
792	    a = MAX2( Ad, As );
793            break;
794         default:
795            /* should never get here */
796            a = 0.0F;  /* silence uninitialized var warning */
797            _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
798            return;
799         }
800
801         /* final clamping */
802#if 0
803         rgba[i][RCOMP] = MAX2( r, 0.0F );
804         rgba[i][GCOMP] = MAX2( g, 0.0F );
805         rgba[i][BCOMP] = MAX2( b, 0.0F );
806         rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F );
807#else
808         ASSIGN_4V(rgba[i], r, g, b, a);
809#endif
810      }
811   }
812}
813
814
815/**
816 * Do any blending operation, any chanType.
817 */
818static void
819blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
820              void *src, const void *dst, GLenum chanType)
821{
822   GLfloat (*rgbaF)[4], (*destF)[4];
823
824   rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
825   destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
826   if (!rgbaF || !destF) {
827      free(rgbaF);
828      free(destF);
829      _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
830      return;
831   }
832
833   if (chanType == GL_UNSIGNED_BYTE) {
834      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
835      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
836      GLuint i;
837      /* convert ubytes to floats */
838      for (i = 0; i < n; i++) {
839         if (mask[i]) {
840            rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
841            rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
842            rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
843            rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
844            destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
845            destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
846            destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
847            destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
848         }
849      }
850      /* do blend */
851      blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
852      /* convert back to ubytes */
853      for (i = 0; i < n; i++) {
854         if (mask[i])
855	   _mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]);
856      }
857   }
858   else if (chanType == GL_UNSIGNED_SHORT) {
859      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
860      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
861      GLuint i;
862      /* convert ushorts to floats */
863      for (i = 0; i < n; i++) {
864         if (mask[i]) {
865            rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
866            rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
867            rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
868            rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
869            destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
870            destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
871            destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
872            destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
873         }
874      }
875      /* do blend */
876      blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
877      /* convert back to ushorts */
878      for (i = 0; i < n; i++) {
879         if (mask[i]) {
880            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
881            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
882            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
883            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
884         }
885      }
886   }
887   else {
888      blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
889                          (GLfloat (*)[4]) dst, chanType);
890   }
891
892   free(rgbaF);
893   free(destF);
894}
895
896
897
898/**
899 * Analyze current blending parameters to pick fastest blending function.
900 * Result: the ctx->Color.BlendFunc pointer is updated.
901 */
902void
903_swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
904{
905   SWcontext *swrast = SWRAST_CONTEXT(ctx);
906   const GLenum eq = ctx->Color.Blend[0].EquationRGB;
907   const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
908   const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
909   const GLenum srcA = ctx->Color.Blend[0].SrcA;
910   const GLenum dstA = ctx->Color.Blend[0].DstA;
911
912   if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
913      swrast->BlendFunc = blend_general;
914   }
915   else if (eq == GL_MIN) {
916      /* Note: GL_MIN ignores the blending weight factors */
917#if defined(USE_MMX_ASM)
918      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
919         swrast->BlendFunc = _mesa_mmx_blend_min;
920      }
921      else
922#endif
923         swrast->BlendFunc = blend_min;
924   }
925   else if (eq == GL_MAX) {
926      /* Note: GL_MAX ignores the blending weight factors */
927#if defined(USE_MMX_ASM)
928      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
929         swrast->BlendFunc = _mesa_mmx_blend_max;
930      }
931      else
932#endif
933         swrast->BlendFunc = blend_max;
934   }
935   else if (srcRGB != srcA || dstRGB != dstA) {
936      swrast->BlendFunc = blend_general;
937   }
938   else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
939            && dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
940#if defined(USE_MMX_ASM)
941      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
942         swrast->BlendFunc = _mesa_mmx_blend_transparency;
943      }
944      else
945#endif
946      {
947         if (chanType == GL_UNSIGNED_BYTE)
948            swrast->BlendFunc = blend_transparency_ubyte;
949         else if (chanType == GL_UNSIGNED_SHORT)
950            swrast->BlendFunc = blend_transparency_ushort;
951         else
952            swrast->BlendFunc = blend_transparency_float;
953      }
954   }
955   else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
956#if defined(USE_MMX_ASM)
957      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
958         swrast->BlendFunc = _mesa_mmx_blend_add;
959      }
960      else
961#endif
962         swrast->BlendFunc = blend_add;
963   }
964   else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
965	     && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
966	    ||
967	    ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
968	     && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
969#if defined(USE_MMX_ASM)
970      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
971         swrast->BlendFunc = _mesa_mmx_blend_modulate;
972      }
973      else
974#endif
975         swrast->BlendFunc = blend_modulate;
976   }
977   else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
978      swrast->BlendFunc = blend_noop;
979   }
980   else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
981      swrast->BlendFunc = blend_replace;
982   }
983   else {
984      swrast->BlendFunc = blend_general;
985   }
986}
987
988
989
990/**
991 * Apply the blending operator to a span of pixels.
992 * We can handle horizontal runs of pixels (spans) or arrays of x/y
993 * pixel coordinates.
994 */
995void
996_swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
997{
998   SWcontext *swrast = SWRAST_CONTEXT(ctx);
999   void *rbPixels;
1000
1001   ASSERT(span->end <= SWRAST_MAX_WIDTH);
1002   ASSERT(span->arrayMask & SPAN_RGBA);
1003   ASSERT(!ctx->Color.ColorLogicOpEnabled);
1004
1005   rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
1006
1007   swrast->BlendFunc(ctx, span->end, span->array->mask,
1008                     span->array->rgba, rbPixels, span->array->ChanType);
1009}
1010