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