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