blend.c revision fc2427e81b1c648550d0368652d6a475df785027
1/* $Id: blend.c,v 1.20 2000/10/23 00:16:28 gareth Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2000 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#ifdef PC_HEADER 30#include "all.h" 31#else 32#include "glheader.h" 33#include "alphabuf.h" 34#include "blend.h" 35#include "context.h" 36#include "enums.h" 37#include "macros.h" 38#include "pb.h" 39#include "span.h" 40#include "types.h" 41#endif 42 43 44void 45_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 46{ 47 GET_CURRENT_CONTEXT(ctx); 48 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFunc"); 49 50 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 51 fprintf(stderr, "glBlendFunc %s %s\n", 52 gl_lookup_enum_by_nr(sfactor), 53 gl_lookup_enum_by_nr(dfactor)); 54 55 switch (sfactor) { 56 case GL_SRC_COLOR: 57 case GL_ONE_MINUS_SRC_COLOR: 58 if (!ctx->Extensions.HaveBlendSquare) { 59 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" ); 60 return; 61 } 62 /* fall-through */ 63 case GL_ZERO: 64 case GL_ONE: 65 case GL_DST_COLOR: 66 case GL_ONE_MINUS_DST_COLOR: 67 case GL_SRC_ALPHA: 68 case GL_ONE_MINUS_SRC_ALPHA: 69 case GL_DST_ALPHA: 70 case GL_ONE_MINUS_DST_ALPHA: 71 case GL_SRC_ALPHA_SATURATE: 72 case GL_CONSTANT_COLOR: 73 case GL_ONE_MINUS_CONSTANT_COLOR: 74 case GL_CONSTANT_ALPHA: 75 case GL_ONE_MINUS_CONSTANT_ALPHA: 76 ctx->Color.BlendSrcRGB = ctx->Color.BlendSrcA = sfactor; 77 break; 78 default: 79 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" ); 80 return; 81 } 82 83 switch (dfactor) { 84 case GL_DST_COLOR: 85 case GL_ONE_MINUS_DST_COLOR: 86 if (!ctx->Extensions.HaveBlendSquare) { 87 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" ); 88 return; 89 } 90 /* fall-through */ 91 case GL_ZERO: 92 case GL_ONE: 93 case GL_SRC_COLOR: 94 case GL_ONE_MINUS_SRC_COLOR: 95 case GL_SRC_ALPHA: 96 case GL_ONE_MINUS_SRC_ALPHA: 97 case GL_DST_ALPHA: 98 case GL_ONE_MINUS_DST_ALPHA: 99 case GL_CONSTANT_COLOR: 100 case GL_ONE_MINUS_CONSTANT_COLOR: 101 case GL_CONSTANT_ALPHA: 102 case GL_ONE_MINUS_CONSTANT_ALPHA: 103 ctx->Color.BlendDstRGB = ctx->Color.BlendDstA = dfactor; 104 break; 105 default: 106 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" ); 107 return; 108 } 109 110 if (ctx->Driver.BlendFunc) { 111 (*ctx->Driver.BlendFunc)( ctx, sfactor, dfactor ); 112 } 113 114 ctx->Color.BlendFunc = NULL; 115 ctx->NewState |= NEW_RASTER_OPS; 116} 117 118 119/* GL_EXT_blend_func_separate */ 120void 121_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, 122 GLenum sfactorA, GLenum dfactorA ) 123{ 124 GET_CURRENT_CONTEXT(ctx); 125 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFuncSeparate"); 126 127 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 128 fprintf(stderr, "glBlendFuncSeperate %s %s %s %s\n", 129 gl_lookup_enum_by_nr(sfactorRGB), 130 gl_lookup_enum_by_nr(dfactorRGB), 131 gl_lookup_enum_by_nr(sfactorA), 132 gl_lookup_enum_by_nr(dfactorA)); 133 134 switch (sfactorRGB) { 135 case GL_SRC_COLOR: 136 case GL_ONE_MINUS_SRC_COLOR: 137 if (!ctx->Extensions.HaveBlendSquare) { 138 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)"); 139 return; 140 } 141 /* fall-through */ 142 case GL_ZERO: 143 case GL_ONE: 144 case GL_DST_COLOR: 145 case GL_ONE_MINUS_DST_COLOR: 146 case GL_SRC_ALPHA: 147 case GL_ONE_MINUS_SRC_ALPHA: 148 case GL_DST_ALPHA: 149 case GL_ONE_MINUS_DST_ALPHA: 150 case GL_SRC_ALPHA_SATURATE: 151 case GL_CONSTANT_COLOR: 152 case GL_ONE_MINUS_CONSTANT_COLOR: 153 case GL_CONSTANT_ALPHA: 154 case GL_ONE_MINUS_CONSTANT_ALPHA: 155 ctx->Color.BlendSrcRGB = sfactorRGB; 156 break; 157 default: 158 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)"); 159 return; 160 } 161 162 switch (dfactorRGB) { 163 case GL_DST_COLOR: 164 case GL_ONE_MINUS_DST_COLOR: 165 if (!ctx->Extensions.HaveBlendSquare) { 166 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)"); 167 return; 168 } 169 /* fall-through */ 170 case GL_ZERO: 171 case GL_ONE: 172 case GL_SRC_COLOR: 173 case GL_ONE_MINUS_SRC_COLOR: 174 case GL_SRC_ALPHA: 175 case GL_ONE_MINUS_SRC_ALPHA: 176 case GL_DST_ALPHA: 177 case GL_ONE_MINUS_DST_ALPHA: 178 case GL_CONSTANT_COLOR: 179 case GL_ONE_MINUS_CONSTANT_COLOR: 180 case GL_CONSTANT_ALPHA: 181 case GL_ONE_MINUS_CONSTANT_ALPHA: 182 ctx->Color.BlendDstRGB = dfactorRGB; 183 break; 184 default: 185 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)"); 186 return; 187 } 188 189 switch (sfactorA) { 190 case GL_SRC_COLOR: 191 case GL_ONE_MINUS_SRC_COLOR: 192 if (!ctx->Extensions.HaveBlendSquare) { 193 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)"); 194 return; 195 } 196 /* fall-through */ 197 case GL_ZERO: 198 case GL_ONE: 199 case GL_DST_COLOR: 200 case GL_ONE_MINUS_DST_COLOR: 201 case GL_SRC_ALPHA: 202 case GL_ONE_MINUS_SRC_ALPHA: 203 case GL_DST_ALPHA: 204 case GL_ONE_MINUS_DST_ALPHA: 205 case GL_SRC_ALPHA_SATURATE: 206 case GL_CONSTANT_COLOR: 207 case GL_ONE_MINUS_CONSTANT_COLOR: 208 case GL_CONSTANT_ALPHA: 209 case GL_ONE_MINUS_CONSTANT_ALPHA: 210 ctx->Color.BlendSrcA = sfactorA; 211 break; 212 default: 213 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)"); 214 return; 215 } 216 217 switch (dfactorA) { 218 case GL_DST_COLOR: 219 case GL_ONE_MINUS_DST_COLOR: 220 if (!ctx->Extensions.HaveBlendSquare) { 221 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)"); 222 return; 223 } 224 /* fall-through */ 225 case GL_ZERO: 226 case GL_ONE: 227 case GL_SRC_COLOR: 228 case GL_ONE_MINUS_SRC_COLOR: 229 case GL_SRC_ALPHA: 230 case GL_ONE_MINUS_SRC_ALPHA: 231 case GL_DST_ALPHA: 232 case GL_ONE_MINUS_DST_ALPHA: 233 case GL_CONSTANT_COLOR: 234 case GL_ONE_MINUS_CONSTANT_COLOR: 235 case GL_CONSTANT_ALPHA: 236 case GL_ONE_MINUS_CONSTANT_ALPHA: 237 ctx->Color.BlendDstA = dfactorA; 238 break; 239 default: 240 gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)" ); 241 return; 242 } 243 244 ctx->Color.BlendFunc = NULL; 245 ctx->NewState |= NEW_RASTER_OPS; 246 247 if (ctx->Driver.BlendFuncSeparate) { 248 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB, 249 sfactorA, dfactorA ); 250 } 251} 252 253 254 255/* This is really an extension function! */ 256void 257_mesa_BlendEquation( GLenum mode ) 258{ 259 GET_CURRENT_CONTEXT(ctx); 260 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendEquation"); 261 262 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 263 fprintf(stderr, "glBlendEquation %s\n", 264 gl_lookup_enum_by_nr(mode)); 265 266 switch (mode) { 267 case GL_MIN_EXT: 268 case GL_MAX_EXT: 269 case GL_FUNC_ADD_EXT: 270 if (ctx->Extensions.HaveBlendMinmax) { 271 ctx->Color.BlendEquation = mode; 272 } 273 else { 274 gl_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 275 return; 276 } 277 case GL_LOGIC_OP: 278 ctx->Color.BlendEquation = mode; 279 break; 280 case GL_FUNC_SUBTRACT_EXT: 281 case GL_FUNC_REVERSE_SUBTRACT_EXT: 282 if (ctx->Extensions.HaveBlendSubtract) { 283 ctx->Color.BlendEquation = mode; 284 } 285 else { 286 gl_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 287 return; 288 } 289 break; 290 default: 291 gl_error( ctx, GL_INVALID_ENUM, "glBlendEquation" ); 292 return; 293 } 294 295 /* This is needed to support 1.1's RGB logic ops AND 296 * 1.0's blending logicops. 297 */ 298 if (mode==GL_LOGIC_OP && ctx->Color.BlendEnabled) { 299 ctx->Color.ColorLogicOpEnabled = GL_TRUE; 300 } 301 else { 302 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 303 } 304 305 ctx->Color.BlendFunc = NULL; 306 ctx->NewState |= NEW_RASTER_OPS; 307 308 if (ctx->Driver.BlendEquation) 309 ctx->Driver.BlendEquation( ctx, mode ); 310} 311 312 313 314void 315_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 316{ 317 GET_CURRENT_CONTEXT(ctx); 318 ctx->Color.BlendColor[0] = CLAMP( red, 0.0F, 1.0F ); 319 ctx->Color.BlendColor[1] = CLAMP( green, 0.0F, 1.0F ); 320 ctx->Color.BlendColor[2] = CLAMP( blue, 0.0F, 1.0F ); 321 ctx->Color.BlendColor[3] = CLAMP( alpha, 0.0F, 1.0F ); 322} 323 324#ifdef USE_MMX_ASM 325#define _BLENDAPI _ASMAPI 326#else 327#define _BLENDAPI 328#endif 329 330/* 331 * Common transparency blending mode. 332 */ 333static void _BLENDAPI 334blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[], 335 GLubyte rgba[][4], CONST GLubyte dest[][4] ) 336{ 337 GLuint i; 338 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT); 339 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA); 340 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA); 341 (void) ctx; 342 343 for (i=0;i<n;i++) { 344 if (mask[i]) { 345 const GLint t = rgba[i][ACOMP]; /* t in [0,255] */ 346 if (t == 0) { 347 /* 0% alpha */ 348 rgba[i][RCOMP] = dest[i][RCOMP]; 349 rgba[i][GCOMP] = dest[i][GCOMP]; 350 rgba[i][BCOMP] = dest[i][BCOMP]; 351 rgba[i][ACOMP] = dest[i][ACOMP]; 352 } 353 else if (t == CHAN_MAX) { 354 /* 100% alpha, no-op */ 355 } 356 else { 357#if 0 358 /* This is pretty close, but Glean complains */ 359 const GLint s = CHAN_MAX - t; 360 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8; 361 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8; 362 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8; 363 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8; 364#elif 0 365 /* This is slower but satisfies Glean */ 366 const GLint s = CHAN_MAX - t; 367 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255; 368 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255; 369 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255; 370 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255; 371#else 372 /* This satisfies Glean and should be reasonably fast */ 373 /* Contributed by Nathan Hand */ 374#define DIV255(X) (((X) << 8) + (X) + 256) >> 16 375 const GLint s = CHAN_MAX - t; 376 const GLint r = DIV255(rgba[i][RCOMP] * t + dest[i][RCOMP] * s); 377 const GLint g = DIV255(rgba[i][GCOMP] * t + dest[i][GCOMP] * s); 378 const GLint b = DIV255(rgba[i][BCOMP] * t + dest[i][BCOMP] * s); 379 const GLint a = DIV255(rgba[i][ACOMP] * t + dest[i][ACOMP] * s); 380#undef DIV255 381#endif 382 ASSERT(r <= CHAN_MAX); 383 ASSERT(g <= CHAN_MAX); 384 ASSERT(b <= CHAN_MAX); 385 ASSERT(a <= CHAN_MAX); 386 rgba[i][RCOMP] = (GLubyte) r; 387 rgba[i][GCOMP] = (GLubyte) g; 388 rgba[i][BCOMP] = (GLubyte) b; 389 rgba[i][ACOMP] = (GLubyte) a; 390 } 391 } 392 } 393} 394 395 396 397/* 398 * Add src and dest. 399 */ 400static void _BLENDAPI 401blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[], 402 GLubyte rgba[][4], CONST GLubyte dest[][4] ) 403{ 404 GLuint i; 405 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT); 406 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE); 407 ASSERT(ctx->Color.BlendDstRGB==GL_ONE); 408 (void) ctx; 409 410 for (i=0;i<n;i++) { 411 if (mask[i]) { 412 GLint r = rgba[i][RCOMP] + dest[i][RCOMP]; 413 GLint g = rgba[i][GCOMP] + dest[i][GCOMP]; 414 GLint b = rgba[i][BCOMP] + dest[i][BCOMP]; 415 GLint a = rgba[i][ACOMP] + dest[i][ACOMP]; 416 rgba[i][RCOMP] = (GLubyte) MIN2( r, CHAN_MAX ); 417 rgba[i][GCOMP] = (GLubyte) MIN2( g, CHAN_MAX ); 418 rgba[i][BCOMP] = (GLubyte) MIN2( b, CHAN_MAX ); 419 rgba[i][ACOMP] = (GLubyte) MIN2( a, CHAN_MAX ); 420 } 421 } 422} 423 424 425 426/* 427 * Blend min function (for GL_EXT_blend_minmax) 428 */ 429static void _BLENDAPI 430blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[], 431 GLubyte rgba[][4], CONST GLubyte dest[][4] ) 432{ 433 GLuint i; 434 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT); 435 (void) ctx; 436 437 for (i=0;i<n;i++) { 438 if (mask[i]) { 439 rgba[i][RCOMP] = (GLubyte) MIN2( rgba[i][RCOMP], dest[i][RCOMP] ); 440 rgba[i][GCOMP] = (GLubyte) MIN2( rgba[i][GCOMP], dest[i][GCOMP] ); 441 rgba[i][BCOMP] = (GLubyte) MIN2( rgba[i][BCOMP], dest[i][BCOMP] ); 442 rgba[i][ACOMP] = (GLubyte) MIN2( rgba[i][ACOMP], dest[i][ACOMP] ); 443 } 444 } 445} 446 447 448 449/* 450 * Blend max function (for GL_EXT_blend_minmax) 451 */ 452static void _BLENDAPI 453blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[], 454 GLubyte rgba[][4], CONST GLubyte dest[][4] ) 455{ 456 GLuint i; 457 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT); 458 (void) ctx; 459 460 for (i=0;i<n;i++) { 461 if (mask[i]) { 462 rgba[i][RCOMP] = (GLubyte) MAX2( rgba[i][RCOMP], dest[i][RCOMP] ); 463 rgba[i][GCOMP] = (GLubyte) MAX2( rgba[i][GCOMP], dest[i][GCOMP] ); 464 rgba[i][BCOMP] = (GLubyte) MAX2( rgba[i][BCOMP], dest[i][BCOMP] ); 465 rgba[i][ACOMP] = (GLubyte) MAX2( rgba[i][ACOMP], dest[i][ACOMP] ); 466 } 467 } 468} 469 470 471 472/* 473 * Modulate: result = src * dest 474 */ 475static void _BLENDAPI 476blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[], 477 GLubyte rgba[][4], CONST GLubyte dest[][4] ) 478{ 479 GLuint i; 480 (void) ctx; 481 482 for (i=0;i<n;i++) { 483 if (mask[i]) { 484 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8; 485 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8; 486 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8; 487 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8; 488 rgba[i][RCOMP] = (GLubyte) r; 489 rgba[i][GCOMP] = (GLubyte) g; 490 rgba[i][BCOMP] = (GLubyte) b; 491 rgba[i][ACOMP] = (GLubyte) a; 492 } 493 } 494} 495 496 497 498/* 499 * General case blend pixels. 500 * Input: n - number of pixels 501 * mask - the usual write mask 502 * In/Out: rgba - the incoming and modified pixels 503 * Input: dest - the pixels from the dest color buffer 504 */ 505static void _BLENDAPI 506blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[], 507 GLubyte rgba[][4], CONST GLubyte dest[][4] ) 508{ 509 GLfloat rscale = 1.0F / CHAN_MAXF; 510 GLfloat gscale = 1.0F / CHAN_MAXF; 511 GLfloat bscale = 1.0F / CHAN_MAXF; 512 GLfloat ascale = 1.0F / CHAN_MAXF; 513 GLuint i; 514 515 for (i=0;i<n;i++) { 516 if (mask[i]) { 517 GLint Rs, Gs, Bs, As; /* Source colors */ 518 GLint Rd, Gd, Bd, Ad; /* Dest colors */ 519 GLfloat sR, sG, sB, sA; /* Source scaling */ 520 GLfloat dR, dG, dB, dA; /* Dest scaling */ 521 GLfloat r, g, b, a; 522 523 /* Source Color */ 524 Rs = rgba[i][RCOMP]; 525 Gs = rgba[i][GCOMP]; 526 Bs = rgba[i][BCOMP]; 527 As = rgba[i][ACOMP]; 528 529 /* Frame buffer color */ 530 Rd = dest[i][RCOMP]; 531 Gd = dest[i][GCOMP]; 532 Bd = dest[i][BCOMP]; 533 Ad = dest[i][ACOMP]; 534 535 /* Source RGB factor */ 536 switch (ctx->Color.BlendSrcRGB) { 537 case GL_ZERO: 538 sR = sG = sB = 0.0F; 539 break; 540 case GL_ONE: 541 sR = sG = sB = 1.0F; 542 break; 543 case GL_DST_COLOR: 544 sR = (GLfloat) Rd * rscale; 545 sG = (GLfloat) Gd * gscale; 546 sB = (GLfloat) Bd * bscale; 547 break; 548 case GL_ONE_MINUS_DST_COLOR: 549 sR = 1.0F - (GLfloat) Rd * rscale; 550 sG = 1.0F - (GLfloat) Gd * gscale; 551 sB = 1.0F - (GLfloat) Bd * bscale; 552 break; 553 case GL_SRC_ALPHA: 554 sR = sG = sB = (GLfloat) As * ascale; 555 break; 556 case GL_ONE_MINUS_SRC_ALPHA: 557 sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale; 558 break; 559 case GL_DST_ALPHA: 560 sR = sG = sB = (GLfloat) Ad * ascale; 561 break; 562 case GL_ONE_MINUS_DST_ALPHA: 563 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale; 564 break; 565 case GL_SRC_ALPHA_SATURATE: 566 if (As < CHAN_MAX - Ad) { 567 sR = sG = sB = (GLfloat) As * ascale; 568 } 569 else { 570 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale; 571 } 572 break; 573 case GL_CONSTANT_COLOR: 574 sR = ctx->Color.BlendColor[0]; 575 sG = ctx->Color.BlendColor[1]; 576 sB = ctx->Color.BlendColor[2]; 577 break; 578 case GL_ONE_MINUS_CONSTANT_COLOR: 579 sR = 1.0F - ctx->Color.BlendColor[0]; 580 sG = 1.0F - ctx->Color.BlendColor[1]; 581 sB = 1.0F - ctx->Color.BlendColor[2]; 582 break; 583 case GL_CONSTANT_ALPHA: 584 sR = sG = sB = ctx->Color.BlendColor[3]; 585 break; 586 case GL_ONE_MINUS_CONSTANT_ALPHA: 587 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3]; 588 break; 589 case GL_SRC_COLOR: /* GL_NV_blend_square */ 590 sR = (GLfloat) Rs * rscale; 591 sG = (GLfloat) Gs * gscale; 592 sB = (GLfloat) Bs * bscale; 593 break; 594 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */ 595 sR = 1.0F - (GLfloat) Rs * rscale; 596 sG = 1.0F - (GLfloat) Gs * gscale; 597 sB = 1.0F - (GLfloat) Bs * bscale; 598 break; 599 default: 600 /* this should never happen */ 601 gl_problem(ctx, "Bad blend source RGB factor in do_blend"); 602 return; 603 } 604 605 /* Source Alpha factor */ 606 switch (ctx->Color.BlendSrcA) { 607 case GL_ZERO: 608 sA = 0.0F; 609 break; 610 case GL_ONE: 611 sA = 1.0F; 612 break; 613 case GL_DST_COLOR: 614 sA = (GLfloat) Ad * ascale; 615 break; 616 case GL_ONE_MINUS_DST_COLOR: 617 sA = 1.0F - (GLfloat) Ad * ascale; 618 break; 619 case GL_SRC_ALPHA: 620 sA = (GLfloat) As * ascale; 621 break; 622 case GL_ONE_MINUS_SRC_ALPHA: 623 sA = (GLfloat) 1.0F - (GLfloat) As * ascale; 624 break; 625 case GL_DST_ALPHA: 626 sA =(GLfloat) Ad * ascale; 627 break; 628 case GL_ONE_MINUS_DST_ALPHA: 629 sA = 1.0F - (GLfloat) Ad * ascale; 630 break; 631 case GL_SRC_ALPHA_SATURATE: 632 sA = 1.0; 633 break; 634 case GL_CONSTANT_COLOR: 635 sA = ctx->Color.BlendColor[3]; 636 break; 637 case GL_ONE_MINUS_CONSTANT_COLOR: 638 sA = 1.0F - ctx->Color.BlendColor[3]; 639 break; 640 case GL_CONSTANT_ALPHA: 641 sA = ctx->Color.BlendColor[3]; 642 break; 643 case GL_ONE_MINUS_CONSTANT_ALPHA: 644 sA = 1.0F - ctx->Color.BlendColor[3]; 645 break; 646 case GL_SRC_COLOR: /* GL_NV_blend_square */ 647 sA = (GLfloat) As * ascale; 648 break; 649 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */ 650 sA = 1.0F - (GLfloat) As * ascale; 651 break; 652 default: 653 /* this should never happen */ 654 sA = 0.0F; 655 gl_problem(ctx, "Bad blend source A factor in do_blend"); 656 } 657 658 /* Dest RGB factor */ 659 switch (ctx->Color.BlendDstRGB) { 660 case GL_ZERO: 661 dR = dG = dB = 0.0F; 662 break; 663 case GL_ONE: 664 dR = dG = dB = 1.0F; 665 break; 666 case GL_SRC_COLOR: 667 dR = (GLfloat) Rs * rscale; 668 dG = (GLfloat) Gs * gscale; 669 dB = (GLfloat) Bs * bscale; 670 break; 671 case GL_ONE_MINUS_SRC_COLOR: 672 dR = 1.0F - (GLfloat) Rs * rscale; 673 dG = 1.0F - (GLfloat) Gs * gscale; 674 dB = 1.0F - (GLfloat) Bs * bscale; 675 break; 676 case GL_SRC_ALPHA: 677 dR = dG = dB = (GLfloat) As * ascale; 678 break; 679 case GL_ONE_MINUS_SRC_ALPHA: 680 dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale; 681 break; 682 case GL_DST_ALPHA: 683 dR = dG = dB = (GLfloat) Ad * ascale; 684 break; 685 case GL_ONE_MINUS_DST_ALPHA: 686 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale; 687 break; 688 case GL_CONSTANT_COLOR: 689 dR = ctx->Color.BlendColor[0]; 690 dG = ctx->Color.BlendColor[1]; 691 dB = ctx->Color.BlendColor[2]; 692 break; 693 case GL_ONE_MINUS_CONSTANT_COLOR: 694 dR = 1.0F - ctx->Color.BlendColor[0]; 695 dG = 1.0F - ctx->Color.BlendColor[1]; 696 dB = 1.0F - ctx->Color.BlendColor[2]; 697 break; 698 case GL_CONSTANT_ALPHA: 699 dR = dG = dB = ctx->Color.BlendColor[3]; 700 break; 701 case GL_ONE_MINUS_CONSTANT_ALPHA: 702 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3]; 703 break; 704 case GL_DST_COLOR: /* GL_NV_blend_square */ 705 dR = (GLfloat) Rd * rscale; 706 dG = (GLfloat) Gd * gscale; 707 dB = (GLfloat) Bd * bscale; 708 break; 709 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */ 710 dR = 1.0F - (GLfloat) Rd * rscale; 711 dG = 1.0F - (GLfloat) Gd * gscale; 712 dB = 1.0F - (GLfloat) Bd * bscale; 713 break; 714 default: 715 /* this should never happen */ 716 dR = dG = dB = 0.0F; 717 gl_problem(ctx, "Bad blend dest RGB factor in do_blend"); 718 } 719 720 /* Dest Alpha factor */ 721 switch (ctx->Color.BlendDstA) { 722 case GL_ZERO: 723 dA = 0.0F; 724 break; 725 case GL_ONE: 726 dA = 1.0F; 727 break; 728 case GL_SRC_COLOR: 729 dA = (GLfloat) As * ascale; 730 break; 731 case GL_ONE_MINUS_SRC_COLOR: 732 dA = 1.0F - (GLfloat) As * ascale; 733 break; 734 case GL_SRC_ALPHA: 735 dA = (GLfloat) As * ascale; 736 break; 737 case GL_ONE_MINUS_SRC_ALPHA: 738 dA = (GLfloat) 1.0F - (GLfloat) As * ascale; 739 break; 740 case GL_DST_ALPHA: 741 dA = (GLfloat) Ad * ascale; 742 break; 743 case GL_ONE_MINUS_DST_ALPHA: 744 dA = 1.0F - (GLfloat) Ad * ascale; 745 break; 746 case GL_CONSTANT_COLOR: 747 dA = ctx->Color.BlendColor[3]; 748 break; 749 case GL_ONE_MINUS_CONSTANT_COLOR: 750 dA = 1.0F - ctx->Color.BlendColor[3]; 751 break; 752 case GL_CONSTANT_ALPHA: 753 dA = ctx->Color.BlendColor[3]; 754 break; 755 case GL_ONE_MINUS_CONSTANT_ALPHA: 756 dA = 1.0F - ctx->Color.BlendColor[3]; 757 break; 758 case GL_DST_COLOR: /* GL_NV_blend_square */ 759 dA = (GLfloat) Ad * ascale; 760 break; 761 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */ 762 dA = 1.0F - (GLfloat) Ad * ascale; 763 break; 764 default: 765 /* this should never happen */ 766 dA = 0.0F; 767 gl_problem(ctx, "Bad blend dest A factor in do_blend"); 768 return; 769 } 770 771 /* Due to round-off problems we have to clamp against zero. */ 772 /* Optimization: we don't have to do this for all src & dst factors */ 773 if (dA < 0.0F) dA = 0.0F; 774 if (dR < 0.0F) dR = 0.0F; 775 if (dG < 0.0F) dG = 0.0F; 776 if (dB < 0.0F) dB = 0.0F; 777 if (sA < 0.0F) sA = 0.0F; 778 if (sR < 0.0F) sR = 0.0F; 779 if (sG < 0.0F) sG = 0.0F; 780 if (sB < 0.0F) sB = 0.0F; 781 782 ASSERT( sR <= 1.0 ); 783 ASSERT( sG <= 1.0 ); 784 ASSERT( sB <= 1.0 ); 785 ASSERT( sA <= 1.0 ); 786 ASSERT( dR <= 1.0 ); 787 ASSERT( dG <= 1.0 ); 788 ASSERT( dB <= 1.0 ); 789 ASSERT( dA <= 1.0 ); 790 791 /* compute blended color */ 792 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) { 793 r = Rs * sR + Rd * dR + 0.5F; 794 g = Gs * sG + Gd * dG + 0.5F; 795 b = Bs * sB + Bd * dB + 0.5F; 796 a = As * sA + Ad * dA + 0.5F; 797 } 798 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) { 799 r = Rs * sR - Rd * dR + 0.5F; 800 g = Gs * sG - Gd * dG + 0.5F; 801 b = Bs * sB - Bd * dB + 0.5F; 802 a = As * sA - Ad * dA + 0.5F; 803 } 804 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) { 805 r = Rd * dR - Rs * sR + 0.5F; 806 g = Gd * dG - Gs * sG + 0.5F; 807 b = Bd * dB - Bs * sB + 0.5F; 808 a = Ad * dA - As * sA + 0.5F; 809 } 810 else { 811 /* should never get here */ 812 r = g = b = a = 0.0F; /* silence uninitialized var warning */ 813 gl_problem(ctx, "unexpected BlendEquation in blend_general()"); 814 } 815 816 /* final clamping */ 817 rgba[i][RCOMP] = (GLubyte) (GLint) CLAMP( r, 0.0F, CHAN_MAXF ); 818 rgba[i][GCOMP] = (GLubyte) (GLint) CLAMP( g, 0.0F, CHAN_MAXF ); 819 rgba[i][BCOMP] = (GLubyte) (GLint) CLAMP( b, 0.0F, CHAN_MAXF ); 820 rgba[i][ACOMP] = (GLubyte) (GLint) CLAMP( a, 0.0F, CHAN_MAXF ); 821 } 822 } 823} 824 825 826 827#if defined(USE_MMX_ASM) 828#include "X86/mmx.h" 829#include "X86/common_x86_asm.h" 830#endif 831 832 833/* 834 * Analyze current blending parameters to pick fastest blending function. 835 * Result: the ctx->Color.BlendFunc pointer is updated. 836 */ 837static void set_blend_function( GLcontext *ctx ) 838{ 839 const GLenum eq = ctx->Color.BlendEquation; 840 const GLenum srcRGB = ctx->Color.BlendSrcRGB; 841 const GLenum dstRGB = ctx->Color.BlendDstRGB; 842 const GLenum srcA = ctx->Color.BlendSrcA; 843 const GLenum dstA = ctx->Color.BlendDstA; 844 845#if defined(USE_MMX_ASM) 846 /* Hmm. A table here would have 12^4 == way too many entries. 847 * Provide a hook for MMX instead. 848 */ 849 if ( cpu_has_mmx ) { 850 gl_mmx_set_blend_function( ctx ); 851 } 852 else 853#endif 854 if (srcRGB != srcA || dstRGB != dstA) { 855 ctx->Color.BlendFunc = blend_general; 856 } 857 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA 858 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) { 859 ctx->Color.BlendFunc = blend_transparency; 860 } 861 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) { 862 ctx->Color.BlendFunc = blend_add; 863 } 864 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT) 865 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR)) 866 || 867 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT) 868 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) { 869 ctx->Color.BlendFunc = blend_modulate; 870 } 871 else if (eq==GL_MIN_EXT) { 872 ctx->Color.BlendFunc = blend_min; 873 } 874 else if (eq==GL_MAX_EXT) { 875 ctx->Color.BlendFunc = blend_max; 876 } 877 else { 878 ctx->Color.BlendFunc = blend_general; 879 } 880} 881 882 883 884/* 885 * Apply the blending operator to a span of pixels. 886 * Input: n - number of pixels in span 887 * x, y - location of leftmost pixel in span in window coords. 888 * mask - boolean mask indicating which pixels to blend. 889 * In/Out: rgba - pixel values 890 */ 891void 892_mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 893 GLubyte rgba[][4], const GLubyte mask[] ) 894{ 895 GLubyte dest[MAX_WIDTH][4]; 896 897 /* Check if device driver can do the work */ 898 if (ctx->Color.BlendEquation==GL_LOGIC_OP && 899 !ctx->Color.ColorLogicOpEnabled) { 900 return; 901 } 902 903 /* Read span of current frame buffer pixels */ 904 gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest ); 905 906 if (!ctx->Color.BlendFunc) 907 set_blend_function(ctx); 908 909 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLubyte (*)[4])dest ); 910} 911 912 913 914/* 915 * Apply the blending operator to an array of pixels. 916 * Input: n - number of pixels in span 917 * x, y - array of pixel locations 918 * mask - boolean mask indicating which pixels to blend. 919 * In/Out: rgba - pixel values 920 */ 921void 922_mesa_blend_pixels( GLcontext *ctx, 923 GLuint n, const GLint x[], const GLint y[], 924 GLubyte rgba[][4], const GLubyte mask[] ) 925{ 926 GLubyte dest[PB_SIZE][4]; 927 928 /* Check if device driver can do the work */ 929 if (ctx->Color.BlendEquation==GL_LOGIC_OP && 930 !ctx->Color.ColorLogicOpEnabled) { 931 return; 932 } 933 934 /* Read pixels from current color buffer */ 935 (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask ); 936 if (ctx->RasterMask & ALPHABUF_BIT) { 937 _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask ); 938 } 939 940 if (!ctx->Color.BlendFunc) 941 set_blend_function(ctx); 942 943 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLubyte (*)[4])dest ); 944} 945