17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
267117f1b4Smrg/**
277117f1b4Smrg * \file swrast/s_blend.c
287117f1b4Smrg * \brief software blending.
297117f1b4Smrg * \author Brian Paul
307117f1b4Smrg *
317117f1b4Smrg * Only a few blend modes have been optimized (min, max, transparency, add)
327117f1b4Smrg * more optimized cases can easily be added if needed.
337117f1b4Smrg * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example.
347117f1b4Smrg */
357117f1b4Smrg
367117f1b4Smrg
377117f1b4Smrg
38c1f859d4Smrg#include "main/glheader.h"
39c1f859d4Smrg#include "main/context.h"
40c1f859d4Smrg#include "main/colormac.h"
41c1f859d4Smrg#include "main/macros.h"
427117f1b4Smrg
437117f1b4Smrg#include "s_blend.h"
447117f1b4Smrg#include "s_context.h"
457117f1b4Smrg#include "s_span.h"
467117f1b4Smrg
477117f1b4Smrg
487117f1b4Smrg#if defined(USE_MMX_ASM)
497117f1b4Smrg#include "x86/mmx.h"
507117f1b4Smrg#include "x86/common_x86_asm.h"
517117f1b4Smrg#endif
527117f1b4Smrg
537117f1b4Smrg
547117f1b4Smrg/**
557117f1b4Smrg * Integer divide by 255
567117f1b4Smrg * Declare "int divtemp" before using.
577117f1b4Smrg * This satisfies Glean and should be reasonably fast.
587117f1b4Smrg * Contributed by Nathan Hand.
597117f1b4Smrg */
607117f1b4Smrg#define DIV255(X)  (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
617117f1b4Smrg
627117f1b4Smrg
637117f1b4Smrg
647117f1b4Smrg/**
657117f1b4Smrg * Special case for glBlendFunc(GL_ZERO, GL_ONE).
667117f1b4Smrg * No-op means the framebuffer values remain unchanged.
677117f1b4Smrg * Any chanType ok.
687117f1b4Smrg */
6901e04c3fSmrgstatic void
703464ebd5Sriastradhblend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
717117f1b4Smrg           GLvoid *src, const GLvoid *dst, GLenum chanType)
727117f1b4Smrg{
737117f1b4Smrg   GLint bytes;
747117f1b4Smrg
7501e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
7601e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
7701e04c3fSmrg   assert(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
7801e04c3fSmrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE);
797117f1b4Smrg   (void) ctx;
807117f1b4Smrg
817117f1b4Smrg   /* just memcpy */
827117f1b4Smrg   if (chanType == GL_UNSIGNED_BYTE)
837117f1b4Smrg      bytes = 4 * n * sizeof(GLubyte);
847117f1b4Smrg   else if (chanType == GL_UNSIGNED_SHORT)
857117f1b4Smrg      bytes = 4 * n * sizeof(GLushort);
867117f1b4Smrg   else
877117f1b4Smrg      bytes = 4 * n * sizeof(GLfloat);
887117f1b4Smrg
89cdc920a0Smrg   memcpy(src, dst, bytes);
907117f1b4Smrg}
917117f1b4Smrg
927117f1b4Smrg
937117f1b4Smrg/**
947117f1b4Smrg * Special case for glBlendFunc(GL_ONE, GL_ZERO)
957117f1b4Smrg * Any chanType ok.
967117f1b4Smrg */
9701e04c3fSmrgstatic void
983464ebd5Sriastradhblend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
997117f1b4Smrg              GLvoid *src, const GLvoid *dst, GLenum chanType)
1007117f1b4Smrg{
10101e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
10201e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
10301e04c3fSmrg   assert(ctx->Color.Blend[0].SrcRGB == GL_ONE);
10401e04c3fSmrg   assert(ctx->Color.Blend[0].DstRGB == GL_ZERO);
1057117f1b4Smrg   (void) ctx;
1067117f1b4Smrg   (void) n;
1077117f1b4Smrg   (void) mask;
1087117f1b4Smrg   (void) src;
1097117f1b4Smrg   (void) dst;
1107117f1b4Smrg}
1117117f1b4Smrg
1127117f1b4Smrg
1137117f1b4Smrg/**
1147117f1b4Smrg * Common transparency blending mode:
1157117f1b4Smrg * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
1167117f1b4Smrg */
11701e04c3fSmrgstatic void
1183464ebd5Sriastradhblend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
1197117f1b4Smrg                         GLvoid *src, const GLvoid *dst, GLenum chanType)
1207117f1b4Smrg{
1217117f1b4Smrg   GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
1227117f1b4Smrg   const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
1237117f1b4Smrg   GLuint i;
1247117f1b4Smrg
12501e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
12601e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
12701e04c3fSmrg   assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
12801e04c3fSmrg   assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
12901e04c3fSmrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
13001e04c3fSmrg   assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
13101e04c3fSmrg   assert(chanType == GL_UNSIGNED_BYTE);
1327117f1b4Smrg
1337117f1b4Smrg   (void) ctx;
1347117f1b4Smrg
1357117f1b4Smrg   for (i = 0; i < n; i++) {
1367117f1b4Smrg      if (mask[i]) {
1377117f1b4Smrg         const GLint t = rgba[i][ACOMP];  /* t is in [0, 255] */
1387117f1b4Smrg         if (t == 0) {
1397117f1b4Smrg            /* 0% alpha */
1407117f1b4Smrg            COPY_4UBV(rgba[i], dest[i]);
1417117f1b4Smrg         }
1427117f1b4Smrg         else if (t != 255) {
1437117f1b4Smrg	    GLint divtemp;
1447117f1b4Smrg            const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
1457117f1b4Smrg            const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
1467117f1b4Smrg            const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
1477117f1b4Smrg            const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
14801e04c3fSmrg            assert(r <= 255);
14901e04c3fSmrg            assert(g <= 255);
15001e04c3fSmrg            assert(b <= 255);
15101e04c3fSmrg            assert(a <= 255);
1527117f1b4Smrg            rgba[i][RCOMP] = (GLubyte) r;
1537117f1b4Smrg            rgba[i][GCOMP] = (GLubyte) g;
1547117f1b4Smrg            rgba[i][BCOMP] = (GLubyte) b;
1557117f1b4Smrg            rgba[i][ACOMP] = (GLubyte) a;
1567117f1b4Smrg         }
1577117f1b4Smrg      }
1587117f1b4Smrg   }
1597117f1b4Smrg}
1607117f1b4Smrg
1617117f1b4Smrg
16201e04c3fSmrgstatic void
1633464ebd5Sriastradhblend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
1647117f1b4Smrg                          GLvoid *src, const GLvoid *dst, GLenum chanType)
1657117f1b4Smrg{
1667117f1b4Smrg   GLushort (*rgba)[4] = (GLushort (*)[4]) src;
1677117f1b4Smrg   const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
1687117f1b4Smrg   GLuint i;
1697117f1b4Smrg
17001e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
17101e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
17201e04c3fSmrg   assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
17301e04c3fSmrg   assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
17401e04c3fSmrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
17501e04c3fSmrg   assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
17601e04c3fSmrg   assert(chanType == GL_UNSIGNED_SHORT);
1777117f1b4Smrg
1787117f1b4Smrg   (void) ctx;
1797117f1b4Smrg
1807117f1b4Smrg   for (i = 0; i < n; i++) {
1817117f1b4Smrg      if (mask[i]) {
1827117f1b4Smrg         const GLint t = rgba[i][ACOMP];
1837117f1b4Smrg         if (t == 0) {
1847117f1b4Smrg            /* 0% alpha */
1857117f1b4Smrg            COPY_4V(rgba[i], dest[i]);
1867117f1b4Smrg         }
1877117f1b4Smrg         else if (t != 65535) {
1887117f1b4Smrg            const GLfloat tt = (GLfloat) t / 65535.0F;
1897117f1b4Smrg            GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
1907117f1b4Smrg            GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
1917117f1b4Smrg            GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
1927117f1b4Smrg            GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
1937117f1b4Smrg            ASSIGN_4V(rgba[i], r, g, b, a);
1947117f1b4Smrg         }
1957117f1b4Smrg      }
1967117f1b4Smrg   }
1977117f1b4Smrg}
1987117f1b4Smrg
1997117f1b4Smrg
20001e04c3fSmrgstatic void
2013464ebd5Sriastradhblend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
2027117f1b4Smrg                         GLvoid *src, const GLvoid *dst, GLenum chanType)
2037117f1b4Smrg{
2047117f1b4Smrg   GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
2057117f1b4Smrg   const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
2067117f1b4Smrg   GLuint i;
2077117f1b4Smrg
20801e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
20901e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
21001e04c3fSmrg   assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
21101e04c3fSmrg   assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
21201e04c3fSmrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
21301e04c3fSmrg   assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
21401e04c3fSmrg   assert(chanType == GL_FLOAT);
2157117f1b4Smrg
2167117f1b4Smrg   (void) ctx;
2177117f1b4Smrg
2187117f1b4Smrg   for (i = 0; i < n; i++) {
2197117f1b4Smrg      if (mask[i]) {
2207117f1b4Smrg         const GLfloat t = rgba[i][ACOMP];  /* t in [0, 1] */
2217117f1b4Smrg         if (t == 0.0F) {
2227117f1b4Smrg            /* 0% alpha */
2237117f1b4Smrg            COPY_4V(rgba[i], dest[i]);
2247117f1b4Smrg         }
2257117f1b4Smrg         else if (t != 1.0F) {
2267117f1b4Smrg            GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP];
2277117f1b4Smrg            GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP];
2287117f1b4Smrg            GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP];
2297117f1b4Smrg            GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP];
2307117f1b4Smrg            ASSIGN_4V(rgba[i], r, g, b, a);
2317117f1b4Smrg         }
2327117f1b4Smrg      }
2337117f1b4Smrg   }
2347117f1b4Smrg}
2357117f1b4Smrg
2367117f1b4Smrg
2377117f1b4Smrg
2387117f1b4Smrg/**
2397117f1b4Smrg * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
2407117f1b4Smrg * Any chanType ok.
2417117f1b4Smrg */
24201e04c3fSmrgstatic void
2433464ebd5Sriastradhblend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
2447117f1b4Smrg          GLvoid *src, const GLvoid *dst, GLenum chanType)
2457117f1b4Smrg{
2467117f1b4Smrg   GLuint i;
2477117f1b4Smrg
24801e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
24901e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
25001e04c3fSmrg   assert(ctx->Color.Blend[0].SrcRGB == GL_ONE);
25101e04c3fSmrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE);
2527117f1b4Smrg   (void) ctx;
2537117f1b4Smrg
2547117f1b4Smrg   if (chanType == GL_UNSIGNED_BYTE) {
2557117f1b4Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
2567117f1b4Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
2577117f1b4Smrg      for (i=0;i<n;i++) {
2587117f1b4Smrg         if (mask[i]) {
2597117f1b4Smrg            GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
2607117f1b4Smrg            GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
2617117f1b4Smrg            GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
2627117f1b4Smrg            GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
2637117f1b4Smrg            rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
2647117f1b4Smrg            rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
2657117f1b4Smrg            rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
2667117f1b4Smrg            rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
2677117f1b4Smrg         }
2687117f1b4Smrg      }
2697117f1b4Smrg   }
2707117f1b4Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
2717117f1b4Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
2727117f1b4Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
2737117f1b4Smrg      for (i=0;i<n;i++) {
2747117f1b4Smrg         if (mask[i]) {
2757117f1b4Smrg            GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
2767117f1b4Smrg            GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
2777117f1b4Smrg            GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
2787117f1b4Smrg            GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
2797117f1b4Smrg            rgba[i][RCOMP] = (GLshort) MIN2( r, 255 );
2807117f1b4Smrg            rgba[i][GCOMP] = (GLshort) MIN2( g, 255 );
2817117f1b4Smrg            rgba[i][BCOMP] = (GLshort) MIN2( b, 255 );
2827117f1b4Smrg            rgba[i][ACOMP] = (GLshort) MIN2( a, 255 );
2837117f1b4Smrg         }
2847117f1b4Smrg      }
2857117f1b4Smrg   }
2867117f1b4Smrg   else {
2877117f1b4Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
2887117f1b4Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
28901e04c3fSmrg      assert(chanType == GL_FLOAT);
2907117f1b4Smrg      for (i=0;i<n;i++) {
2917117f1b4Smrg         if (mask[i]) {
2927117f1b4Smrg            /* don't RGB clamp to max */
2937117f1b4Smrg            rgba[i][RCOMP] += dest[i][RCOMP];
2947117f1b4Smrg            rgba[i][GCOMP] += dest[i][GCOMP];
2957117f1b4Smrg            rgba[i][BCOMP] += dest[i][BCOMP];
2967117f1b4Smrg            rgba[i][ACOMP] += dest[i][ACOMP];
2977117f1b4Smrg         }
2987117f1b4Smrg      }
2997117f1b4Smrg   }
3007117f1b4Smrg}
3017117f1b4Smrg
3027117f1b4Smrg
3037117f1b4Smrg
3047117f1b4Smrg/**
3057117f1b4Smrg * Blend min function.
3067117f1b4Smrg * Any chanType ok.
3077117f1b4Smrg */
30801e04c3fSmrgstatic void
3093464ebd5Sriastradhblend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
3107117f1b4Smrg          GLvoid *src, const GLvoid *dst, GLenum chanType)
3117117f1b4Smrg{
3127117f1b4Smrg   GLuint i;
31301e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_MIN);
31401e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_MIN);
3157117f1b4Smrg   (void) ctx;
3167117f1b4Smrg
3177117f1b4Smrg   if (chanType == GL_UNSIGNED_BYTE) {
3187117f1b4Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
3197117f1b4Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
3207117f1b4Smrg      for (i=0;i<n;i++) {
3217117f1b4Smrg         if (mask[i]) {
3227117f1b4Smrg            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
3237117f1b4Smrg            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
3247117f1b4Smrg            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
3257117f1b4Smrg            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
3267117f1b4Smrg         }
3277117f1b4Smrg      }
3287117f1b4Smrg   }
3297117f1b4Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
3307117f1b4Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
3317117f1b4Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
3327117f1b4Smrg      for (i=0;i<n;i++) {
3337117f1b4Smrg         if (mask[i]) {
3347117f1b4Smrg            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
3357117f1b4Smrg            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
3367117f1b4Smrg            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
3377117f1b4Smrg            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
3387117f1b4Smrg         }
3397117f1b4Smrg      }
3407117f1b4Smrg   }
3417117f1b4Smrg   else {
3427117f1b4Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
3437117f1b4Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
34401e04c3fSmrg      assert(chanType == GL_FLOAT);
3457117f1b4Smrg      for (i=0;i<n;i++) {
3467117f1b4Smrg         if (mask[i]) {
3477117f1b4Smrg            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
3487117f1b4Smrg            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
3497117f1b4Smrg            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
3507117f1b4Smrg            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
3517117f1b4Smrg         }
3527117f1b4Smrg      }
3537117f1b4Smrg   }
3547117f1b4Smrg}
3557117f1b4Smrg
3567117f1b4Smrg
3577117f1b4Smrg/**
3587117f1b4Smrg * Blend max function.
3597117f1b4Smrg * Any chanType ok.
3607117f1b4Smrg */
36101e04c3fSmrgstatic void
3623464ebd5Sriastradhblend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
3637117f1b4Smrg          GLvoid *src, const GLvoid *dst, GLenum chanType)
3647117f1b4Smrg{
3657117f1b4Smrg   GLuint i;
36601e04c3fSmrg   assert(ctx->Color.Blend[0].EquationRGB == GL_MAX);
36701e04c3fSmrg   assert(ctx->Color.Blend[0].EquationA == GL_MAX);
3687117f1b4Smrg   (void) ctx;
3697117f1b4Smrg
3707117f1b4Smrg   if (chanType == GL_UNSIGNED_BYTE) {
3717117f1b4Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
3727117f1b4Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
3737117f1b4Smrg      for (i=0;i<n;i++) {
3747117f1b4Smrg         if (mask[i]) {
3757117f1b4Smrg            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
3767117f1b4Smrg            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
3777117f1b4Smrg            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
3787117f1b4Smrg            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
3797117f1b4Smrg         }
3807117f1b4Smrg      }
3817117f1b4Smrg   }
3827117f1b4Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
3837117f1b4Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
3847117f1b4Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
3857117f1b4Smrg      for (i=0;i<n;i++) {
3867117f1b4Smrg         if (mask[i]) {
3877117f1b4Smrg            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
3887117f1b4Smrg            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
3897117f1b4Smrg            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
3907117f1b4Smrg            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
3917117f1b4Smrg         }
3927117f1b4Smrg      }
3937117f1b4Smrg   }
3947117f1b4Smrg   else {
3957117f1b4Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
3967117f1b4Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
39701e04c3fSmrg      assert(chanType == GL_FLOAT);
3987117f1b4Smrg      for (i=0;i<n;i++) {
3997117f1b4Smrg         if (mask[i]) {
4007117f1b4Smrg            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
4017117f1b4Smrg            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
4027117f1b4Smrg            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
4037117f1b4Smrg            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
4047117f1b4Smrg         }
4057117f1b4Smrg      }
4067117f1b4Smrg   }
4077117f1b4Smrg}
4087117f1b4Smrg
4097117f1b4Smrg
4107117f1b4Smrg
4117117f1b4Smrg/**
4127117f1b4Smrg * Modulate:  result = src * dest
4137117f1b4Smrg * Any chanType ok.
4147117f1b4Smrg */
41501e04c3fSmrgstatic void
4163464ebd5Sriastradhblend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
4177117f1b4Smrg               GLvoid *src, const GLvoid *dst, GLenum chanType)
4187117f1b4Smrg{
4197117f1b4Smrg   GLuint i;
4207117f1b4Smrg   (void) ctx;
4217117f1b4Smrg
4227117f1b4Smrg   if (chanType == GL_UNSIGNED_BYTE) {
4237117f1b4Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
4247117f1b4Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
4257117f1b4Smrg      for (i=0;i<n;i++) {
4267117f1b4Smrg         if (mask[i]) {
4277117f1b4Smrg	    GLint divtemp;
4287117f1b4Smrg            rgba[i][RCOMP] = DIV255(rgba[i][RCOMP] * dest[i][RCOMP]);
4297117f1b4Smrg            rgba[i][GCOMP] = DIV255(rgba[i][GCOMP] * dest[i][GCOMP]);
4307117f1b4Smrg            rgba[i][BCOMP] = DIV255(rgba[i][BCOMP] * dest[i][BCOMP]);
4317117f1b4Smrg            rgba[i][ACOMP] = DIV255(rgba[i][ACOMP] * dest[i][ACOMP]);
4327117f1b4Smrg         }
4337117f1b4Smrg      }
4347117f1b4Smrg   }
4357117f1b4Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
4367117f1b4Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
4377117f1b4Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
4387117f1b4Smrg      for (i=0;i<n;i++) {
4397117f1b4Smrg         if (mask[i]) {
4407117f1b4Smrg            rgba[i][RCOMP] = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
4417117f1b4Smrg            rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
4427117f1b4Smrg            rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
4437117f1b4Smrg            rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
4447117f1b4Smrg         }
4457117f1b4Smrg      }
4467117f1b4Smrg   }
4477117f1b4Smrg   else {
4487117f1b4Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
4497117f1b4Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
45001e04c3fSmrg      assert(chanType == GL_FLOAT);
4517117f1b4Smrg      for (i=0;i<n;i++) {
4527117f1b4Smrg         if (mask[i]) {
4537117f1b4Smrg            rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
4547117f1b4Smrg            rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
4557117f1b4Smrg            rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
4567117f1b4Smrg            rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
4577117f1b4Smrg         }
4587117f1b4Smrg      }
4597117f1b4Smrg   }
4607117f1b4Smrg}
4617117f1b4Smrg
4627117f1b4Smrg
4637117f1b4Smrg/**
4647117f1b4Smrg * Do any blending operation, using floating point.
4657117f1b4Smrg * \param n  number of pixels
4667117f1b4Smrg * \param mask  fragment writemask array
4677117f1b4Smrg * \param rgba  array of incoming (and modified) pixels
4687117f1b4Smrg * \param dest  array of pixels from the dest color buffer
4697117f1b4Smrg */
4707117f1b4Smrgstatic void
4713464ebd5Sriastradhblend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
4727117f1b4Smrg                    GLfloat rgba[][4], GLfloat dest[][4],
4737117f1b4Smrg                    GLenum chanType)
4747117f1b4Smrg{
4757117f1b4Smrg   GLuint i;
4767117f1b4Smrg
4777117f1b4Smrg   for (i = 0; i < n; i++) {
4787117f1b4Smrg      if (mask[i]) {
4797117f1b4Smrg         /* Incoming/source Color */
4807117f1b4Smrg         const GLfloat Rs = rgba[i][RCOMP];
4817117f1b4Smrg         const GLfloat Gs = rgba[i][GCOMP];
4827117f1b4Smrg         const GLfloat Bs = rgba[i][BCOMP];
4837117f1b4Smrg         const GLfloat As = rgba[i][ACOMP];
4847117f1b4Smrg
4857117f1b4Smrg         /* Frame buffer/dest color */
4867117f1b4Smrg         const GLfloat Rd = dest[i][RCOMP];
4877117f1b4Smrg         const GLfloat Gd = dest[i][GCOMP];
4887117f1b4Smrg         const GLfloat Bd = dest[i][BCOMP];
4897117f1b4Smrg         const GLfloat Ad = dest[i][ACOMP];
4907117f1b4Smrg
4917117f1b4Smrg         GLfloat sR, sG, sB, sA;  /* Source factor */
4927117f1b4Smrg         GLfloat dR, dG, dB, dA;  /* Dest factor */
4937117f1b4Smrg         GLfloat r, g, b, a;      /* result color */
4947117f1b4Smrg
4957117f1b4Smrg         /* XXX for the case of constant blend terms we could init
4967117f1b4Smrg          * the sX and dX variables just once before the loop.
4977117f1b4Smrg          */
4987117f1b4Smrg
4997117f1b4Smrg         /* Source RGB factor */
5003464ebd5Sriastradh         switch (ctx->Color.Blend[0].SrcRGB) {
5017117f1b4Smrg            case GL_ZERO:
5027117f1b4Smrg               sR = sG = sB = 0.0F;
5037117f1b4Smrg               break;
5047117f1b4Smrg            case GL_ONE:
5057117f1b4Smrg               sR = sG = sB = 1.0F;
5067117f1b4Smrg               break;
5077117f1b4Smrg            case GL_DST_COLOR:
5087117f1b4Smrg               sR = Rd;
5097117f1b4Smrg               sG = Gd;
5107117f1b4Smrg               sB = Bd;
5117117f1b4Smrg               break;
5127117f1b4Smrg            case GL_ONE_MINUS_DST_COLOR:
5137117f1b4Smrg               sR = 1.0F - Rd;
5147117f1b4Smrg               sG = 1.0F - Gd;
5157117f1b4Smrg               sB = 1.0F - Bd;
5167117f1b4Smrg               break;
5177117f1b4Smrg            case GL_SRC_ALPHA:
5187117f1b4Smrg               sR = sG = sB = As;
5197117f1b4Smrg               break;
5207117f1b4Smrg            case GL_ONE_MINUS_SRC_ALPHA:
5217117f1b4Smrg               sR = sG = sB = 1.0F - As;
5227117f1b4Smrg               break;
5237117f1b4Smrg            case GL_DST_ALPHA:
5247117f1b4Smrg               sR = sG = sB = Ad;
5257117f1b4Smrg               break;
5267117f1b4Smrg            case GL_ONE_MINUS_DST_ALPHA:
5277117f1b4Smrg               sR = sG = sB = 1.0F - Ad;
5287117f1b4Smrg               break;
5297117f1b4Smrg            case GL_SRC_ALPHA_SATURATE:
5307117f1b4Smrg               if (As < 1.0F - Ad) {
5317117f1b4Smrg                  sR = sG = sB = As;
5327117f1b4Smrg               }
5337117f1b4Smrg               else {
5347117f1b4Smrg                  sR = sG = sB = 1.0F - Ad;
5357117f1b4Smrg               }
5367117f1b4Smrg               break;
5377117f1b4Smrg            case GL_CONSTANT_COLOR:
5387117f1b4Smrg               sR = ctx->Color.BlendColor[0];
5397117f1b4Smrg               sG = ctx->Color.BlendColor[1];
5407117f1b4Smrg               sB = ctx->Color.BlendColor[2];
5417117f1b4Smrg               break;
5427117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
5437117f1b4Smrg               sR = 1.0F - ctx->Color.BlendColor[0];
5447117f1b4Smrg               sG = 1.0F - ctx->Color.BlendColor[1];
5457117f1b4Smrg               sB = 1.0F - ctx->Color.BlendColor[2];
5467117f1b4Smrg               break;
5477117f1b4Smrg            case GL_CONSTANT_ALPHA:
5487117f1b4Smrg               sR = sG = sB = ctx->Color.BlendColor[3];
5497117f1b4Smrg               break;
5507117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
5517117f1b4Smrg               sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
5527117f1b4Smrg               break;
5537117f1b4Smrg            case GL_SRC_COLOR:
5547117f1b4Smrg               sR = Rs;
5557117f1b4Smrg               sG = Gs;
5567117f1b4Smrg               sB = Bs;
5577117f1b4Smrg               break;
5587117f1b4Smrg            case GL_ONE_MINUS_SRC_COLOR:
5597117f1b4Smrg               sR = 1.0F - Rs;
5607117f1b4Smrg               sG = 1.0F - Gs;
5617117f1b4Smrg               sB = 1.0F - Bs;
5627117f1b4Smrg               break;
5637117f1b4Smrg            default:
5647117f1b4Smrg               /* this should never happen */
5657117f1b4Smrg               _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
5667117f1b4Smrg               return;
5677117f1b4Smrg         }
5687117f1b4Smrg
5697117f1b4Smrg         /* Source Alpha factor */
5703464ebd5Sriastradh         switch (ctx->Color.Blend[0].SrcA) {
5717117f1b4Smrg            case GL_ZERO:
5727117f1b4Smrg               sA = 0.0F;
5737117f1b4Smrg               break;
5747117f1b4Smrg            case GL_ONE:
5757117f1b4Smrg               sA = 1.0F;
5767117f1b4Smrg               break;
5777117f1b4Smrg            case GL_DST_COLOR:
5787117f1b4Smrg               sA = Ad;
5797117f1b4Smrg               break;
5807117f1b4Smrg            case GL_ONE_MINUS_DST_COLOR:
5817117f1b4Smrg               sA = 1.0F - Ad;
5827117f1b4Smrg               break;
5837117f1b4Smrg            case GL_SRC_ALPHA:
5847117f1b4Smrg               sA = As;
5857117f1b4Smrg               break;
5867117f1b4Smrg            case GL_ONE_MINUS_SRC_ALPHA:
5877117f1b4Smrg               sA = 1.0F - As;
5887117f1b4Smrg               break;
5897117f1b4Smrg            case GL_DST_ALPHA:
5907117f1b4Smrg               sA = Ad;
5917117f1b4Smrg               break;
5927117f1b4Smrg            case GL_ONE_MINUS_DST_ALPHA:
5937117f1b4Smrg               sA = 1.0F - Ad;
5947117f1b4Smrg               break;
5957117f1b4Smrg            case GL_SRC_ALPHA_SATURATE:
5967117f1b4Smrg               sA = 1.0;
5977117f1b4Smrg               break;
5987117f1b4Smrg            case GL_CONSTANT_COLOR:
5997117f1b4Smrg               sA = ctx->Color.BlendColor[3];
6007117f1b4Smrg               break;
6017117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
6027117f1b4Smrg               sA = 1.0F - ctx->Color.BlendColor[3];
6037117f1b4Smrg               break;
6047117f1b4Smrg            case GL_CONSTANT_ALPHA:
6057117f1b4Smrg               sA = ctx->Color.BlendColor[3];
6067117f1b4Smrg               break;
6077117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
6087117f1b4Smrg               sA = 1.0F - ctx->Color.BlendColor[3];
6097117f1b4Smrg               break;
6107117f1b4Smrg            case GL_SRC_COLOR:
6117117f1b4Smrg               sA = As;
6127117f1b4Smrg               break;
6137117f1b4Smrg            case GL_ONE_MINUS_SRC_COLOR:
6147117f1b4Smrg               sA = 1.0F - As;
6157117f1b4Smrg               break;
6167117f1b4Smrg            default:
6177117f1b4Smrg               /* this should never happen */
6187117f1b4Smrg               sA = 0.0F;
6197117f1b4Smrg               _mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
6207117f1b4Smrg               return;
6217117f1b4Smrg         }
6227117f1b4Smrg
6237117f1b4Smrg         /* Dest RGB factor */
6243464ebd5Sriastradh         switch (ctx->Color.Blend[0].DstRGB) {
6257117f1b4Smrg            case GL_ZERO:
6267117f1b4Smrg               dR = dG = dB = 0.0F;
6277117f1b4Smrg               break;
6287117f1b4Smrg            case GL_ONE:
6297117f1b4Smrg               dR = dG = dB = 1.0F;
6307117f1b4Smrg               break;
6317117f1b4Smrg            case GL_SRC_COLOR:
6327117f1b4Smrg               dR = Rs;
6337117f1b4Smrg               dG = Gs;
6347117f1b4Smrg               dB = Bs;
6357117f1b4Smrg               break;
6367117f1b4Smrg            case GL_ONE_MINUS_SRC_COLOR:
6377117f1b4Smrg               dR = 1.0F - Rs;
6387117f1b4Smrg               dG = 1.0F - Gs;
6397117f1b4Smrg               dB = 1.0F - Bs;
6407117f1b4Smrg               break;
6417117f1b4Smrg            case GL_SRC_ALPHA:
6427117f1b4Smrg               dR = dG = dB = As;
6437117f1b4Smrg               break;
6447117f1b4Smrg            case GL_ONE_MINUS_SRC_ALPHA:
6457117f1b4Smrg               dR = dG = dB = 1.0F - As;
6467117f1b4Smrg               break;
6477117f1b4Smrg            case GL_DST_ALPHA:
6487117f1b4Smrg               dR = dG = dB = Ad;
6497117f1b4Smrg               break;
6507117f1b4Smrg            case GL_ONE_MINUS_DST_ALPHA:
6517117f1b4Smrg               dR = dG = dB = 1.0F - Ad;
6527117f1b4Smrg               break;
6537117f1b4Smrg            case GL_CONSTANT_COLOR:
6547117f1b4Smrg               dR = ctx->Color.BlendColor[0];
6557117f1b4Smrg               dG = ctx->Color.BlendColor[1];
6567117f1b4Smrg               dB = ctx->Color.BlendColor[2];
6577117f1b4Smrg               break;
6587117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
6597117f1b4Smrg               dR = 1.0F - ctx->Color.BlendColor[0];
6607117f1b4Smrg               dG = 1.0F - ctx->Color.BlendColor[1];
6617117f1b4Smrg               dB = 1.0F - ctx->Color.BlendColor[2];
6627117f1b4Smrg               break;
6637117f1b4Smrg            case GL_CONSTANT_ALPHA:
6647117f1b4Smrg               dR = dG = dB = ctx->Color.BlendColor[3];
6657117f1b4Smrg               break;
6667117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
6677117f1b4Smrg               dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
6687117f1b4Smrg               break;
6697117f1b4Smrg            case GL_DST_COLOR:
6707117f1b4Smrg               dR = Rd;
6717117f1b4Smrg               dG = Gd;
6727117f1b4Smrg               dB = Bd;
6737117f1b4Smrg               break;
6747117f1b4Smrg            case GL_ONE_MINUS_DST_COLOR:
6757117f1b4Smrg               dR = 1.0F - Rd;
6767117f1b4Smrg               dG = 1.0F - Gd;
6777117f1b4Smrg               dB = 1.0F - Bd;
6787117f1b4Smrg               break;
6797117f1b4Smrg            default:
6807117f1b4Smrg               /* this should never happen */
6817117f1b4Smrg               dR = dG = dB = 0.0F;
6827117f1b4Smrg               _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
6837117f1b4Smrg               return;
6847117f1b4Smrg         }
6857117f1b4Smrg
6867117f1b4Smrg         /* Dest Alpha factor */
6873464ebd5Sriastradh         switch (ctx->Color.Blend[0].DstA) {
6887117f1b4Smrg            case GL_ZERO:
6897117f1b4Smrg               dA = 0.0F;
6907117f1b4Smrg               break;
6917117f1b4Smrg            case GL_ONE:
6927117f1b4Smrg               dA = 1.0F;
6937117f1b4Smrg               break;
6947117f1b4Smrg            case GL_SRC_COLOR:
6957117f1b4Smrg               dA = As;
6967117f1b4Smrg               break;
6977117f1b4Smrg            case GL_ONE_MINUS_SRC_COLOR:
6987117f1b4Smrg               dA = 1.0F - As;
6997117f1b4Smrg               break;
7007117f1b4Smrg            case GL_SRC_ALPHA:
7017117f1b4Smrg               dA = As;
7027117f1b4Smrg               break;
7037117f1b4Smrg            case GL_ONE_MINUS_SRC_ALPHA:
7047117f1b4Smrg               dA = 1.0F - As;
7057117f1b4Smrg               break;
7067117f1b4Smrg            case GL_DST_ALPHA:
7077117f1b4Smrg               dA = Ad;
7087117f1b4Smrg               break;
7097117f1b4Smrg            case GL_ONE_MINUS_DST_ALPHA:
7107117f1b4Smrg               dA = 1.0F - Ad;
7117117f1b4Smrg               break;
7127117f1b4Smrg            case GL_CONSTANT_COLOR:
7137117f1b4Smrg               dA = ctx->Color.BlendColor[3];
7147117f1b4Smrg               break;
7157117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
7167117f1b4Smrg               dA = 1.0F - ctx->Color.BlendColor[3];
7177117f1b4Smrg               break;
7187117f1b4Smrg            case GL_CONSTANT_ALPHA:
7197117f1b4Smrg               dA = ctx->Color.BlendColor[3];
7207117f1b4Smrg               break;
7217117f1b4Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
7227117f1b4Smrg               dA = 1.0F - ctx->Color.BlendColor[3];
7237117f1b4Smrg               break;
7247117f1b4Smrg            case GL_DST_COLOR:
7257117f1b4Smrg               dA = Ad;
7267117f1b4Smrg               break;
7277117f1b4Smrg            case GL_ONE_MINUS_DST_COLOR:
7287117f1b4Smrg               dA = 1.0F - Ad;
7297117f1b4Smrg               break;
7307117f1b4Smrg            default:
7317117f1b4Smrg               /* this should never happen */
7327117f1b4Smrg               dA = 0.0F;
7337117f1b4Smrg               _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
7347117f1b4Smrg               return;
7357117f1b4Smrg         }
7367117f1b4Smrg
7377117f1b4Smrg         /* compute the blended RGB */
7383464ebd5Sriastradh         switch (ctx->Color.Blend[0].EquationRGB) {
7397117f1b4Smrg         case GL_FUNC_ADD:
7407117f1b4Smrg            r = Rs * sR + Rd * dR;
7417117f1b4Smrg            g = Gs * sG + Gd * dG;
7427117f1b4Smrg            b = Bs * sB + Bd * dB;
7437117f1b4Smrg            a = As * sA + Ad * dA;
7447117f1b4Smrg            break;
7457117f1b4Smrg         case GL_FUNC_SUBTRACT:
7467117f1b4Smrg            r = Rs * sR - Rd * dR;
7477117f1b4Smrg            g = Gs * sG - Gd * dG;
7487117f1b4Smrg            b = Bs * sB - Bd * dB;
7497117f1b4Smrg            a = As * sA - Ad * dA;
7507117f1b4Smrg            break;
7517117f1b4Smrg         case GL_FUNC_REVERSE_SUBTRACT:
7527117f1b4Smrg            r = Rd * dR - Rs * sR;
7537117f1b4Smrg            g = Gd * dG - Gs * sG;
7547117f1b4Smrg            b = Bd * dB - Bs * sB;
7557117f1b4Smrg            a = Ad * dA - As * sA;
7567117f1b4Smrg            break;
7577117f1b4Smrg         case GL_MIN:
7587117f1b4Smrg	    r = MIN2( Rd, Rs );
7597117f1b4Smrg	    g = MIN2( Gd, Gs );
7607117f1b4Smrg	    b = MIN2( Bd, Bs );
7617117f1b4Smrg            break;
7627117f1b4Smrg         case GL_MAX:
7637117f1b4Smrg	    r = MAX2( Rd, Rs );
7647117f1b4Smrg	    g = MAX2( Gd, Gs );
7657117f1b4Smrg	    b = MAX2( Bd, Bs );
7667117f1b4Smrg            break;
7677117f1b4Smrg	 default:
7687117f1b4Smrg            /* should never get here */
7697117f1b4Smrg            r = g = b = 0.0F;  /* silence uninitialized var warning */
7707117f1b4Smrg            _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
7717117f1b4Smrg            return;
7727117f1b4Smrg         }
7737117f1b4Smrg
7747117f1b4Smrg         /* compute the blended alpha */
7753464ebd5Sriastradh         switch (ctx->Color.Blend[0].EquationA) {
7767117f1b4Smrg         case GL_FUNC_ADD:
7777117f1b4Smrg            a = As * sA + Ad * dA;
7787117f1b4Smrg            break;
7797117f1b4Smrg         case GL_FUNC_SUBTRACT:
7807117f1b4Smrg            a = As * sA - Ad * dA;
7817117f1b4Smrg            break;
7827117f1b4Smrg         case GL_FUNC_REVERSE_SUBTRACT:
7837117f1b4Smrg            a = Ad * dA - As * sA;
7847117f1b4Smrg            break;
7857117f1b4Smrg         case GL_MIN:
7867117f1b4Smrg	    a = MIN2( Ad, As );
7877117f1b4Smrg            break;
7887117f1b4Smrg         case GL_MAX:
7897117f1b4Smrg	    a = MAX2( Ad, As );
7907117f1b4Smrg            break;
7917117f1b4Smrg         default:
7927117f1b4Smrg            /* should never get here */
7937117f1b4Smrg            a = 0.0F;  /* silence uninitialized var warning */
7947117f1b4Smrg            _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
7957117f1b4Smrg            return;
7967117f1b4Smrg         }
7977117f1b4Smrg
7987117f1b4Smrg         /* final clamping */
7997117f1b4Smrg#if 0
8007117f1b4Smrg         rgba[i][RCOMP] = MAX2( r, 0.0F );
8017117f1b4Smrg         rgba[i][GCOMP] = MAX2( g, 0.0F );
8027117f1b4Smrg         rgba[i][BCOMP] = MAX2( b, 0.0F );
8037117f1b4Smrg         rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F );
8047117f1b4Smrg#else
8057117f1b4Smrg         ASSIGN_4V(rgba[i], r, g, b, a);
8067117f1b4Smrg#endif
8077117f1b4Smrg      }
8087117f1b4Smrg   }
8097117f1b4Smrg}
8107117f1b4Smrg
8117117f1b4Smrg
8127117f1b4Smrg/**
8137117f1b4Smrg * Do any blending operation, any chanType.
8147117f1b4Smrg */
8157117f1b4Smrgstatic void
8163464ebd5Sriastradhblend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
8177117f1b4Smrg              void *src, const void *dst, GLenum chanType)
8187117f1b4Smrg{
8193464ebd5Sriastradh   GLfloat (*rgbaF)[4], (*destF)[4];
8203464ebd5Sriastradh
8213464ebd5Sriastradh   rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
8223464ebd5Sriastradh   destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
8233464ebd5Sriastradh   if (!rgbaF || !destF) {
8243464ebd5Sriastradh      free(rgbaF);
8253464ebd5Sriastradh      free(destF);
8263464ebd5Sriastradh      _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
8273464ebd5Sriastradh      return;
8283464ebd5Sriastradh   }
8297117f1b4Smrg
8307117f1b4Smrg   if (chanType == GL_UNSIGNED_BYTE) {
8317117f1b4Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
8327117f1b4Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
8337117f1b4Smrg      GLuint i;
8347117f1b4Smrg      /* convert ubytes to floats */
8357117f1b4Smrg      for (i = 0; i < n; i++) {
8367117f1b4Smrg         if (mask[i]) {
8377117f1b4Smrg            rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
8387117f1b4Smrg            rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
8397117f1b4Smrg            rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
8407117f1b4Smrg            rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
8417117f1b4Smrg            destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
8427117f1b4Smrg            destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
8437117f1b4Smrg            destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
8447117f1b4Smrg            destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
8457117f1b4Smrg         }
8467117f1b4Smrg      }
8477117f1b4Smrg      /* do blend */
8487117f1b4Smrg      blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
8497117f1b4Smrg      /* convert back to ubytes */
8507117f1b4Smrg      for (i = 0; i < n; i++) {
851af69d88dSmrg         if (mask[i])
852af69d88dSmrg	   _mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]);
8537117f1b4Smrg      }
8547117f1b4Smrg   }
8557117f1b4Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
8567117f1b4Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
8577117f1b4Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
8587117f1b4Smrg      GLuint i;
8597117f1b4Smrg      /* convert ushorts to floats */
8607117f1b4Smrg      for (i = 0; i < n; i++) {
8617117f1b4Smrg         if (mask[i]) {
8627117f1b4Smrg            rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
8637117f1b4Smrg            rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
8647117f1b4Smrg            rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
8657117f1b4Smrg            rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
8667117f1b4Smrg            destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
8677117f1b4Smrg            destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
8687117f1b4Smrg            destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
8697117f1b4Smrg            destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
8707117f1b4Smrg         }
8717117f1b4Smrg      }
8727117f1b4Smrg      /* do blend */
8737117f1b4Smrg      blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
8747117f1b4Smrg      /* convert back to ushorts */
8757117f1b4Smrg      for (i = 0; i < n; i++) {
8767117f1b4Smrg         if (mask[i]) {
8777117f1b4Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
8787117f1b4Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
8797117f1b4Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
8807117f1b4Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
8817117f1b4Smrg         }
8827117f1b4Smrg      }
8837117f1b4Smrg   }
8847117f1b4Smrg   else {
885c1f859d4Smrg      blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
886c1f859d4Smrg                          (GLfloat (*)[4]) dst, chanType);
8877117f1b4Smrg   }
8883464ebd5Sriastradh
8893464ebd5Sriastradh   free(rgbaF);
8903464ebd5Sriastradh   free(destF);
8917117f1b4Smrg}
8927117f1b4Smrg
8937117f1b4Smrg
8947117f1b4Smrg
8957117f1b4Smrg/**
8967117f1b4Smrg * Analyze current blending parameters to pick fastest blending function.
8977117f1b4Smrg * Result: the ctx->Color.BlendFunc pointer is updated.
8987117f1b4Smrg */
8997117f1b4Smrgvoid
9003464ebd5Sriastradh_swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
9017117f1b4Smrg{
9027117f1b4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
9033464ebd5Sriastradh   const GLenum eq = ctx->Color.Blend[0].EquationRGB;
9043464ebd5Sriastradh   const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
9053464ebd5Sriastradh   const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
9063464ebd5Sriastradh   const GLenum srcA = ctx->Color.Blend[0].SrcA;
9073464ebd5Sriastradh   const GLenum dstA = ctx->Color.Blend[0].DstA;
9087117f1b4Smrg
9093464ebd5Sriastradh   if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
9107117f1b4Smrg      swrast->BlendFunc = blend_general;
9117117f1b4Smrg   }
9127117f1b4Smrg   else if (eq == GL_MIN) {
9137117f1b4Smrg      /* Note: GL_MIN ignores the blending weight factors */
9147117f1b4Smrg#if defined(USE_MMX_ASM)
9157117f1b4Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
9167117f1b4Smrg         swrast->BlendFunc = _mesa_mmx_blend_min;
9177117f1b4Smrg      }
9187117f1b4Smrg      else
9197117f1b4Smrg#endif
9207117f1b4Smrg         swrast->BlendFunc = blend_min;
9217117f1b4Smrg   }
9227117f1b4Smrg   else if (eq == GL_MAX) {
9237117f1b4Smrg      /* Note: GL_MAX ignores the blending weight factors */
9247117f1b4Smrg#if defined(USE_MMX_ASM)
9257117f1b4Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
9267117f1b4Smrg         swrast->BlendFunc = _mesa_mmx_blend_max;
9277117f1b4Smrg      }
9287117f1b4Smrg      else
9297117f1b4Smrg#endif
9307117f1b4Smrg         swrast->BlendFunc = blend_max;
9317117f1b4Smrg   }
9327117f1b4Smrg   else if (srcRGB != srcA || dstRGB != dstA) {
9337117f1b4Smrg      swrast->BlendFunc = blend_general;
9347117f1b4Smrg   }
9357117f1b4Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
9367117f1b4Smrg            && dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
9377117f1b4Smrg#if defined(USE_MMX_ASM)
9387117f1b4Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
9397117f1b4Smrg         swrast->BlendFunc = _mesa_mmx_blend_transparency;
9407117f1b4Smrg      }
9417117f1b4Smrg      else
9427117f1b4Smrg#endif
9437117f1b4Smrg      {
9447117f1b4Smrg         if (chanType == GL_UNSIGNED_BYTE)
9457117f1b4Smrg            swrast->BlendFunc = blend_transparency_ubyte;
9467117f1b4Smrg         else if (chanType == GL_UNSIGNED_SHORT)
9477117f1b4Smrg            swrast->BlendFunc = blend_transparency_ushort;
9487117f1b4Smrg         else
9497117f1b4Smrg            swrast->BlendFunc = blend_transparency_float;
9507117f1b4Smrg      }
9517117f1b4Smrg   }
9527117f1b4Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
9537117f1b4Smrg#if defined(USE_MMX_ASM)
9547117f1b4Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
9557117f1b4Smrg         swrast->BlendFunc = _mesa_mmx_blend_add;
9567117f1b4Smrg      }
9577117f1b4Smrg      else
9587117f1b4Smrg#endif
9597117f1b4Smrg         swrast->BlendFunc = blend_add;
9607117f1b4Smrg   }
9617117f1b4Smrg   else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
9627117f1b4Smrg	     && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
9637117f1b4Smrg	    ||
9647117f1b4Smrg	    ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
9657117f1b4Smrg	     && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
9667117f1b4Smrg#if defined(USE_MMX_ASM)
9677117f1b4Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
9687117f1b4Smrg         swrast->BlendFunc = _mesa_mmx_blend_modulate;
9697117f1b4Smrg      }
9707117f1b4Smrg      else
9717117f1b4Smrg#endif
9727117f1b4Smrg         swrast->BlendFunc = blend_modulate;
9737117f1b4Smrg   }
9747117f1b4Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
9757117f1b4Smrg      swrast->BlendFunc = blend_noop;
9767117f1b4Smrg   }
9777117f1b4Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
9787117f1b4Smrg      swrast->BlendFunc = blend_replace;
9797117f1b4Smrg   }
9807117f1b4Smrg   else {
9817117f1b4Smrg      swrast->BlendFunc = blend_general;
9827117f1b4Smrg   }
9837117f1b4Smrg}
9847117f1b4Smrg
9857117f1b4Smrg
9867117f1b4Smrg
9877117f1b4Smrg/**
9887117f1b4Smrg * Apply the blending operator to a span of pixels.
9897117f1b4Smrg * We can handle horizontal runs of pixels (spans) or arrays of x/y
9907117f1b4Smrg * pixel coordinates.
9917117f1b4Smrg */
9927117f1b4Smrgvoid
9933464ebd5Sriastradh_swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
9947117f1b4Smrg{
9957117f1b4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
9967117f1b4Smrg   void *rbPixels;
9977117f1b4Smrg
99801e04c3fSmrg   assert(span->end <= SWRAST_MAX_WIDTH);
99901e04c3fSmrg   assert(span->arrayMask & SPAN_RGBA);
100001e04c3fSmrg   assert(!ctx->Color.ColorLogicOpEnabled);
10017117f1b4Smrg
10027117f1b4Smrg   rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
10037117f1b4Smrg
10047117f1b4Smrg   swrast->BlendFunc(ctx, span->end, span->array->mask,
10057117f1b4Smrg                     span->array->rgba, rbPixels, span->array->ChanType);
10067117f1b4Smrg}
1007