s_blend.c revision b63e8556fa9655bdfcc69fa04663e854f7fb2fbd
1/* $Id: s_blend.c,v 1.16 2002/04/02 23:36:51 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 4.1 6 * 7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28 29#include "glheader.h" 30#include "context.h" 31#include "macros.h" 32 33#include "s_alphabuf.h" 34#include "s_blend.h" 35#include "s_context.h" 36#include "s_span.h" 37 38 39#if defined(USE_MMX_ASM) 40#include "X86/mmx.h" 41#include "X86/common_x86_asm.h" 42#define _BLENDAPI _ASMAPI 43#else 44#define _BLENDAPI 45#endif 46 47 48/* 49 * Special case for glBlendFunc(GL_ZERO, GL_ONE) 50 */ 51static void _BLENDAPI 52blend_noop( GLcontext *ctx, GLuint n, const GLubyte mask[], 53 GLchan rgba[][4], CONST GLchan dest[][4] ) 54{ 55 GLuint i; 56 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT); 57 ASSERT(ctx->Color.BlendSrcRGB==GL_ZERO); 58 ASSERT(ctx->Color.BlendDstRGB==GL_ONE); 59 (void) ctx; 60 61 for (i = 0; i < n; i++) { 62 if (mask[i]) { 63 rgba[i][RCOMP] = dest[i][RCOMP]; 64 rgba[i][GCOMP] = dest[i][GCOMP]; 65 rgba[i][BCOMP] = dest[i][BCOMP]; 66 rgba[i][ACOMP] = dest[i][ACOMP]; 67 } 68 } 69} 70 71 72/* 73 * Special case for glBlendFunc(GL_ONE, GL_ZERO) 74 */ 75static void _BLENDAPI 76blend_replace( GLcontext *ctx, GLuint n, const GLubyte mask[], 77 GLchan rgba[][4], CONST GLchan dest[][4] ) 78{ 79 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT); 80 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE); 81 ASSERT(ctx->Color.BlendDstRGB==GL_ZERO); 82 (void) ctx; 83 (void) n; 84 (void) mask; 85 (void) rgba; 86 (void) dest; 87} 88 89 90/* 91 * Common transparency blending mode. 92 */ 93static void _BLENDAPI 94blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[], 95 GLchan rgba[][4], CONST GLchan dest[][4] ) 96{ 97 GLuint i; 98 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT); 99 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA); 100 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA); 101 (void) ctx; 102 103 for (i=0;i<n;i++) { 104 if (mask[i]) { 105 const GLint t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */ 106 if (t == 0) { 107 /* 0% alpha */ 108 rgba[i][RCOMP] = dest[i][RCOMP]; 109 rgba[i][GCOMP] = dest[i][GCOMP]; 110 rgba[i][BCOMP] = dest[i][BCOMP]; 111 rgba[i][ACOMP] = dest[i][ACOMP]; 112 } 113 else if (t == CHAN_MAX) { 114 /* 100% alpha, no-op */ 115 } 116 else { 117#if 0 118 /* This is pretty close, but Glean complains */ 119 const GLint s = CHAN_MAX - t; 120 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8; 121 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8; 122 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8; 123 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8; 124#elif 0 125 /* This is slower but satisfies Glean */ 126 const GLint s = CHAN_MAX - t; 127 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255; 128 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255; 129 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255; 130 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255; 131#else 132#if CHAN_BITS == 8 133 /* This satisfies Glean and should be reasonably fast */ 134 /* Contributed by Nathan Hand */ 135#if 0 136#define DIV255(X) (((X) << 8) + (X) + 256) >> 16 137#else 138 GLint temp; 139#define DIV255(X) (temp = (X), ((temp << 8) + temp + 256) >> 16) 140#endif 141 const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP]; 142 const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP]; 143 const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP]; 144 const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP]; 145#undef DIV255 146#elif CHAN_BITS == 16 147 const GLfloat tt = (GLfloat) t / CHAN_MAXF; 148 const GLint r = (GLint) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]); 149 const GLint g = (GLint) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]); 150 const GLint b = (GLint) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]); 151 const GLint a = (GLint) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]); 152#else /* CHAN_BITS == 32 */ 153 const GLfloat tt = (GLfloat) t / CHAN_MAXF; 154 const GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]; 155 const GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]; 156 const GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]; 157 const GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]; 158#endif 159#endif 160 ASSERT(r <= CHAN_MAX); 161 ASSERT(g <= CHAN_MAX); 162 ASSERT(b <= CHAN_MAX); 163 ASSERT(a <= CHAN_MAX); 164 rgba[i][RCOMP] = (GLchan) r; 165 rgba[i][GCOMP] = (GLchan) g; 166 rgba[i][BCOMP] = (GLchan) b; 167 rgba[i][ACOMP] = (GLchan) a; 168 } 169 } 170 } 171} 172 173 174 175/* 176 * Add src and dest. 177 */ 178static void _BLENDAPI 179blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[], 180 GLchan rgba[][4], CONST GLchan dest[][4] ) 181{ 182 GLuint i; 183 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT); 184 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE); 185 ASSERT(ctx->Color.BlendDstRGB==GL_ONE); 186 (void) ctx; 187 188 for (i=0;i<n;i++) { 189 if (mask[i]) { 190 GLint r = rgba[i][RCOMP] + dest[i][RCOMP]; 191 GLint g = rgba[i][GCOMP] + dest[i][GCOMP]; 192 GLint b = rgba[i][BCOMP] + dest[i][BCOMP]; 193 GLint a = rgba[i][ACOMP] + dest[i][ACOMP]; 194 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX ); 195 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX ); 196 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX ); 197 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX ); 198 } 199 } 200} 201 202 203 204/* 205 * Blend min function (for GL_EXT_blend_minmax) 206 */ 207static void _BLENDAPI 208blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[], 209 GLchan rgba[][4], CONST GLchan dest[][4] ) 210{ 211 GLuint i; 212 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT); 213 (void) ctx; 214 215 for (i=0;i<n;i++) { 216 if (mask[i]) { 217 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] ); 218 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] ); 219 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] ); 220 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] ); 221 } 222 } 223} 224 225 226 227/* 228 * Blend max function (for GL_EXT_blend_minmax) 229 */ 230static void _BLENDAPI 231blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[], 232 GLchan rgba[][4], CONST GLchan dest[][4] ) 233{ 234 GLuint i; 235 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT); 236 (void) ctx; 237 238 for (i=0;i<n;i++) { 239 if (mask[i]) { 240 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] ); 241 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] ); 242 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] ); 243 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] ); 244 } 245 } 246} 247 248 249 250/* 251 * Modulate: result = src * dest 252 */ 253static void _BLENDAPI 254blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[], 255 GLchan rgba[][4], CONST GLchan dest[][4] ) 256{ 257 GLuint i; 258 (void) ctx; 259 260 for (i=0;i<n;i++) { 261 if (mask[i]) { 262#if CHAN_TYPE == GL_FLOAT 263 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP]; 264 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP]; 265 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP]; 266 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP]; 267#else 268 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8; 269 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8; 270 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8; 271 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8; 272 rgba[i][RCOMP] = (GLchan) r; 273 rgba[i][GCOMP] = (GLchan) g; 274 rgba[i][BCOMP] = (GLchan) b; 275 rgba[i][ACOMP] = (GLchan) a; 276#endif 277 } 278 } 279} 280 281 282 283/* 284 * General case blend pixels. 285 * Input: n - number of pixels 286 * mask - the usual write mask 287 * In/Out: rgba - the incoming and modified pixels 288 * Input: dest - the pixels from the dest color buffer 289 */ 290static void _BLENDAPI 291blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[], 292 GLchan rgba[][4], CONST GLchan dest[][4] ) 293{ 294 GLfloat rscale = 1.0F / CHAN_MAXF; 295 GLfloat gscale = 1.0F / CHAN_MAXF; 296 GLfloat bscale = 1.0F / CHAN_MAXF; 297 GLfloat ascale = 1.0F / CHAN_MAXF; 298 GLuint i; 299 300 for (i=0;i<n;i++) { 301 if (mask[i]) { 302 GLint Rs, Gs, Bs, As; /* Source colors */ 303 GLint Rd, Gd, Bd, Ad; /* Dest colors */ 304 GLfloat sR, sG, sB, sA; /* Source scaling */ 305 GLfloat dR, dG, dB, dA; /* Dest scaling */ 306 GLfloat r, g, b, a; 307 308 /* Source Color */ 309 Rs = rgba[i][RCOMP]; 310 Gs = rgba[i][GCOMP]; 311 Bs = rgba[i][BCOMP]; 312 As = rgba[i][ACOMP]; 313 314 /* Frame buffer color */ 315 Rd = dest[i][RCOMP]; 316 Gd = dest[i][GCOMP]; 317 Bd = dest[i][BCOMP]; 318 Ad = dest[i][ACOMP]; 319 320 /* Source RGB factor */ 321 switch (ctx->Color.BlendSrcRGB) { 322 case GL_ZERO: 323 sR = sG = sB = 0.0F; 324 break; 325 case GL_ONE: 326 sR = sG = sB = 1.0F; 327 break; 328 case GL_DST_COLOR: 329 sR = (GLfloat) Rd * rscale; 330 sG = (GLfloat) Gd * gscale; 331 sB = (GLfloat) Bd * bscale; 332 break; 333 case GL_ONE_MINUS_DST_COLOR: 334 sR = 1.0F - (GLfloat) Rd * rscale; 335 sG = 1.0F - (GLfloat) Gd * gscale; 336 sB = 1.0F - (GLfloat) Bd * bscale; 337 break; 338 case GL_SRC_ALPHA: 339 sR = sG = sB = (GLfloat) As * ascale; 340 break; 341 case GL_ONE_MINUS_SRC_ALPHA: 342 sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale; 343 break; 344 case GL_DST_ALPHA: 345 sR = sG = sB = (GLfloat) Ad * ascale; 346 break; 347 case GL_ONE_MINUS_DST_ALPHA: 348 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale; 349 break; 350 case GL_SRC_ALPHA_SATURATE: 351 if (As < CHAN_MAX - Ad) { 352 sR = sG = sB = (GLfloat) As * ascale; 353 } 354 else { 355 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale; 356 } 357 break; 358 case GL_CONSTANT_COLOR: 359 sR = ctx->Color.BlendColor[0]; 360 sG = ctx->Color.BlendColor[1]; 361 sB = ctx->Color.BlendColor[2]; 362 break; 363 case GL_ONE_MINUS_CONSTANT_COLOR: 364 sR = 1.0F - ctx->Color.BlendColor[0]; 365 sG = 1.0F - ctx->Color.BlendColor[1]; 366 sB = 1.0F - ctx->Color.BlendColor[2]; 367 break; 368 case GL_CONSTANT_ALPHA: 369 sR = sG = sB = ctx->Color.BlendColor[3]; 370 break; 371 case GL_ONE_MINUS_CONSTANT_ALPHA: 372 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3]; 373 break; 374 case GL_SRC_COLOR: /* GL_NV_blend_square */ 375 sR = (GLfloat) Rs * rscale; 376 sG = (GLfloat) Gs * gscale; 377 sB = (GLfloat) Bs * bscale; 378 break; 379 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */ 380 sR = 1.0F - (GLfloat) Rs * rscale; 381 sG = 1.0F - (GLfloat) Gs * gscale; 382 sB = 1.0F - (GLfloat) Bs * bscale; 383 break; 384 default: 385 /* this should never happen */ 386 _mesa_problem(ctx, "Bad blend source RGB factor in do_blend"); 387 return; 388 } 389 390 /* Source Alpha factor */ 391 switch (ctx->Color.BlendSrcA) { 392 case GL_ZERO: 393 sA = 0.0F; 394 break; 395 case GL_ONE: 396 sA = 1.0F; 397 break; 398 case GL_DST_COLOR: 399 sA = (GLfloat) Ad * ascale; 400 break; 401 case GL_ONE_MINUS_DST_COLOR: 402 sA = 1.0F - (GLfloat) Ad * ascale; 403 break; 404 case GL_SRC_ALPHA: 405 sA = (GLfloat) As * ascale; 406 break; 407 case GL_ONE_MINUS_SRC_ALPHA: 408 sA = (GLfloat) 1.0F - (GLfloat) As * ascale; 409 break; 410 case GL_DST_ALPHA: 411 sA =(GLfloat) Ad * ascale; 412 break; 413 case GL_ONE_MINUS_DST_ALPHA: 414 sA = 1.0F - (GLfloat) Ad * ascale; 415 break; 416 case GL_SRC_ALPHA_SATURATE: 417 sA = 1.0; 418 break; 419 case GL_CONSTANT_COLOR: 420 sA = ctx->Color.BlendColor[3]; 421 break; 422 case GL_ONE_MINUS_CONSTANT_COLOR: 423 sA = 1.0F - ctx->Color.BlendColor[3]; 424 break; 425 case GL_CONSTANT_ALPHA: 426 sA = ctx->Color.BlendColor[3]; 427 break; 428 case GL_ONE_MINUS_CONSTANT_ALPHA: 429 sA = 1.0F - ctx->Color.BlendColor[3]; 430 break; 431 case GL_SRC_COLOR: /* GL_NV_blend_square */ 432 sA = (GLfloat) As * ascale; 433 break; 434 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */ 435 sA = 1.0F - (GLfloat) As * ascale; 436 break; 437 default: 438 /* this should never happen */ 439 sA = 0.0F; 440 _mesa_problem(ctx, "Bad blend source A factor in do_blend"); 441 } 442 443 /* Dest RGB factor */ 444 switch (ctx->Color.BlendDstRGB) { 445 case GL_ZERO: 446 dR = dG = dB = 0.0F; 447 break; 448 case GL_ONE: 449 dR = dG = dB = 1.0F; 450 break; 451 case GL_SRC_COLOR: 452 dR = (GLfloat) Rs * rscale; 453 dG = (GLfloat) Gs * gscale; 454 dB = (GLfloat) Bs * bscale; 455 break; 456 case GL_ONE_MINUS_SRC_COLOR: 457 dR = 1.0F - (GLfloat) Rs * rscale; 458 dG = 1.0F - (GLfloat) Gs * gscale; 459 dB = 1.0F - (GLfloat) Bs * bscale; 460 break; 461 case GL_SRC_ALPHA: 462 dR = dG = dB = (GLfloat) As * ascale; 463 break; 464 case GL_ONE_MINUS_SRC_ALPHA: 465 dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale; 466 break; 467 case GL_DST_ALPHA: 468 dR = dG = dB = (GLfloat) Ad * ascale; 469 break; 470 case GL_ONE_MINUS_DST_ALPHA: 471 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale; 472 break; 473 case GL_CONSTANT_COLOR: 474 dR = ctx->Color.BlendColor[0]; 475 dG = ctx->Color.BlendColor[1]; 476 dB = ctx->Color.BlendColor[2]; 477 break; 478 case GL_ONE_MINUS_CONSTANT_COLOR: 479 dR = 1.0F - ctx->Color.BlendColor[0]; 480 dG = 1.0F - ctx->Color.BlendColor[1]; 481 dB = 1.0F - ctx->Color.BlendColor[2]; 482 break; 483 case GL_CONSTANT_ALPHA: 484 dR = dG = dB = ctx->Color.BlendColor[3]; 485 break; 486 case GL_ONE_MINUS_CONSTANT_ALPHA: 487 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3]; 488 break; 489 case GL_DST_COLOR: /* GL_NV_blend_square */ 490 dR = (GLfloat) Rd * rscale; 491 dG = (GLfloat) Gd * gscale; 492 dB = (GLfloat) Bd * bscale; 493 break; 494 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */ 495 dR = 1.0F - (GLfloat) Rd * rscale; 496 dG = 1.0F - (GLfloat) Gd * gscale; 497 dB = 1.0F - (GLfloat) Bd * bscale; 498 break; 499 default: 500 /* this should never happen */ 501 dR = dG = dB = 0.0F; 502 _mesa_problem(ctx, "Bad blend dest RGB factor in do_blend"); 503 } 504 505 /* Dest Alpha factor */ 506 switch (ctx->Color.BlendDstA) { 507 case GL_ZERO: 508 dA = 0.0F; 509 break; 510 case GL_ONE: 511 dA = 1.0F; 512 break; 513 case GL_SRC_COLOR: 514 dA = (GLfloat) As * ascale; 515 break; 516 case GL_ONE_MINUS_SRC_COLOR: 517 dA = 1.0F - (GLfloat) As * ascale; 518 break; 519 case GL_SRC_ALPHA: 520 dA = (GLfloat) As * ascale; 521 break; 522 case GL_ONE_MINUS_SRC_ALPHA: 523 dA = (GLfloat) 1.0F - (GLfloat) As * ascale; 524 break; 525 case GL_DST_ALPHA: 526 dA = (GLfloat) Ad * ascale; 527 break; 528 case GL_ONE_MINUS_DST_ALPHA: 529 dA = 1.0F - (GLfloat) Ad * ascale; 530 break; 531 case GL_CONSTANT_COLOR: 532 dA = ctx->Color.BlendColor[3]; 533 break; 534 case GL_ONE_MINUS_CONSTANT_COLOR: 535 dA = 1.0F - ctx->Color.BlendColor[3]; 536 break; 537 case GL_CONSTANT_ALPHA: 538 dA = ctx->Color.BlendColor[3]; 539 break; 540 case GL_ONE_MINUS_CONSTANT_ALPHA: 541 dA = 1.0F - ctx->Color.BlendColor[3]; 542 break; 543 case GL_DST_COLOR: /* GL_NV_blend_square */ 544 dA = (GLfloat) Ad * ascale; 545 break; 546 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */ 547 dA = 1.0F - (GLfloat) Ad * ascale; 548 break; 549 default: 550 /* this should never happen */ 551 dA = 0.0F; 552 _mesa_problem(ctx, "Bad blend dest A factor in do_blend"); 553 return; 554 } 555 556 /* Due to round-off problems we have to clamp against zero. */ 557 /* Optimization: we don't have to do this for all src & dst factors */ 558 if (dA < 0.0F) dA = 0.0F; 559 if (dR < 0.0F) dR = 0.0F; 560 if (dG < 0.0F) dG = 0.0F; 561 if (dB < 0.0F) dB = 0.0F; 562 if (sA < 0.0F) sA = 0.0F; 563 if (sR < 0.0F) sR = 0.0F; 564 if (sG < 0.0F) sG = 0.0F; 565 if (sB < 0.0F) sB = 0.0F; 566 567 ASSERT( sR <= 1.0 ); 568 ASSERT( sG <= 1.0 ); 569 ASSERT( sB <= 1.0 ); 570 ASSERT( sA <= 1.0 ); 571 ASSERT( dR <= 1.0 ); 572 ASSERT( dG <= 1.0 ); 573 ASSERT( dB <= 1.0 ); 574 ASSERT( dA <= 1.0 ); 575 576 /* compute blended color */ 577 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) { 578 r = Rs * sR + Rd * dR + 0.5F; 579 g = Gs * sG + Gd * dG + 0.5F; 580 b = Bs * sB + Bd * dB + 0.5F; 581 a = As * sA + Ad * dA + 0.5F; 582 } 583 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) { 584 r = Rs * sR - Rd * dR + 0.5F; 585 g = Gs * sG - Gd * dG + 0.5F; 586 b = Bs * sB - Bd * dB + 0.5F; 587 a = As * sA - Ad * dA + 0.5F; 588 } 589 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) { 590 r = Rd * dR - Rs * sR + 0.5F; 591 g = Gd * dG - Gs * sG + 0.5F; 592 b = Bd * dB - Bs * sB + 0.5F; 593 a = Ad * dA - As * sA + 0.5F; 594 } 595 else { 596 /* should never get here */ 597 r = g = b = a = 0.0F; /* silence uninitialized var warning */ 598 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()"); 599 } 600 601 /* final clamping */ 602 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF ); 603 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF ); 604 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF ); 605 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF ); 606 } 607 } 608} 609 610 611 612 613 614/* 615 * Analyze current blending parameters to pick fastest blending function. 616 * Result: the ctx->Color.BlendFunc pointer is updated. 617 */ 618void _swrast_choose_blend_func( GLcontext *ctx ) 619{ 620 const GLenum eq = ctx->Color.BlendEquation; 621 const GLenum srcRGB = ctx->Color.BlendSrcRGB; 622 const GLenum dstRGB = ctx->Color.BlendDstRGB; 623 const GLenum srcA = ctx->Color.BlendSrcA; 624 const GLenum dstA = ctx->Color.BlendDstA; 625 626 if (srcRGB != srcA || dstRGB != dstA) { 627 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general; 628 } 629 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA 630 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) 631 { 632 /* XXX It looks like the MMX blend code is broken. Disable for now. */ 633#if 0 && defined(USE_MMX_ASM) 634 if ( cpu_has_mmx ) { 635 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency; 636 } 637 else 638#endif 639 SWRAST_CONTEXT(ctx)->BlendFunc = blend_transparency; 640 } 641 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) { 642 SWRAST_CONTEXT(ctx)->BlendFunc = blend_add; 643 } 644 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT) 645 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR)) 646 || 647 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT) 648 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) { 649 SWRAST_CONTEXT(ctx)->BlendFunc = blend_modulate; 650 } 651 else if (eq==GL_MIN_EXT) { 652 SWRAST_CONTEXT(ctx)->BlendFunc = blend_min; 653 } 654 else if (eq==GL_MAX_EXT) { 655 SWRAST_CONTEXT(ctx)->BlendFunc = blend_max; 656 } 657 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ZERO && dstRGB == GL_ONE) { 658 SWRAST_CONTEXT(ctx)->BlendFunc = blend_noop; 659 } 660 else if (eq==GL_FUNC_ADD_EXT && srcRGB == GL_ONE && dstRGB == GL_ZERO) { 661 SWRAST_CONTEXT(ctx)->BlendFunc = blend_replace; 662 } 663 else { 664 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general; 665 } 666} 667 668 669 670/* 671 * Apply the blending operator to a span of pixels. 672 * We can handle horizontal runs of pixels (spans) or arrays of x/y 673 * pixel coordinates. 674 */ 675void 676_mesa_blend_span( GLcontext *ctx, const struct sw_span *span, 677 GLchan rgba[][4] ) 678{ 679 SWcontext *swrast = SWRAST_CONTEXT(ctx); 680 GLchan framebuffer[MAX_WIDTH][4]; 681 682 ASSERT(span->end <= MAX_WIDTH); 683 ASSERT(span->arrayMask & SPAN_RGBA); 684 ASSERT(!ctx->Color.ColorLogicOpEnabled); 685 686 /* Read span of current frame buffer pixels */ 687 if (span->arrayMask & SPAN_XY) { 688 /* array of x/y pixel coords */ 689 (*swrast->Driver.ReadRGBAPixels)( ctx, span->end, 690 span->xArray, span->yArray, 691 framebuffer, span->mask ); 692 if (swrast->_RasterMask & ALPHABUF_BIT) { 693 _mesa_read_alpha_pixels( ctx, span->end, span->xArray, span->yArray, 694 framebuffer, span->mask ); 695 } 696 } 697 else { 698 /* horizontal run of pixels */ 699 _mesa_read_rgba_span( ctx, ctx->DrawBuffer, span->end, 700 span->x, span->y, framebuffer ); 701 } 702 703 SWRAST_CONTEXT(ctx)->BlendFunc( ctx, span->end, span->mask, rgba, 704 (const GLchan (*)[4]) framebuffer ); 705} 706