1 /** 2 * \file blend.c 3 * Blending operations. 4 */ 5 6 /* 7 * Mesa 3-D graphics library 8 * 9 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a 12 * copy of this software and associated documentation files (the "Software"), 13 * to deal in the Software without restriction, including without limitation 14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 * and/or sell copies of the Software, and to permit persons to whom the 16 * Software is furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included 19 * in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 * OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 31 32 #include "glheader.h" 33 #include "blend.h" 34 #include "context.h" 35 #include "enums.h" 36 #include "macros.h" 37 #include "mtypes.h" 38 39 40 41 /** 42 * Check if given blend source factor is legal. 43 * \return GL_TRUE if legal, GL_FALSE otherwise. 44 */ 45 static GLboolean 46 legal_src_factor(const struct gl_context *ctx, GLenum factor) 47 { 48 switch (factor) { 49 case GL_SRC_COLOR: 50 case GL_ONE_MINUS_SRC_COLOR: 51 case GL_ZERO: 52 case GL_ONE: 53 case GL_DST_COLOR: 54 case GL_ONE_MINUS_DST_COLOR: 55 case GL_SRC_ALPHA: 56 case GL_ONE_MINUS_SRC_ALPHA: 57 case GL_DST_ALPHA: 58 case GL_ONE_MINUS_DST_ALPHA: 59 case GL_SRC_ALPHA_SATURATE: 60 return GL_TRUE; 61 case GL_CONSTANT_COLOR: 62 case GL_ONE_MINUS_CONSTANT_COLOR: 63 case GL_CONSTANT_ALPHA: 64 case GL_ONE_MINUS_CONSTANT_ALPHA: 65 return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2; 66 case GL_SRC1_COLOR: 67 case GL_SRC1_ALPHA: 68 case GL_ONE_MINUS_SRC1_COLOR: 69 case GL_ONE_MINUS_SRC1_ALPHA: 70 return ctx->API != API_OPENGLES 71 && ctx->Extensions.ARB_blend_func_extended; 72 default: 73 return GL_FALSE; 74 } 75 } 76 77 78 /** 79 * Check if given blend destination factor is legal. 80 * \return GL_TRUE if legal, GL_FALSE otherwise. 81 */ 82 static GLboolean 83 legal_dst_factor(const struct gl_context *ctx, GLenum factor) 84 { 85 switch (factor) { 86 case GL_DST_COLOR: 87 case GL_ONE_MINUS_DST_COLOR: 88 case GL_ZERO: 89 case GL_ONE: 90 case GL_SRC_COLOR: 91 case GL_ONE_MINUS_SRC_COLOR: 92 case GL_SRC_ALPHA: 93 case GL_ONE_MINUS_SRC_ALPHA: 94 case GL_DST_ALPHA: 95 case GL_ONE_MINUS_DST_ALPHA: 96 return GL_TRUE; 97 case GL_CONSTANT_COLOR: 98 case GL_ONE_MINUS_CONSTANT_COLOR: 99 case GL_CONSTANT_ALPHA: 100 case GL_ONE_MINUS_CONSTANT_ALPHA: 101 return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2; 102 case GL_SRC_ALPHA_SATURATE: 103 return (ctx->API != API_OPENGLES 104 && ctx->Extensions.ARB_blend_func_extended) 105 || _mesa_is_gles3(ctx); 106 case GL_SRC1_COLOR: 107 case GL_SRC1_ALPHA: 108 case GL_ONE_MINUS_SRC1_COLOR: 109 case GL_ONE_MINUS_SRC1_ALPHA: 110 return ctx->API != API_OPENGLES 111 && ctx->Extensions.ARB_blend_func_extended; 112 default: 113 return GL_FALSE; 114 } 115 } 116 117 118 /** 119 * Check if src/dest RGB/A blend factors are legal. If not generate 120 * a GL error. 121 * \return GL_TRUE if factors are legal, GL_FALSE otherwise. 122 */ 123 static GLboolean 124 validate_blend_factors(struct gl_context *ctx, const char *func, 125 GLenum sfactorRGB, GLenum dfactorRGB, 126 GLenum sfactorA, GLenum dfactorA) 127 { 128 if (!legal_src_factor(ctx, sfactorRGB)) { 129 _mesa_error(ctx, GL_INVALID_ENUM, 130 "%s(sfactorRGB = %s)", func, 131 _mesa_enum_to_string(sfactorRGB)); 132 return GL_FALSE; 133 } 134 135 if (!legal_dst_factor(ctx, dfactorRGB)) { 136 _mesa_error(ctx, GL_INVALID_ENUM, 137 "%s(dfactorRGB = %s)", func, 138 _mesa_enum_to_string(dfactorRGB)); 139 return GL_FALSE; 140 } 141 142 if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { 143 _mesa_error(ctx, GL_INVALID_ENUM, 144 "%s(sfactorA = %s)", func, 145 _mesa_enum_to_string(sfactorA)); 146 return GL_FALSE; 147 } 148 149 if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { 150 _mesa_error(ctx, GL_INVALID_ENUM, 151 "%s(dfactorA = %s)", func, 152 _mesa_enum_to_string(dfactorA)); 153 return GL_FALSE; 154 } 155 156 return GL_TRUE; 157 } 158 159 160 static GLboolean 161 blend_factor_is_dual_src(GLenum factor) 162 { 163 return (factor == GL_SRC1_COLOR || 164 factor == GL_SRC1_ALPHA || 165 factor == GL_ONE_MINUS_SRC1_COLOR || 166 factor == GL_ONE_MINUS_SRC1_ALPHA); 167 } 168 169 static void 170 update_uses_dual_src(struct gl_context *ctx, int buf) 171 { 172 ctx->Color.Blend[buf]._UsesDualSrc = 173 (blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcRGB) || 174 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstRGB) || 175 blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcA) || 176 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstA)); 177 } 178 179 180 /** 181 * Return the number of per-buffer blend states to update in 182 * glBlendFunc, glBlendFuncSeparate, glBlendEquation, etc. 183 */ 184 static inline unsigned 185 num_buffers(const struct gl_context *ctx) 186 { 187 return ctx->Extensions.ARB_draw_buffers_blend 188 ? ctx->Const.MaxDrawBuffers : 1; 189 } 190 191 192 /* Returns true if there was no change */ 193 static bool 194 skip_blend_state_update(const struct gl_context *ctx, 195 GLenum sfactorRGB, GLenum dfactorRGB, 196 GLenum sfactorA, GLenum dfactorA) 197 { 198 /* Check if we're really changing any state. If not, return early. */ 199 if (ctx->Color._BlendFuncPerBuffer) { 200 const unsigned numBuffers = num_buffers(ctx); 201 202 /* Check all per-buffer states */ 203 for (unsigned buf = 0; buf < numBuffers; buf++) { 204 if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || 205 ctx->Color.Blend[buf].DstRGB != dfactorRGB || 206 ctx->Color.Blend[buf].SrcA != sfactorA || 207 ctx->Color.Blend[buf].DstA != dfactorA) { 208 return false; 209 } 210 } 211 } 212 else { 213 /* only need to check 0th per-buffer state */ 214 if (ctx->Color.Blend[0].SrcRGB != sfactorRGB || 215 ctx->Color.Blend[0].DstRGB != dfactorRGB || 216 ctx->Color.Blend[0].SrcA != sfactorA || 217 ctx->Color.Blend[0].DstA != dfactorA) { 218 return false; 219 } 220 } 221 222 return true; 223 } 224 225 226 static void 227 blend_func_separate(struct gl_context *ctx, 228 GLenum sfactorRGB, GLenum dfactorRGB, 229 GLenum sfactorA, GLenum dfactorA) 230 { 231 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewBlend ? 0 : _NEW_COLOR); 232 ctx->NewDriverState |= ctx->DriverFlags.NewBlend; 233 234 const unsigned numBuffers = num_buffers(ctx); 235 for (unsigned buf = 0; buf < numBuffers; buf++) { 236 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 237 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 238 ctx->Color.Blend[buf].SrcA = sfactorA; 239 ctx->Color.Blend[buf].DstA = dfactorA; 240 } 241 242 update_uses_dual_src(ctx, 0); 243 for (unsigned buf = 1; buf < numBuffers; buf++) { 244 ctx->Color.Blend[buf]._UsesDualSrc = ctx->Color.Blend[0]._UsesDualSrc; 245 } 246 247 ctx->Color._BlendFuncPerBuffer = GL_FALSE; 248 249 if (ctx->Driver.BlendFuncSeparate) { 250 ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, 251 sfactorA, dfactorA); 252 } 253 } 254 255 256 /** 257 * Specify the blending operation. 258 * 259 * \param sfactor source factor operator. 260 * \param dfactor destination factor operator. 261 * 262 * \sa glBlendFunc, glBlendFuncSeparateEXT 263 */ 264 void GLAPIENTRY 265 _mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 266 { 267 GET_CURRENT_CONTEXT(ctx); 268 269 if (skip_blend_state_update(ctx, sfactor, dfactor, sfactor, dfactor)) 270 return; 271 272 if (!validate_blend_factors(ctx, "glBlendFunc", 273 sfactor, dfactor, sfactor, dfactor)) { 274 return; 275 } 276 277 blend_func_separate(ctx, sfactor, dfactor, sfactor, dfactor); 278 } 279 280 281 void GLAPIENTRY 282 _mesa_BlendFunc_no_error(GLenum sfactor, GLenum dfactor) 283 { 284 GET_CURRENT_CONTEXT(ctx); 285 286 if (skip_blend_state_update(ctx, sfactor, dfactor, sfactor, dfactor)) 287 return; 288 289 blend_func_separate(ctx, sfactor, dfactor, sfactor, dfactor); 290 } 291 292 293 /** 294 * Set the separate blend source/dest factors for all draw buffers. 295 * 296 * \param sfactorRGB RGB source factor operator. 297 * \param dfactorRGB RGB destination factor operator. 298 * \param sfactorA alpha source factor operator. 299 * \param dfactorA alpha destination factor operator. 300 */ 301 void GLAPIENTRY 302 _mesa_BlendFuncSeparate( GLenum sfactorRGB, GLenum dfactorRGB, 303 GLenum sfactorA, GLenum dfactorA ) 304 { 305 GET_CURRENT_CONTEXT(ctx); 306 307 if (MESA_VERBOSE & VERBOSE_API) 308 _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", 309 _mesa_enum_to_string(sfactorRGB), 310 _mesa_enum_to_string(dfactorRGB), 311 _mesa_enum_to_string(sfactorA), 312 _mesa_enum_to_string(dfactorA)); 313 314 315 316 if (skip_blend_state_update(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA)) 317 return; 318 319 if (!validate_blend_factors(ctx, "glBlendFuncSeparate", 320 sfactorRGB, dfactorRGB, 321 sfactorA, dfactorA)) { 322 return; 323 } 324 325 blend_func_separate(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA); 326 } 327 328 329 void GLAPIENTRY 330 _mesa_BlendFuncSeparate_no_error(GLenum sfactorRGB, GLenum dfactorRGB, 331 GLenum sfactorA, GLenum dfactorA) 332 { 333 GET_CURRENT_CONTEXT(ctx); 334 335 if (skip_blend_state_update(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA)) 336 return; 337 338 blend_func_separate(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA); 339 } 340 341 342 void GLAPIENTRY 343 _mesa_BlendFunciARB_no_error(GLuint buf, GLenum sfactor, GLenum dfactor) 344 { 345 _mesa_BlendFuncSeparateiARB_no_error(buf, sfactor, dfactor, sfactor, 346 dfactor); 347 } 348 349 350 /** 351 * Set blend source/dest factors for one color buffer/target. 352 */ 353 void GLAPIENTRY 354 _mesa_BlendFunciARB(GLuint buf, GLenum sfactor, GLenum dfactor) 355 { 356 _mesa_BlendFuncSeparateiARB(buf, sfactor, dfactor, sfactor, dfactor); 357 } 358 359 360 static ALWAYS_INLINE void 361 blend_func_separatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, 362 GLenum sfactorA, GLenum dfactorA, bool no_error) 363 { 364 GET_CURRENT_CONTEXT(ctx); 365 366 if (!no_error) { 367 if (!ctx->Extensions.ARB_draw_buffers_blend) { 368 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); 369 return; 370 } 371 372 if (buf >= ctx->Const.MaxDrawBuffers) { 373 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", 374 buf); 375 return; 376 } 377 } 378 379 if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && 380 ctx->Color.Blend[buf].DstRGB == dfactorRGB && 381 ctx->Color.Blend[buf].SrcA == sfactorA && 382 ctx->Color.Blend[buf].DstA == dfactorA) 383 return; /* no change */ 384 385 if (!no_error && !validate_blend_factors(ctx, "glBlendFuncSeparatei", 386 sfactorRGB, dfactorRGB, 387 sfactorA, dfactorA)) { 388 return; 389 } 390 391 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewBlend ? 0 : _NEW_COLOR); 392 ctx->NewDriverState |= ctx->DriverFlags.NewBlend; 393 394 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 395 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 396 ctx->Color.Blend[buf].SrcA = sfactorA; 397 ctx->Color.Blend[buf].DstA = dfactorA; 398 update_uses_dual_src(ctx, buf); 399 ctx->Color._BlendFuncPerBuffer = GL_TRUE; 400 } 401 402 403 void GLAPIENTRY 404 _mesa_BlendFuncSeparateiARB_no_error(GLuint buf, GLenum sfactorRGB, 405 GLenum dfactorRGB, GLenum sfactorA, 406 GLenum dfactorA) 407 { 408 blend_func_separatei(buf, sfactorRGB, dfactorRGB, sfactorA, dfactorA, 409 true); 410 } 411 412 413 /** 414 * Set separate blend source/dest factors for one color buffer/target. 415 */ 416 void GLAPIENTRY 417 _mesa_BlendFuncSeparateiARB(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, 418 GLenum sfactorA, GLenum dfactorA) 419 { 420 blend_func_separatei(buf, sfactorRGB, dfactorRGB, sfactorA, dfactorA, 421 false); 422 } 423 424 425 /** 426 * Return true if \p mode is a legal blending equation, excluding 427 * GL_KHR_blend_equation_advanced modes. 428 */ 429 static bool 430 legal_simple_blend_equation(const struct gl_context *ctx, GLenum mode) 431 { 432 switch (mode) { 433 case GL_FUNC_ADD: 434 case GL_FUNC_SUBTRACT: 435 case GL_FUNC_REVERSE_SUBTRACT: 436 return GL_TRUE; 437 case GL_MIN: 438 case GL_MAX: 439 return ctx->Extensions.EXT_blend_minmax; 440 default: 441 return GL_FALSE; 442 } 443 } 444 445 static enum gl_advanced_blend_mode 446 advanced_blend_mode_from_gl_enum(GLenum mode) 447 { 448 switch (mode) { 449 case GL_MULTIPLY_KHR: 450 return BLEND_MULTIPLY; 451 case GL_SCREEN_KHR: 452 return BLEND_SCREEN; 453 case GL_OVERLAY_KHR: 454 return BLEND_OVERLAY; 455 case GL_DARKEN_KHR: 456 return BLEND_DARKEN; 457 case GL_LIGHTEN_KHR: 458 return BLEND_LIGHTEN; 459 case GL_COLORDODGE_KHR: 460 return BLEND_COLORDODGE; 461 case GL_COLORBURN_KHR: 462 return BLEND_COLORBURN; 463 case GL_HARDLIGHT_KHR: 464 return BLEND_HARDLIGHT; 465 case GL_SOFTLIGHT_KHR: 466 return BLEND_SOFTLIGHT; 467 case GL_DIFFERENCE_KHR: 468 return BLEND_DIFFERENCE; 469 case GL_EXCLUSION_KHR: 470 return BLEND_EXCLUSION; 471 case GL_HSL_HUE_KHR: 472 return BLEND_HSL_HUE; 473 case GL_HSL_SATURATION_KHR: 474 return BLEND_HSL_SATURATION; 475 case GL_HSL_COLOR_KHR: 476 return BLEND_HSL_COLOR; 477 case GL_HSL_LUMINOSITY_KHR: 478 return BLEND_HSL_LUMINOSITY; 479 default: 480 return BLEND_NONE; 481 } 482 } 483 484 /** 485 * If \p mode is one of the advanced blending equations defined by 486 * GL_KHR_blend_equation_advanced (and the extension is supported), 487 * return the corresponding BLEND_* enum. Otherwise, return BLEND_NONE 488 * (which can also be treated as false). 489 */ 490 static enum gl_advanced_blend_mode 491 advanced_blend_mode(const struct gl_context *ctx, GLenum mode) 492 { 493 return _mesa_has_KHR_blend_equation_advanced(ctx) ? 494 advanced_blend_mode_from_gl_enum(mode) : BLEND_NONE; 495 } 496 497 /* This is really an extension function! */ 498 void GLAPIENTRY 499 _mesa_BlendEquation( GLenum mode ) 500 { 501 GET_CURRENT_CONTEXT(ctx); 502 const unsigned numBuffers = num_buffers(ctx); 503 unsigned buf; 504 bool changed = false; 505 enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode); 506 507 if (MESA_VERBOSE & VERBOSE_API) 508 _mesa_debug(ctx, "glBlendEquation(%s)\n", 509 _mesa_enum_to_string(mode)); 510 511 if (ctx->Color._BlendEquationPerBuffer) { 512 /* Check all per-buffer states */ 513 for (buf = 0; buf < numBuffers; buf++) { 514 if (ctx->Color.Blend[buf].EquationRGB != mode || 515 ctx->Color.Blend[buf].EquationA != mode) { 516 changed = true; 517 break; 518 } 519 } 520 } 521 else { 522 /* only need to check 0th per-buffer state */ 523 if (ctx->Color.Blend[0].EquationRGB != mode || 524 ctx->Color.Blend[0].EquationA != mode) { 525 changed = true; 526 } 527 } 528 529 if (!changed) 530 return; 531 532 533 if (!legal_simple_blend_equation(ctx, mode) && !advanced_mode) { 534 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 535 return; 536 } 537 538 _mesa_flush_vertices_for_blend_state(ctx); 539 540 for (buf = 0; buf < numBuffers; buf++) { 541 ctx->Color.Blend[buf].EquationRGB = mode; 542 ctx->Color.Blend[buf].EquationA = mode; 543 } 544 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 545 ctx->Color._AdvancedBlendMode = advanced_mode; 546 547 if (ctx->Driver.BlendEquationSeparate) 548 ctx->Driver.BlendEquationSeparate(ctx, mode, mode); 549 } 550 551 552 /** 553 * Set blend equation for one color buffer/target. 554 */ 555 static void 556 blend_equationi(struct gl_context *ctx, GLuint buf, GLenum mode, 557 enum gl_advanced_blend_mode advanced_mode) 558 { 559 if (ctx->Color.Blend[buf].EquationRGB == mode && 560 ctx->Color.Blend[buf].EquationA == mode) 561 return; /* no change */ 562 563 _mesa_flush_vertices_for_blend_state(ctx); 564 ctx->Color.Blend[buf].EquationRGB = mode; 565 ctx->Color.Blend[buf].EquationA = mode; 566 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 567 568 if (buf == 0) 569 ctx->Color._AdvancedBlendMode = advanced_mode; 570 } 571 572 573 void GLAPIENTRY 574 _mesa_BlendEquationiARB_no_error(GLuint buf, GLenum mode) 575 { 576 GET_CURRENT_CONTEXT(ctx); 577 578 enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode); 579 blend_equationi(ctx, buf, mode, advanced_mode); 580 } 581 582 583 void GLAPIENTRY 584 _mesa_BlendEquationiARB(GLuint buf, GLenum mode) 585 { 586 GET_CURRENT_CONTEXT(ctx); 587 enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode); 588 589 if (MESA_VERBOSE & VERBOSE_API) 590 _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", 591 buf, _mesa_enum_to_string(mode)); 592 593 if (buf >= ctx->Const.MaxDrawBuffers) { 594 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationi(buffer=%u)", 595 buf); 596 return; 597 } 598 599 if (!legal_simple_blend_equation(ctx, mode) && !advanced_mode) { 600 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); 601 return; 602 } 603 604 blend_equationi(ctx, buf, mode, advanced_mode); 605 } 606 607 608 static void 609 blend_equation_separate(struct gl_context *ctx, GLenum modeRGB, GLenum modeA, 610 bool no_error) 611 { 612 const unsigned numBuffers = num_buffers(ctx); 613 unsigned buf; 614 bool changed = false; 615 616 if (ctx->Color._BlendEquationPerBuffer) { 617 /* Check all per-buffer states */ 618 for (buf = 0; buf < numBuffers; buf++) { 619 if (ctx->Color.Blend[buf].EquationRGB != modeRGB || 620 ctx->Color.Blend[buf].EquationA != modeA) { 621 changed = true; 622 break; 623 } 624 } 625 } else { 626 /* only need to check 0th per-buffer state */ 627 if (ctx->Color.Blend[0].EquationRGB != modeRGB || 628 ctx->Color.Blend[0].EquationA != modeA) { 629 changed = true; 630 } 631 } 632 633 if (!changed) 634 return; 635 636 if (!no_error) { 637 if ((modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate) { 638 _mesa_error(ctx, GL_INVALID_OPERATION, 639 "glBlendEquationSeparateEXT not supported by driver"); 640 return; 641 } 642 643 /* Only allow simple blending equations. 644 * The GL_KHR_blend_equation_advanced spec says: 645 * 646 * "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha> 647 * parameters of BlendEquationSeparate or BlendEquationSeparatei." 648 */ 649 if (!legal_simple_blend_equation(ctx, modeRGB)) { 650 _mesa_error(ctx, GL_INVALID_ENUM, 651 "glBlendEquationSeparateEXT(modeRGB)"); 652 return; 653 } 654 655 if (!legal_simple_blend_equation(ctx, modeA)) { 656 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 657 return; 658 } 659 } 660 661 _mesa_flush_vertices_for_blend_state(ctx); 662 663 for (buf = 0; buf < numBuffers; buf++) { 664 ctx->Color.Blend[buf].EquationRGB = modeRGB; 665 ctx->Color.Blend[buf].EquationA = modeA; 666 } 667 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 668 ctx->Color._AdvancedBlendMode = BLEND_NONE; 669 670 if (ctx->Driver.BlendEquationSeparate) 671 ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); 672 } 673 674 675 void GLAPIENTRY 676 _mesa_BlendEquationSeparate_no_error(GLenum modeRGB, GLenum modeA) 677 { 678 GET_CURRENT_CONTEXT(ctx); 679 blend_equation_separate(ctx, modeRGB, modeA, true); 680 } 681 682 683 void GLAPIENTRY 684 _mesa_BlendEquationSeparate(GLenum modeRGB, GLenum modeA) 685 { 686 GET_CURRENT_CONTEXT(ctx); 687 688 if (MESA_VERBOSE & VERBOSE_API) 689 _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", 690 _mesa_enum_to_string(modeRGB), 691 _mesa_enum_to_string(modeA)); 692 693 blend_equation_separate(ctx, modeRGB, modeA, false); 694 } 695 696 697 static ALWAYS_INLINE void 698 blend_equation_separatei(struct gl_context *ctx, GLuint buf, GLenum modeRGB, 699 GLenum modeA, bool no_error) 700 { 701 if (ctx->Color.Blend[buf].EquationRGB == modeRGB && 702 ctx->Color.Blend[buf].EquationA == modeA) 703 return; /* no change */ 704 705 if (!no_error) { 706 /* Only allow simple blending equations. 707 * The GL_KHR_blend_equation_advanced spec says: 708 * 709 * "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha> 710 * parameters of BlendEquationSeparate or BlendEquationSeparatei." 711 */ 712 if (!legal_simple_blend_equation(ctx, modeRGB)) { 713 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); 714 return; 715 } 716 717 if (!legal_simple_blend_equation(ctx, modeA)) { 718 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); 719 return; 720 } 721 } 722 723 _mesa_flush_vertices_for_blend_state(ctx); 724 ctx->Color.Blend[buf].EquationRGB = modeRGB; 725 ctx->Color.Blend[buf].EquationA = modeA; 726 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 727 ctx->Color._AdvancedBlendMode = BLEND_NONE; 728 } 729 730 731 void GLAPIENTRY 732 _mesa_BlendEquationSeparateiARB_no_error(GLuint buf, GLenum modeRGB, 733 GLenum modeA) 734 { 735 GET_CURRENT_CONTEXT(ctx); 736 blend_equation_separatei(ctx, buf, modeRGB, modeA, true); 737 } 738 739 740 /** 741 * Set separate blend equations for one color buffer/target. 742 */ 743 void GLAPIENTRY 744 _mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA) 745 { 746 GET_CURRENT_CONTEXT(ctx); 747 748 if (MESA_VERBOSE & VERBOSE_API) 749 _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, 750 _mesa_enum_to_string(modeRGB), 751 _mesa_enum_to_string(modeA)); 752 753 if (buf >= ctx->Const.MaxDrawBuffers) { 754 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", 755 buf); 756 return; 757 } 758 759 blend_equation_separatei(ctx, buf, modeRGB, modeA, false); 760 } 761 762 763 /** 764 * Set the blending color. 765 * 766 * \param red red color component. 767 * \param green green color component. 768 * \param blue blue color component. 769 * \param alpha alpha color component. 770 * 771 * \sa glBlendColor(). 772 * 773 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 774 * change, flushes the vertices and notifies the driver via 775 * dd_function_table::BlendColor callback. 776 */ 777 void GLAPIENTRY 778 _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 779 { 780 GLfloat tmp[4]; 781 GET_CURRENT_CONTEXT(ctx); 782 783 tmp[0] = red; 784 tmp[1] = green; 785 tmp[2] = blue; 786 tmp[3] = alpha; 787 788 if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) 789 return; 790 791 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewBlendColor ? 0 : _NEW_COLOR); 792 ctx->NewDriverState |= ctx->DriverFlags.NewBlendColor; 793 COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); 794 795 ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); 796 ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); 797 ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); 798 ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); 799 800 if (ctx->Driver.BlendColor) 801 ctx->Driver.BlendColor(ctx, ctx->Color.BlendColor); 802 } 803 804 805 /** 806 * Specify the alpha test function. 807 * 808 * \param func alpha comparison function. 809 * \param ref reference value. 810 * 811 * Verifies the parameters and updates gl_colorbuffer_attrib. 812 * On a change, flushes the vertices and notifies the driver via 813 * dd_function_table::AlphaFunc callback. 814 */ 815 void GLAPIENTRY 816 _mesa_AlphaFunc( GLenum func, GLclampf ref ) 817 { 818 GET_CURRENT_CONTEXT(ctx); 819 820 if (MESA_VERBOSE & VERBOSE_API) 821 _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", 822 _mesa_enum_to_string(func), ref); 823 824 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) 825 return; /* no change */ 826 827 switch (func) { 828 case GL_NEVER: 829 case GL_LESS: 830 case GL_EQUAL: 831 case GL_LEQUAL: 832 case GL_GREATER: 833 case GL_NOTEQUAL: 834 case GL_GEQUAL: 835 case GL_ALWAYS: 836 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewAlphaTest ? 0 : _NEW_COLOR); 837 ctx->NewDriverState |= ctx->DriverFlags.NewAlphaTest; 838 ctx->Color.AlphaFunc = func; 839 ctx->Color.AlphaRefUnclamped = ref; 840 ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); 841 842 if (ctx->Driver.AlphaFunc) 843 ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); 844 return; 845 846 default: 847 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 848 return; 849 } 850 } 851 852 853 static ALWAYS_INLINE void 854 logic_op(struct gl_context *ctx, GLenum opcode, bool no_error) 855 { 856 if (ctx->Color.LogicOp == opcode) 857 return; 858 859 if (!no_error) { 860 switch (opcode) { 861 case GL_CLEAR: 862 case GL_SET: 863 case GL_COPY: 864 case GL_COPY_INVERTED: 865 case GL_NOOP: 866 case GL_INVERT: 867 case GL_AND: 868 case GL_NAND: 869 case GL_OR: 870 case GL_NOR: 871 case GL_XOR: 872 case GL_EQUIV: 873 case GL_AND_REVERSE: 874 case GL_AND_INVERTED: 875 case GL_OR_REVERSE: 876 case GL_OR_INVERTED: 877 break; 878 default: 879 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 880 return; 881 } 882 } 883 884 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewLogicOp ? 0 : _NEW_COLOR); 885 ctx->NewDriverState |= ctx->DriverFlags.NewLogicOp; 886 ctx->Color.LogicOp = opcode; 887 888 if (ctx->Driver.LogicOpcode) 889 ctx->Driver.LogicOpcode(ctx, opcode); 890 } 891 892 893 /** 894 * Specify a logic pixel operation for color index rendering. 895 * 896 * \param opcode operation. 897 * 898 * Verifies that \p opcode is a valid enum and updates 899 * gl_colorbuffer_attrib::LogicOp. 900 * On a change, flushes the vertices and notifies the driver via the 901 * dd_function_table::LogicOpcode callback. 902 */ 903 void GLAPIENTRY 904 _mesa_LogicOp( GLenum opcode ) 905 { 906 GET_CURRENT_CONTEXT(ctx); 907 908 if (MESA_VERBOSE & VERBOSE_API) 909 _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_enum_to_string(opcode)); 910 911 logic_op(ctx, opcode, false); 912 } 913 914 915 void GLAPIENTRY 916 _mesa_LogicOp_no_error(GLenum opcode) 917 { 918 GET_CURRENT_CONTEXT(ctx); 919 logic_op(ctx, opcode, true); 920 } 921 922 923 void GLAPIENTRY 924 _mesa_IndexMask( GLuint mask ) 925 { 926 GET_CURRENT_CONTEXT(ctx); 927 928 if (ctx->Color.IndexMask == mask) 929 return; 930 931 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR); 932 ctx->NewDriverState |= ctx->DriverFlags.NewColorMask; 933 ctx->Color.IndexMask = mask; 934 } 935 936 937 /** 938 * Enable or disable writing of frame buffer color components. 939 * 940 * \param red whether to mask writing of the red color component. 941 * \param green whether to mask writing of the green color component. 942 * \param blue whether to mask writing of the blue color component. 943 * \param alpha whether to mask writing of the alpha color component. 944 * 945 * \sa glColorMask(). 946 * 947 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 948 * change, flushes the vertices and notifies the driver via the 949 * dd_function_table::ColorMask callback. 950 */ 951 void GLAPIENTRY 952 _mesa_ColorMask( GLboolean red, GLboolean green, 953 GLboolean blue, GLboolean alpha ) 954 { 955 GET_CURRENT_CONTEXT(ctx); 956 GLubyte tmp[4]; 957 GLuint i; 958 GLboolean flushed; 959 960 if (MESA_VERBOSE & VERBOSE_API) 961 _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", 962 red, green, blue, alpha); 963 964 /* Shouldn't have any information about channel depth in core mesa 965 * -- should probably store these as the native booleans: 966 */ 967 tmp[RCOMP] = red ? 0xff : 0x0; 968 tmp[GCOMP] = green ? 0xff : 0x0; 969 tmp[BCOMP] = blue ? 0xff : 0x0; 970 tmp[ACOMP] = alpha ? 0xff : 0x0; 971 972 flushed = GL_FALSE; 973 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 974 if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { 975 if (!flushed) { 976 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR); 977 ctx->NewDriverState |= ctx->DriverFlags.NewColorMask; 978 } 979 flushed = GL_TRUE; 980 COPY_4UBV(ctx->Color.ColorMask[i], tmp); 981 } 982 } 983 984 if (ctx->Driver.ColorMask) 985 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 986 } 987 988 989 /** 990 * For GL_EXT_draw_buffers2 and GL3 991 */ 992 void GLAPIENTRY 993 _mesa_ColorMaski(GLuint buf, GLboolean red, GLboolean green, 994 GLboolean blue, GLboolean alpha) 995 { 996 GLubyte tmp[4]; 997 GET_CURRENT_CONTEXT(ctx); 998 999 if (MESA_VERBOSE & VERBOSE_API) 1000 _mesa_debug(ctx, "glColorMaski %u %d %d %d %d\n", 1001 buf, red, green, blue, alpha); 1002 1003 if (buf >= ctx->Const.MaxDrawBuffers) { 1004 _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaski(buf=%u)", buf); 1005 return; 1006 } 1007 1008 /* Shouldn't have any information about channel depth in core mesa 1009 * -- should probably store these as the native booleans: 1010 */ 1011 tmp[RCOMP] = red ? 0xff : 0x0; 1012 tmp[GCOMP] = green ? 0xff : 0x0; 1013 tmp[BCOMP] = blue ? 0xff : 0x0; 1014 tmp[ACOMP] = alpha ? 0xff : 0x0; 1015 1016 if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) 1017 return; 1018 1019 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR); 1020 ctx->NewDriverState |= ctx->DriverFlags.NewColorMask; 1021 COPY_4UBV(ctx->Color.ColorMask[buf], tmp); 1022 } 1023 1024 1025 void GLAPIENTRY 1026 _mesa_ClampColor(GLenum target, GLenum clamp) 1027 { 1028 GET_CURRENT_CONTEXT(ctx); 1029 1030 /* Check for both the extension and the GL version, since the Intel driver 1031 * does not advertise the extension in core profiles. 1032 */ 1033 if (ctx->Version <= 30 && !ctx->Extensions.ARB_color_buffer_float) { 1034 _mesa_error(ctx, GL_INVALID_OPERATION, "glClampColor()"); 1035 return; 1036 } 1037 1038 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 1039 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 1040 return; 1041 } 1042 1043 switch (target) { 1044 case GL_CLAMP_VERTEX_COLOR_ARB: 1045 if (ctx->API == API_OPENGL_CORE) 1046 goto invalid_enum; 1047 FLUSH_VERTICES(ctx, _NEW_LIGHT); 1048 ctx->Light.ClampVertexColor = clamp; 1049 _mesa_update_clamp_vertex_color(ctx, ctx->DrawBuffer); 1050 break; 1051 case GL_CLAMP_FRAGMENT_COLOR_ARB: 1052 if (ctx->API == API_OPENGL_CORE) 1053 goto invalid_enum; 1054 FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); 1055 ctx->Color.ClampFragmentColor = clamp; 1056 _mesa_update_clamp_fragment_color(ctx, ctx->DrawBuffer); 1057 break; 1058 case GL_CLAMP_READ_COLOR_ARB: 1059 ctx->Color.ClampReadColor = clamp; 1060 break; 1061 default: 1062 goto invalid_enum; 1063 } 1064 return; 1065 1066 invalid_enum: 1067 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColor(%s)", 1068 _mesa_enum_to_string(target)); 1069 } 1070 1071 static GLboolean 1072 get_clamp_color(const struct gl_framebuffer *fb, GLenum clamp) 1073 { 1074 if (clamp == GL_TRUE || clamp == GL_FALSE) 1075 return clamp; 1076 1077 assert(clamp == GL_FIXED_ONLY); 1078 if (!fb) 1079 return GL_TRUE; 1080 1081 return fb->_AllColorBuffersFixedPoint; 1082 } 1083 1084 GLboolean 1085 _mesa_get_clamp_fragment_color(const struct gl_context *ctx, 1086 const struct gl_framebuffer *drawFb) 1087 { 1088 return get_clamp_color(drawFb, ctx->Color.ClampFragmentColor); 1089 } 1090 1091 GLboolean 1092 _mesa_get_clamp_vertex_color(const struct gl_context *ctx, 1093 const struct gl_framebuffer *drawFb) 1094 { 1095 return get_clamp_color(drawFb, ctx->Light.ClampVertexColor); 1096 } 1097 1098 GLboolean 1099 _mesa_get_clamp_read_color(const struct gl_context *ctx, 1100 const struct gl_framebuffer *readFb) 1101 { 1102 return get_clamp_color(readFb, ctx->Color.ClampReadColor); 1103 } 1104 1105 /** 1106 * Update the ctx->Color._ClampFragmentColor field 1107 */ 1108 void 1109 _mesa_update_clamp_fragment_color(struct gl_context *ctx, 1110 const struct gl_framebuffer *drawFb) 1111 { 1112 /* Don't clamp if: 1113 * - there is no colorbuffer 1114 * - all colorbuffers are unsigned normalized, so clamping has no effect 1115 * - there is an integer colorbuffer 1116 */ 1117 if (!drawFb || !drawFb->_HasSNormOrFloatColorBuffer || 1118 drawFb->_IntegerBuffers) 1119 ctx->Color._ClampFragmentColor = GL_FALSE; 1120 else 1121 ctx->Color._ClampFragmentColor = 1122 _mesa_get_clamp_fragment_color(ctx, drawFb); 1123 } 1124 1125 /** 1126 * Update the ctx->Color._ClampVertexColor field 1127 */ 1128 void 1129 _mesa_update_clamp_vertex_color(struct gl_context *ctx, 1130 const struct gl_framebuffer *drawFb) 1131 { 1132 ctx->Light._ClampVertexColor = 1133 _mesa_get_clamp_vertex_color(ctx, drawFb); 1134 } 1135 1136 /** 1137 * Returns an appropriate mesa_format for color rendering based on the 1138 * GL_FRAMEBUFFER_SRGB state. 1139 * 1140 * Some drivers implement GL_FRAMEBUFFER_SRGB using a flag on the blend state 1141 * (which GL_FRAMEBUFFER_SRGB maps to reasonably), but some have to do so by 1142 * overriding the format of the surface. This is a helper for doing the 1143 * surface format override variant. 1144 */ 1145 mesa_format 1146 _mesa_get_render_format(const struct gl_context *ctx, mesa_format format) 1147 { 1148 if (ctx->Color.sRGBEnabled) 1149 return format; 1150 else 1151 return _mesa_get_srgb_format_linear(format); 1152 } 1153 1154 /**********************************************************************/ 1155 /** \name Initialization */ 1156 /*@{*/ 1157 1158 /** 1159 * Initialization of the context's Color attribute group. 1160 * 1161 * \param ctx GL context. 1162 * 1163 * Initializes the related fields in the context color attribute group, 1164 * __struct gl_contextRec::Color. 1165 */ 1166 void _mesa_init_color( struct gl_context * ctx ) 1167 { 1168 GLuint i; 1169 1170 /* Color buffer group */ 1171 ctx->Color.IndexMask = ~0u; 1172 memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); 1173 ctx->Color.ClearIndex = 0; 1174 ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 ); 1175 ctx->Color.AlphaEnabled = GL_FALSE; 1176 ctx->Color.AlphaFunc = GL_ALWAYS; 1177 ctx->Color.AlphaRef = 0; 1178 ctx->Color.BlendEnabled = 0x0; 1179 for (i = 0; i < ARRAY_SIZE(ctx->Color.Blend); i++) { 1180 ctx->Color.Blend[i].SrcRGB = GL_ONE; 1181 ctx->Color.Blend[i].DstRGB = GL_ZERO; 1182 ctx->Color.Blend[i].SrcA = GL_ONE; 1183 ctx->Color.Blend[i].DstA = GL_ZERO; 1184 ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; 1185 ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; 1186 } 1187 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 1188 ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); 1189 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 1190 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 1191 ctx->Color.LogicOp = GL_COPY; 1192 ctx->Color.DitherFlag = GL_TRUE; 1193 1194 /* GL_FRONT is not possible on GLES. Instead GL_BACK will render to either 1195 * the front or the back buffer depending on the config */ 1196 if (ctx->Visual.doubleBufferMode || _mesa_is_gles(ctx)) { 1197 ctx->Color.DrawBuffer[0] = GL_BACK; 1198 } 1199 else { 1200 ctx->Color.DrawBuffer[0] = GL_FRONT; 1201 } 1202 1203 ctx->Color.ClampFragmentColor = ctx->API == API_OPENGL_COMPAT ? 1204 GL_FIXED_ONLY_ARB : GL_FALSE; 1205 ctx->Color._ClampFragmentColor = GL_FALSE; 1206 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 1207 1208 /* GLES 1/2/3 behaves as though GL_FRAMEBUFFER_SRGB is always enabled 1209 * if EGL_KHR_gl_colorspace has been used to request sRGB. 1210 */ 1211 ctx->Color.sRGBEnabled = _mesa_is_gles(ctx); 1212 1213 ctx->Color.BlendCoherent = true; 1214 } 1215 1216 /*@}*/ 1217