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 */ 45static GLboolean 46legal_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 */ 82static GLboolean 83legal_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 */ 123static GLboolean 124validate_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 160static GLboolean 161blend_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 169static void 170update_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 */ 184static inline unsigned 185num_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 */ 193static bool 194skip_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 226static void 227blend_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 */ 264void 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 281void 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 */ 301void 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 329void 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 342void 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 */ 353void GLAPIENTRY 354_mesa_BlendFunciARB(GLuint buf, GLenum sfactor, GLenum dfactor) 355{ 356 _mesa_BlendFuncSeparateiARB(buf, sfactor, dfactor, sfactor, dfactor); 357} 358 359 360static ALWAYS_INLINE void 361blend_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 403void 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 */ 416void 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 */ 429static bool 430legal_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 445static enum gl_advanced_blend_mode 446advanced_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 */ 490static enum gl_advanced_blend_mode 491advanced_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! */ 498void 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_adv(ctx, ctx->Color.BlendEnabled, 539 advanced_mode); 540 541 for (buf = 0; buf < numBuffers; buf++) { 542 ctx->Color.Blend[buf].EquationRGB = mode; 543 ctx->Color.Blend[buf].EquationA = mode; 544 } 545 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 546 ctx->Color._AdvancedBlendMode = advanced_mode; 547 548 if (ctx->Driver.BlendEquationSeparate) 549 ctx->Driver.BlendEquationSeparate(ctx, mode, mode); 550} 551 552 553/** 554 * Set blend equation for one color buffer/target. 555 */ 556static void 557blend_equationi(struct gl_context *ctx, GLuint buf, GLenum mode, 558 enum gl_advanced_blend_mode advanced_mode) 559{ 560 if (ctx->Color.Blend[buf].EquationRGB == mode && 561 ctx->Color.Blend[buf].EquationA == mode) 562 return; /* no change */ 563 564 _mesa_flush_vertices_for_blend_adv(ctx, ctx->Color.BlendEnabled, 565 advanced_mode); 566 ctx->Color.Blend[buf].EquationRGB = mode; 567 ctx->Color.Blend[buf].EquationA = mode; 568 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 569 570 if (buf == 0) 571 ctx->Color._AdvancedBlendMode = advanced_mode; 572} 573 574 575void GLAPIENTRY 576_mesa_BlendEquationiARB_no_error(GLuint buf, GLenum mode) 577{ 578 GET_CURRENT_CONTEXT(ctx); 579 580 enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode); 581 blend_equationi(ctx, buf, mode, advanced_mode); 582} 583 584 585void GLAPIENTRY 586_mesa_BlendEquationiARB(GLuint buf, GLenum mode) 587{ 588 GET_CURRENT_CONTEXT(ctx); 589 enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode); 590 591 if (MESA_VERBOSE & VERBOSE_API) 592 _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", 593 buf, _mesa_enum_to_string(mode)); 594 595 if (buf >= ctx->Const.MaxDrawBuffers) { 596 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationi(buffer=%u)", 597 buf); 598 return; 599 } 600 601 if (!legal_simple_blend_equation(ctx, mode) && !advanced_mode) { 602 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); 603 return; 604 } 605 606 blend_equationi(ctx, buf, mode, advanced_mode); 607} 608 609 610static void 611blend_equation_separate(struct gl_context *ctx, GLenum modeRGB, GLenum modeA, 612 bool no_error) 613{ 614 const unsigned numBuffers = num_buffers(ctx); 615 unsigned buf; 616 bool changed = false; 617 618 if (ctx->Color._BlendEquationPerBuffer) { 619 /* Check all per-buffer states */ 620 for (buf = 0; buf < numBuffers; buf++) { 621 if (ctx->Color.Blend[buf].EquationRGB != modeRGB || 622 ctx->Color.Blend[buf].EquationA != modeA) { 623 changed = true; 624 break; 625 } 626 } 627 } else { 628 /* only need to check 0th per-buffer state */ 629 if (ctx->Color.Blend[0].EquationRGB != modeRGB || 630 ctx->Color.Blend[0].EquationA != modeA) { 631 changed = true; 632 } 633 } 634 635 if (!changed) 636 return; 637 638 if (!no_error) { 639 if ((modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate) { 640 _mesa_error(ctx, GL_INVALID_OPERATION, 641 "glBlendEquationSeparateEXT not supported by driver"); 642 return; 643 } 644 645 /* Only allow simple blending equations. 646 * The GL_KHR_blend_equation_advanced spec says: 647 * 648 * "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha> 649 * parameters of BlendEquationSeparate or BlendEquationSeparatei." 650 */ 651 if (!legal_simple_blend_equation(ctx, modeRGB)) { 652 _mesa_error(ctx, GL_INVALID_ENUM, 653 "glBlendEquationSeparateEXT(modeRGB)"); 654 return; 655 } 656 657 if (!legal_simple_blend_equation(ctx, modeA)) { 658 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 659 return; 660 } 661 } 662 663 _mesa_flush_vertices_for_blend_state(ctx); 664 665 for (buf = 0; buf < numBuffers; buf++) { 666 ctx->Color.Blend[buf].EquationRGB = modeRGB; 667 ctx->Color.Blend[buf].EquationA = modeA; 668 } 669 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 670 ctx->Color._AdvancedBlendMode = BLEND_NONE; 671 672 if (ctx->Driver.BlendEquationSeparate) 673 ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); 674} 675 676 677void GLAPIENTRY 678_mesa_BlendEquationSeparate_no_error(GLenum modeRGB, GLenum modeA) 679{ 680 GET_CURRENT_CONTEXT(ctx); 681 blend_equation_separate(ctx, modeRGB, modeA, true); 682} 683 684 685void GLAPIENTRY 686_mesa_BlendEquationSeparate(GLenum modeRGB, GLenum modeA) 687{ 688 GET_CURRENT_CONTEXT(ctx); 689 690 if (MESA_VERBOSE & VERBOSE_API) 691 _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", 692 _mesa_enum_to_string(modeRGB), 693 _mesa_enum_to_string(modeA)); 694 695 blend_equation_separate(ctx, modeRGB, modeA, false); 696} 697 698 699static ALWAYS_INLINE void 700blend_equation_separatei(struct gl_context *ctx, GLuint buf, GLenum modeRGB, 701 GLenum modeA, bool no_error) 702{ 703 if (ctx->Color.Blend[buf].EquationRGB == modeRGB && 704 ctx->Color.Blend[buf].EquationA == modeA) 705 return; /* no change */ 706 707 if (!no_error) { 708 /* Only allow simple blending equations. 709 * The GL_KHR_blend_equation_advanced spec says: 710 * 711 * "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha> 712 * parameters of BlendEquationSeparate or BlendEquationSeparatei." 713 */ 714 if (!legal_simple_blend_equation(ctx, modeRGB)) { 715 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); 716 return; 717 } 718 719 if (!legal_simple_blend_equation(ctx, modeA)) { 720 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); 721 return; 722 } 723 } 724 725 _mesa_flush_vertices_for_blend_state(ctx); 726 ctx->Color.Blend[buf].EquationRGB = modeRGB; 727 ctx->Color.Blend[buf].EquationA = modeA; 728 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 729 ctx->Color._AdvancedBlendMode = BLEND_NONE; 730} 731 732 733void GLAPIENTRY 734_mesa_BlendEquationSeparateiARB_no_error(GLuint buf, GLenum modeRGB, 735 GLenum modeA) 736{ 737 GET_CURRENT_CONTEXT(ctx); 738 blend_equation_separatei(ctx, buf, modeRGB, modeA, true); 739} 740 741 742/** 743 * Set separate blend equations for one color buffer/target. 744 */ 745void GLAPIENTRY 746_mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA) 747{ 748 GET_CURRENT_CONTEXT(ctx); 749 750 if (MESA_VERBOSE & VERBOSE_API) 751 _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, 752 _mesa_enum_to_string(modeRGB), 753 _mesa_enum_to_string(modeA)); 754 755 if (buf >= ctx->Const.MaxDrawBuffers) { 756 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", 757 buf); 758 return; 759 } 760 761 blend_equation_separatei(ctx, buf, modeRGB, modeA, false); 762} 763 764 765/** 766 * Set the blending color. 767 * 768 * \param red red color component. 769 * \param green green color component. 770 * \param blue blue color component. 771 * \param alpha alpha color component. 772 * 773 * \sa glBlendColor(). 774 * 775 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 776 * change, flushes the vertices and notifies the driver via 777 * dd_function_table::BlendColor callback. 778 */ 779void GLAPIENTRY 780_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 781{ 782 GLfloat tmp[4]; 783 GET_CURRENT_CONTEXT(ctx); 784 785 tmp[0] = red; 786 tmp[1] = green; 787 tmp[2] = blue; 788 tmp[3] = alpha; 789 790 if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) 791 return; 792 793 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewBlendColor ? 0 : _NEW_COLOR); 794 ctx->NewDriverState |= ctx->DriverFlags.NewBlendColor; 795 COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); 796 797 ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); 798 ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); 799 ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); 800 ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); 801 802 if (ctx->Driver.BlendColor) 803 ctx->Driver.BlendColor(ctx, ctx->Color.BlendColor); 804} 805 806 807/** 808 * Specify the alpha test function. 809 * 810 * \param func alpha comparison function. 811 * \param ref reference value. 812 * 813 * Verifies the parameters and updates gl_colorbuffer_attrib. 814 * On a change, flushes the vertices and notifies the driver via 815 * dd_function_table::AlphaFunc callback. 816 */ 817void GLAPIENTRY 818_mesa_AlphaFunc( GLenum func, GLclampf ref ) 819{ 820 GET_CURRENT_CONTEXT(ctx); 821 822 if (MESA_VERBOSE & VERBOSE_API) 823 _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", 824 _mesa_enum_to_string(func), ref); 825 826 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) 827 return; /* no change */ 828 829 switch (func) { 830 case GL_NEVER: 831 case GL_LESS: 832 case GL_EQUAL: 833 case GL_LEQUAL: 834 case GL_GREATER: 835 case GL_NOTEQUAL: 836 case GL_GEQUAL: 837 case GL_ALWAYS: 838 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewAlphaTest ? 0 : _NEW_COLOR); 839 ctx->NewDriverState |= ctx->DriverFlags.NewAlphaTest; 840 ctx->Color.AlphaFunc = func; 841 ctx->Color.AlphaRefUnclamped = ref; 842 ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); 843 844 if (ctx->Driver.AlphaFunc) 845 ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); 846 return; 847 848 default: 849 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 850 return; 851 } 852} 853 854static const enum gl_logicop_mode color_logicop_mapping[16] = { 855 COLOR_LOGICOP_CLEAR, 856 COLOR_LOGICOP_AND, 857 COLOR_LOGICOP_AND_REVERSE, 858 COLOR_LOGICOP_COPY, 859 COLOR_LOGICOP_AND_INVERTED, 860 COLOR_LOGICOP_NOOP, 861 COLOR_LOGICOP_XOR, 862 COLOR_LOGICOP_OR, 863 COLOR_LOGICOP_NOR, 864 COLOR_LOGICOP_EQUIV, 865 COLOR_LOGICOP_INVERT, 866 COLOR_LOGICOP_OR_REVERSE, 867 COLOR_LOGICOP_COPY_INVERTED, 868 COLOR_LOGICOP_OR_INVERTED, 869 COLOR_LOGICOP_NAND, 870 COLOR_LOGICOP_SET 871}; 872 873static ALWAYS_INLINE void 874logic_op(struct gl_context *ctx, GLenum opcode, bool no_error) 875{ 876 if (ctx->Color.LogicOp == opcode) 877 return; 878 879 if (!no_error) { 880 switch (opcode) { 881 case GL_CLEAR: 882 case GL_SET: 883 case GL_COPY: 884 case GL_COPY_INVERTED: 885 case GL_NOOP: 886 case GL_INVERT: 887 case GL_AND: 888 case GL_NAND: 889 case GL_OR: 890 case GL_NOR: 891 case GL_XOR: 892 case GL_EQUIV: 893 case GL_AND_REVERSE: 894 case GL_AND_INVERTED: 895 case GL_OR_REVERSE: 896 case GL_OR_INVERTED: 897 break; 898 default: 899 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 900 return; 901 } 902 } 903 904 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewLogicOp ? 0 : _NEW_COLOR); 905 ctx->NewDriverState |= ctx->DriverFlags.NewLogicOp; 906 ctx->Color.LogicOp = opcode; 907 ctx->Color._LogicOp = color_logicop_mapping[opcode & 0x0f]; 908 909 if (ctx->Driver.LogicOpcode) 910 ctx->Driver.LogicOpcode(ctx, ctx->Color._LogicOp); 911} 912 913 914/** 915 * Specify a logic pixel operation for color index rendering. 916 * 917 * \param opcode operation. 918 * 919 * Verifies that \p opcode is a valid enum and updates 920 * gl_colorbuffer_attrib::LogicOp. 921 * On a change, flushes the vertices and notifies the driver via the 922 * dd_function_table::LogicOpcode callback. 923 */ 924void GLAPIENTRY 925_mesa_LogicOp( GLenum opcode ) 926{ 927 GET_CURRENT_CONTEXT(ctx); 928 929 if (MESA_VERBOSE & VERBOSE_API) 930 _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_enum_to_string(opcode)); 931 932 logic_op(ctx, opcode, false); 933} 934 935 936void GLAPIENTRY 937_mesa_LogicOp_no_error(GLenum opcode) 938{ 939 GET_CURRENT_CONTEXT(ctx); 940 logic_op(ctx, opcode, true); 941} 942 943 944void GLAPIENTRY 945_mesa_IndexMask( GLuint mask ) 946{ 947 GET_CURRENT_CONTEXT(ctx); 948 949 if (ctx->Color.IndexMask == mask) 950 return; 951 952 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR); 953 ctx->NewDriverState |= ctx->DriverFlags.NewColorMask; 954 ctx->Color.IndexMask = mask; 955} 956 957 958/** 959 * Enable or disable writing of frame buffer color components. 960 * 961 * \param red whether to mask writing of the red color component. 962 * \param green whether to mask writing of the green color component. 963 * \param blue whether to mask writing of the blue color component. 964 * \param alpha whether to mask writing of the alpha color component. 965 * 966 * \sa glColorMask(). 967 * 968 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 969 * change, flushes the vertices and notifies the driver via the 970 * dd_function_table::ColorMask callback. 971 */ 972void GLAPIENTRY 973_mesa_ColorMask( GLboolean red, GLboolean green, 974 GLboolean blue, GLboolean alpha ) 975{ 976 GET_CURRENT_CONTEXT(ctx); 977 978 if (MESA_VERBOSE & VERBOSE_API) 979 _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", 980 red, green, blue, alpha); 981 982 GLbitfield mask = (!!red) | 983 ((!!green) << 1) | 984 ((!!blue) << 2) | 985 ((!!alpha) << 3); 986 mask = _mesa_replicate_colormask(mask, ctx->Const.MaxDrawBuffers); 987 988 if (ctx->Color.ColorMask == mask) 989 return; 990 991 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR); 992 ctx->NewDriverState |= ctx->DriverFlags.NewColorMask; 993 ctx->Color.ColorMask = mask; 994 995 if (ctx->Driver.ColorMask) 996 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 997} 998 999 1000/** 1001 * For GL_EXT_draw_buffers2 and GL3 1002 */ 1003void GLAPIENTRY 1004_mesa_ColorMaski(GLuint buf, GLboolean red, GLboolean green, 1005 GLboolean blue, GLboolean alpha) 1006{ 1007 GET_CURRENT_CONTEXT(ctx); 1008 1009 if (MESA_VERBOSE & VERBOSE_API) 1010 _mesa_debug(ctx, "glColorMaski %u %d %d %d %d\n", 1011 buf, red, green, blue, alpha); 1012 1013 if (buf >= ctx->Const.MaxDrawBuffers) { 1014 _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaski(buf=%u)", buf); 1015 return; 1016 } 1017 1018 GLbitfield mask = (!!red) | 1019 ((!!green) << 1) | 1020 ((!!blue) << 2) | 1021 ((!!alpha) << 3); 1022 1023 if (GET_COLORMASK(ctx->Color.ColorMask, buf) == mask) 1024 return; 1025 1026 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR); 1027 ctx->NewDriverState |= ctx->DriverFlags.NewColorMask; 1028 ctx->Color.ColorMask &= ~(0xf << (4 * buf)); 1029 ctx->Color.ColorMask |= mask << (4 * buf); 1030} 1031 1032 1033void GLAPIENTRY 1034_mesa_ClampColor(GLenum target, GLenum clamp) 1035{ 1036 GET_CURRENT_CONTEXT(ctx); 1037 1038 /* Check for both the extension and the GL version, since the Intel driver 1039 * does not advertise the extension in core profiles. 1040 */ 1041 if (ctx->Version <= 30 && !ctx->Extensions.ARB_color_buffer_float) { 1042 _mesa_error(ctx, GL_INVALID_OPERATION, "glClampColor()"); 1043 return; 1044 } 1045 1046 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 1047 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 1048 return; 1049 } 1050 1051 switch (target) { 1052 case GL_CLAMP_VERTEX_COLOR_ARB: 1053 if (ctx->API == API_OPENGL_CORE) 1054 goto invalid_enum; 1055 FLUSH_VERTICES(ctx, _NEW_LIGHT); 1056 ctx->Light.ClampVertexColor = clamp; 1057 _mesa_update_clamp_vertex_color(ctx, ctx->DrawBuffer); 1058 break; 1059 case GL_CLAMP_FRAGMENT_COLOR_ARB: 1060 if (ctx->API == API_OPENGL_CORE) 1061 goto invalid_enum; 1062 FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); 1063 ctx->Color.ClampFragmentColor = clamp; 1064 _mesa_update_clamp_fragment_color(ctx, ctx->DrawBuffer); 1065 break; 1066 case GL_CLAMP_READ_COLOR_ARB: 1067 ctx->Color.ClampReadColor = clamp; 1068 break; 1069 default: 1070 goto invalid_enum; 1071 } 1072 return; 1073 1074invalid_enum: 1075 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColor(%s)", 1076 _mesa_enum_to_string(target)); 1077} 1078 1079static GLboolean 1080get_clamp_color(const struct gl_framebuffer *fb, GLenum clamp) 1081{ 1082 if (clamp == GL_TRUE || clamp == GL_FALSE) 1083 return clamp; 1084 1085 assert(clamp == GL_FIXED_ONLY); 1086 if (!fb) 1087 return GL_TRUE; 1088 1089 return fb->_AllColorBuffersFixedPoint; 1090} 1091 1092GLboolean 1093_mesa_get_clamp_fragment_color(const struct gl_context *ctx, 1094 const struct gl_framebuffer *drawFb) 1095{ 1096 return get_clamp_color(drawFb, ctx->Color.ClampFragmentColor); 1097} 1098 1099GLboolean 1100_mesa_get_clamp_vertex_color(const struct gl_context *ctx, 1101 const struct gl_framebuffer *drawFb) 1102{ 1103 return get_clamp_color(drawFb, ctx->Light.ClampVertexColor); 1104} 1105 1106GLboolean 1107_mesa_get_clamp_read_color(const struct gl_context *ctx, 1108 const struct gl_framebuffer *readFb) 1109{ 1110 return get_clamp_color(readFb, ctx->Color.ClampReadColor); 1111} 1112 1113/** 1114 * Update the ctx->Color._ClampFragmentColor field 1115 */ 1116void 1117_mesa_update_clamp_fragment_color(struct gl_context *ctx, 1118 const struct gl_framebuffer *drawFb) 1119{ 1120 /* Don't clamp if: 1121 * - there is no colorbuffer 1122 * - all colorbuffers are unsigned normalized, so clamping has no effect 1123 * - there is an integer colorbuffer 1124 */ 1125 if (!drawFb || !drawFb->_HasSNormOrFloatColorBuffer || 1126 drawFb->_IntegerBuffers) 1127 ctx->Color._ClampFragmentColor = GL_FALSE; 1128 else 1129 ctx->Color._ClampFragmentColor = 1130 _mesa_get_clamp_fragment_color(ctx, drawFb); 1131} 1132 1133/** 1134 * Update the ctx->Color._ClampVertexColor field 1135 */ 1136void 1137_mesa_update_clamp_vertex_color(struct gl_context *ctx, 1138 const struct gl_framebuffer *drawFb) 1139{ 1140 ctx->Light._ClampVertexColor = 1141 _mesa_get_clamp_vertex_color(ctx, drawFb); 1142} 1143 1144/** 1145 * Returns an appropriate mesa_format for color rendering based on the 1146 * GL_FRAMEBUFFER_SRGB state. 1147 * 1148 * Some drivers implement GL_FRAMEBUFFER_SRGB using a flag on the blend state 1149 * (which GL_FRAMEBUFFER_SRGB maps to reasonably), but some have to do so by 1150 * overriding the format of the surface. This is a helper for doing the 1151 * surface format override variant. 1152 */ 1153mesa_format 1154_mesa_get_render_format(const struct gl_context *ctx, mesa_format format) 1155{ 1156 if (ctx->Color.sRGBEnabled) 1157 return format; 1158 else 1159 return _mesa_get_srgb_format_linear(format); 1160} 1161 1162/**********************************************************************/ 1163/** \name Initialization */ 1164/*@{*/ 1165 1166/** 1167 * Initialization of the context's Color attribute group. 1168 * 1169 * \param ctx GL context. 1170 * 1171 * Initializes the related fields in the context color attribute group, 1172 * __struct gl_contextRec::Color. 1173 */ 1174void _mesa_init_color( struct gl_context * ctx ) 1175{ 1176 GLuint i; 1177 1178 /* Color buffer group */ 1179 ctx->Color.IndexMask = ~0u; 1180 ctx->Color.ColorMask = 0xffffffff; 1181 ctx->Color.ClearIndex = 0; 1182 ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 ); 1183 ctx->Color.AlphaEnabled = GL_FALSE; 1184 ctx->Color.AlphaFunc = GL_ALWAYS; 1185 ctx->Color.AlphaRef = 0; 1186 ctx->Color.BlendEnabled = 0x0; 1187 for (i = 0; i < ARRAY_SIZE(ctx->Color.Blend); i++) { 1188 ctx->Color.Blend[i].SrcRGB = GL_ONE; 1189 ctx->Color.Blend[i].DstRGB = GL_ZERO; 1190 ctx->Color.Blend[i].SrcA = GL_ONE; 1191 ctx->Color.Blend[i].DstA = GL_ZERO; 1192 ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; 1193 ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; 1194 } 1195 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 1196 ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); 1197 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 1198 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 1199 ctx->Color.LogicOp = GL_COPY; 1200 ctx->Color._LogicOp = COLOR_LOGICOP_COPY; 1201 ctx->Color.DitherFlag = GL_TRUE; 1202 1203 /* GL_FRONT is not possible on GLES. Instead GL_BACK will render to either 1204 * the front or the back buffer depending on the config */ 1205 if (ctx->Visual.doubleBufferMode || _mesa_is_gles(ctx)) { 1206 ctx->Color.DrawBuffer[0] = GL_BACK; 1207 } 1208 else { 1209 ctx->Color.DrawBuffer[0] = GL_FRONT; 1210 } 1211 1212 ctx->Color.ClampFragmentColor = ctx->API == API_OPENGL_COMPAT ? 1213 GL_FIXED_ONLY_ARB : GL_FALSE; 1214 ctx->Color._ClampFragmentColor = GL_FALSE; 1215 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 1216 1217 /* GLES 1/2/3 behaves as though GL_FRAMEBUFFER_SRGB is always enabled 1218 * if EGL_KHR_gl_colorspace has been used to request sRGB. 1219 */ 1220 ctx->Color.sRGBEnabled = _mesa_is_gles(ctx); 1221 1222 ctx->Color.BlendCoherent = true; 1223} 1224 1225/*@}*/ 1226