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