Home | History | Annotate | Download | only in swrast
      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  */
     72 static void _BLENDAPI
     73 blend_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  */
    100 static void _BLENDAPI
    101 blend_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  */
    120 static void _BLENDAPI
    121 blend_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 
    165 static void _BLENDAPI
    166 blend_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 
    203 static void _BLENDAPI
    204 blend_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  */
    245 static void _BLENDAPI
    246 blend_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  */
    311 static void _BLENDAPI
    312 blend_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  */
    364 static void _BLENDAPI
    365 blend_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  */
    418 static void _BLENDAPI
    419 blend_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  */
    473 static void
    474 blend_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  */
    818 static void
    819 blend_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  */
    902 void
    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  */
    995 void
    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