blend.c revision 40663864d2ee46afe246c15f5c4e6e380bb81720
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 _mesa_is_desktop_gl(ctx) 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 (_mesa_is_desktop_gl(ctx) 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 _mesa_is_desktop_gl(ctx) 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 160/** 161 * Specify the blending operation. 162 * 163 * \param sfactor source factor operator. 164 * \param dfactor destination factor operator. 165 * 166 * \sa glBlendFunc, glBlendFuncSeparateEXT 167 */ 168void GLAPIENTRY 169_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 170{ 171 _mesa_BlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); 172} 173 174static GLboolean 175blend_factor_is_dual_src(GLenum factor) 176{ 177 return (factor == GL_SRC1_COLOR || 178 factor == GL_SRC1_ALPHA || 179 factor == GL_ONE_MINUS_SRC1_COLOR || 180 factor == GL_ONE_MINUS_SRC1_ALPHA); 181} 182 183static void 184update_uses_dual_src(struct gl_context *ctx, int buf) 185{ 186 ctx->Color.Blend[buf]._UsesDualSrc = 187 (blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcRGB) || 188 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstRGB) || 189 blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcA) || 190 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstA)); 191} 192 193 194/** 195 * Return the number of per-buffer blend states to update in 196 * glBlendFunc, glBlendFuncSeparate, glBlendEquation, etc. 197 */ 198static inline unsigned 199num_buffers(const struct gl_context *ctx) 200{ 201 return ctx->Extensions.ARB_draw_buffers_blend 202 ? ctx->Const.MaxDrawBuffers : 1; 203} 204 205 206/** 207 * Set the separate blend source/dest factors for all draw buffers. 208 * 209 * \param sfactorRGB RGB source factor operator. 210 * \param dfactorRGB RGB destination factor operator. 211 * \param sfactorA alpha source factor operator. 212 * \param dfactorA alpha destination factor operator. 213 */ 214void GLAPIENTRY 215_mesa_BlendFuncSeparate( GLenum sfactorRGB, GLenum dfactorRGB, 216 GLenum sfactorA, GLenum dfactorA ) 217{ 218 GET_CURRENT_CONTEXT(ctx); 219 const unsigned numBuffers = num_buffers(ctx); 220 unsigned buf; 221 bool changed = false; 222 223 if (MESA_VERBOSE & VERBOSE_API) 224 _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", 225 _mesa_enum_to_string(sfactorRGB), 226 _mesa_enum_to_string(dfactorRGB), 227 _mesa_enum_to_string(sfactorA), 228 _mesa_enum_to_string(dfactorA)); 229 230 /* Check if we're really changing any state. If not, return early. */ 231 if (ctx->Color._BlendFuncPerBuffer) { 232 /* Check all per-buffer states */ 233 for (buf = 0; buf < numBuffers; buf++) { 234 if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || 235 ctx->Color.Blend[buf].DstRGB != dfactorRGB || 236 ctx->Color.Blend[buf].SrcA != sfactorA || 237 ctx->Color.Blend[buf].DstA != dfactorA) { 238 changed = true; 239 break; 240 } 241 } 242 } 243 else { 244 /* only need to check 0th per-buffer state */ 245 if (ctx->Color.Blend[0].SrcRGB != sfactorRGB || 246 ctx->Color.Blend[0].DstRGB != dfactorRGB || 247 ctx->Color.Blend[0].SrcA != sfactorA || 248 ctx->Color.Blend[0].DstA != dfactorA) { 249 changed = true; 250 } 251 } 252 253 if (!changed) 254 return; 255 256 if (!validate_blend_factors(ctx, "glBlendFuncSeparate", 257 sfactorRGB, dfactorRGB, 258 sfactorA, dfactorA)) { 259 return; 260 } 261 262 FLUSH_VERTICES(ctx, _NEW_COLOR); 263 264 for (buf = 0; buf < numBuffers; buf++) { 265 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 266 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 267 ctx->Color.Blend[buf].SrcA = sfactorA; 268 ctx->Color.Blend[buf].DstA = dfactorA; 269 } 270 271 update_uses_dual_src(ctx, 0); 272 for (buf = 1; buf < numBuffers; buf++) { 273 ctx->Color.Blend[buf]._UsesDualSrc = ctx->Color.Blend[0]._UsesDualSrc; 274 } 275 276 ctx->Color._BlendFuncPerBuffer = GL_FALSE; 277 278 if (ctx->Driver.BlendFuncSeparate) { 279 ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, 280 sfactorA, dfactorA); 281 } 282} 283 284 285/** 286 * Set blend source/dest factors for one color buffer/target. 287 */ 288void GLAPIENTRY 289_mesa_BlendFunciARB(GLuint buf, GLenum sfactor, GLenum dfactor) 290{ 291 _mesa_BlendFuncSeparateiARB(buf, sfactor, dfactor, sfactor, dfactor); 292} 293 294 295/** 296 * Set separate blend source/dest factors for one color buffer/target. 297 */ 298void GLAPIENTRY 299_mesa_BlendFuncSeparateiARB(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, 300 GLenum sfactorA, GLenum dfactorA) 301{ 302 GET_CURRENT_CONTEXT(ctx); 303 304 if (!ctx->Extensions.ARB_draw_buffers_blend) { 305 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); 306 return; 307 } 308 309 if (buf >= ctx->Const.MaxDrawBuffers) { 310 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", 311 buf); 312 return; 313 } 314 315 if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && 316 ctx->Color.Blend[buf].DstRGB == dfactorRGB && 317 ctx->Color.Blend[buf].SrcA == sfactorA && 318 ctx->Color.Blend[buf].DstA == dfactorA) 319 return; /* no change */ 320 321 if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", 322 sfactorRGB, dfactorRGB, 323 sfactorA, dfactorA)) { 324 return; 325 } 326 327 FLUSH_VERTICES(ctx, _NEW_COLOR); 328 329 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 330 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 331 ctx->Color.Blend[buf].SrcA = sfactorA; 332 ctx->Color.Blend[buf].DstA = dfactorA; 333 update_uses_dual_src(ctx, buf); 334 ctx->Color._BlendFuncPerBuffer = GL_TRUE; 335} 336 337 338/** 339 * Check if given blend equation is legal. 340 * \return GL_TRUE if legal, GL_FALSE otherwise. 341 */ 342static GLboolean 343legal_blend_equation(const struct gl_context *ctx, GLenum mode) 344{ 345 switch (mode) { 346 case GL_FUNC_ADD: 347 case GL_FUNC_SUBTRACT: 348 case GL_FUNC_REVERSE_SUBTRACT: 349 return GL_TRUE; 350 case GL_MIN: 351 case GL_MAX: 352 return ctx->Extensions.EXT_blend_minmax; 353 default: 354 return GL_FALSE; 355 } 356} 357 358 359/* This is really an extension function! */ 360void GLAPIENTRY 361_mesa_BlendEquation( GLenum mode ) 362{ 363 GET_CURRENT_CONTEXT(ctx); 364 const unsigned numBuffers = num_buffers(ctx); 365 unsigned buf; 366 bool changed = false; 367 368 if (MESA_VERBOSE & VERBOSE_API) 369 _mesa_debug(ctx, "glBlendEquation(%s)\n", 370 _mesa_enum_to_string(mode)); 371 372 if (ctx->Color._BlendEquationPerBuffer) { 373 /* Check all per-buffer states */ 374 for (buf = 0; buf < numBuffers; buf++) { 375 if (ctx->Color.Blend[buf].EquationRGB != mode || 376 ctx->Color.Blend[buf].EquationA != mode) { 377 changed = true; 378 break; 379 } 380 } 381 } 382 else { 383 /* only need to check 0th per-buffer state */ 384 if (ctx->Color.Blend[0].EquationRGB != mode || 385 ctx->Color.Blend[0].EquationA != mode) { 386 changed = true; 387 } 388 } 389 390 if (!changed) 391 return; 392 393 if (!legal_blend_equation(ctx, mode)) { 394 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 395 return; 396 } 397 398 FLUSH_VERTICES(ctx, _NEW_COLOR); 399 400 for (buf = 0; buf < numBuffers; buf++) { 401 ctx->Color.Blend[buf].EquationRGB = mode; 402 ctx->Color.Blend[buf].EquationA = mode; 403 } 404 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 405 406 if (ctx->Driver.BlendEquationSeparate) 407 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 408} 409 410 411/** 412 * Set blend equation for one color buffer/target. 413 */ 414void GLAPIENTRY 415_mesa_BlendEquationiARB(GLuint buf, GLenum mode) 416{ 417 GET_CURRENT_CONTEXT(ctx); 418 419 if (MESA_VERBOSE & VERBOSE_API) 420 _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", 421 buf, _mesa_enum_to_string(mode)); 422 423 if (buf >= ctx->Const.MaxDrawBuffers) { 424 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationi(buffer=%u)", 425 buf); 426 return; 427 } 428 429 if (!legal_blend_equation(ctx, mode)) { 430 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); 431 return; 432 } 433 434 if (ctx->Color.Blend[buf].EquationRGB == mode && 435 ctx->Color.Blend[buf].EquationA == mode) 436 return; /* no change */ 437 438 FLUSH_VERTICES(ctx, _NEW_COLOR); 439 ctx->Color.Blend[buf].EquationRGB = mode; 440 ctx->Color.Blend[buf].EquationA = mode; 441 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 442} 443 444 445void GLAPIENTRY 446_mesa_BlendEquationSeparate( GLenum modeRGB, GLenum modeA ) 447{ 448 GET_CURRENT_CONTEXT(ctx); 449 const unsigned numBuffers = num_buffers(ctx); 450 unsigned buf; 451 bool changed = false; 452 453 if (MESA_VERBOSE & VERBOSE_API) 454 _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", 455 _mesa_enum_to_string(modeRGB), 456 _mesa_enum_to_string(modeA)); 457 458 if (ctx->Color._BlendEquationPerBuffer) { 459 /* Check all per-buffer states */ 460 for (buf = 0; buf < numBuffers; buf++) { 461 if (ctx->Color.Blend[buf].EquationRGB != modeRGB || 462 ctx->Color.Blend[buf].EquationA != modeA) { 463 changed = true; 464 break; 465 } 466 } 467 } 468 else { 469 /* only need to check 0th per-buffer state */ 470 if (ctx->Color.Blend[0].EquationRGB != modeRGB || 471 ctx->Color.Blend[0].EquationA != modeA) { 472 changed = true; 473 } 474 } 475 476 if (!changed) 477 return; 478 479 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 480 _mesa_error(ctx, GL_INVALID_OPERATION, 481 "glBlendEquationSeparateEXT not supported by driver"); 482 return; 483 } 484 485 if (!legal_blend_equation(ctx, modeRGB)) { 486 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 487 return; 488 } 489 490 if (!legal_blend_equation(ctx, modeA)) { 491 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 492 return; 493 } 494 495 FLUSH_VERTICES(ctx, _NEW_COLOR); 496 497 for (buf = 0; buf < numBuffers; buf++) { 498 ctx->Color.Blend[buf].EquationRGB = modeRGB; 499 ctx->Color.Blend[buf].EquationA = modeA; 500 } 501 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 502 503 if (ctx->Driver.BlendEquationSeparate) 504 ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); 505} 506 507 508/** 509 * Set separate blend equations for one color buffer/target. 510 */ 511void GLAPIENTRY 512_mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA) 513{ 514 GET_CURRENT_CONTEXT(ctx); 515 516 if (MESA_VERBOSE & VERBOSE_API) 517 _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, 518 _mesa_enum_to_string(modeRGB), 519 _mesa_enum_to_string(modeA)); 520 521 if (buf >= ctx->Const.MaxDrawBuffers) { 522 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", 523 buf); 524 return; 525 } 526 527 if (!legal_blend_equation(ctx, modeRGB)) { 528 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); 529 return; 530 } 531 532 if (!legal_blend_equation(ctx, modeA)) { 533 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); 534 return; 535 } 536 537 if (ctx->Color.Blend[buf].EquationRGB == modeRGB && 538 ctx->Color.Blend[buf].EquationA == modeA) 539 return; /* no change */ 540 541 FLUSH_VERTICES(ctx, _NEW_COLOR); 542 ctx->Color.Blend[buf].EquationRGB = modeRGB; 543 ctx->Color.Blend[buf].EquationA = modeA; 544 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 545} 546 547 548/** 549 * Set the blending color. 550 * 551 * \param red red color component. 552 * \param green green color component. 553 * \param blue blue color component. 554 * \param alpha alpha color component. 555 * 556 * \sa glBlendColor(). 557 * 558 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 559 * change, flushes the vertices and notifies the driver via 560 * dd_function_table::BlendColor callback. 561 */ 562void GLAPIENTRY 563_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 564{ 565 GLfloat tmp[4]; 566 GET_CURRENT_CONTEXT(ctx); 567 568 tmp[0] = red; 569 tmp[1] = green; 570 tmp[2] = blue; 571 tmp[3] = alpha; 572 573 if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) 574 return; 575 576 FLUSH_VERTICES(ctx, _NEW_COLOR); 577 COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); 578 579 ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); 580 ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); 581 ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); 582 ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); 583 584 if (ctx->Driver.BlendColor) 585 (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor); 586} 587 588 589/** 590 * Specify the alpha test function. 591 * 592 * \param func alpha comparison function. 593 * \param ref reference value. 594 * 595 * Verifies the parameters and updates gl_colorbuffer_attrib. 596 * On a change, flushes the vertices and notifies the driver via 597 * dd_function_table::AlphaFunc callback. 598 */ 599void GLAPIENTRY 600_mesa_AlphaFunc( GLenum func, GLclampf ref ) 601{ 602 GET_CURRENT_CONTEXT(ctx); 603 604 if (MESA_VERBOSE & VERBOSE_API) 605 _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", 606 _mesa_enum_to_string(func), ref); 607 608 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) 609 return; /* no change */ 610 611 switch (func) { 612 case GL_NEVER: 613 case GL_LESS: 614 case GL_EQUAL: 615 case GL_LEQUAL: 616 case GL_GREATER: 617 case GL_NOTEQUAL: 618 case GL_GEQUAL: 619 case GL_ALWAYS: 620 FLUSH_VERTICES(ctx, _NEW_COLOR); 621 ctx->Color.AlphaFunc = func; 622 ctx->Color.AlphaRefUnclamped = ref; 623 ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); 624 625 if (ctx->Driver.AlphaFunc) 626 ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); 627 return; 628 629 default: 630 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 631 return; 632 } 633} 634 635 636/** 637 * Specify a logic pixel operation for color index rendering. 638 * 639 * \param opcode operation. 640 * 641 * Verifies that \p opcode is a valid enum and updates 642 * gl_colorbuffer_attrib::LogicOp. 643 * On a change, flushes the vertices and notifies the driver via the 644 * dd_function_table::LogicOpcode callback. 645 */ 646void GLAPIENTRY 647_mesa_LogicOp( GLenum opcode ) 648{ 649 GET_CURRENT_CONTEXT(ctx); 650 651 if (MESA_VERBOSE & VERBOSE_API) 652 _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_enum_to_string(opcode)); 653 654 switch (opcode) { 655 case GL_CLEAR: 656 case GL_SET: 657 case GL_COPY: 658 case GL_COPY_INVERTED: 659 case GL_NOOP: 660 case GL_INVERT: 661 case GL_AND: 662 case GL_NAND: 663 case GL_OR: 664 case GL_NOR: 665 case GL_XOR: 666 case GL_EQUIV: 667 case GL_AND_REVERSE: 668 case GL_AND_INVERTED: 669 case GL_OR_REVERSE: 670 case GL_OR_INVERTED: 671 break; 672 default: 673 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 674 return; 675 } 676 677 if (ctx->Color.LogicOp == opcode) 678 return; 679 680 FLUSH_VERTICES(ctx, _NEW_COLOR); 681 ctx->Color.LogicOp = opcode; 682 683 if (ctx->Driver.LogicOpcode) 684 ctx->Driver.LogicOpcode( ctx, opcode ); 685} 686 687 688void GLAPIENTRY 689_mesa_IndexMask( GLuint mask ) 690{ 691 GET_CURRENT_CONTEXT(ctx); 692 693 if (ctx->Color.IndexMask == mask) 694 return; 695 696 FLUSH_VERTICES(ctx, _NEW_COLOR); 697 ctx->Color.IndexMask = mask; 698} 699 700 701/** 702 * Enable or disable writing of frame buffer color components. 703 * 704 * \param red whether to mask writing of the red color component. 705 * \param green whether to mask writing of the green color component. 706 * \param blue whether to mask writing of the blue color component. 707 * \param alpha whether to mask writing of the alpha color component. 708 * 709 * \sa glColorMask(). 710 * 711 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 712 * change, flushes the vertices and notifies the driver via the 713 * dd_function_table::ColorMask callback. 714 */ 715void GLAPIENTRY 716_mesa_ColorMask( GLboolean red, GLboolean green, 717 GLboolean blue, GLboolean alpha ) 718{ 719 GET_CURRENT_CONTEXT(ctx); 720 GLubyte tmp[4]; 721 GLuint i; 722 GLboolean flushed; 723 724 if (MESA_VERBOSE & VERBOSE_API) 725 _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", 726 red, green, blue, alpha); 727 728 /* Shouldn't have any information about channel depth in core mesa 729 * -- should probably store these as the native booleans: 730 */ 731 tmp[RCOMP] = red ? 0xff : 0x0; 732 tmp[GCOMP] = green ? 0xff : 0x0; 733 tmp[BCOMP] = blue ? 0xff : 0x0; 734 tmp[ACOMP] = alpha ? 0xff : 0x0; 735 736 flushed = GL_FALSE; 737 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 738 if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { 739 if (!flushed) { 740 FLUSH_VERTICES(ctx, _NEW_COLOR); 741 } 742 flushed = GL_TRUE; 743 COPY_4UBV(ctx->Color.ColorMask[i], tmp); 744 } 745 } 746 747 if (ctx->Driver.ColorMask) 748 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 749} 750 751 752/** 753 * For GL_EXT_draw_buffers2 and GL3 754 */ 755void GLAPIENTRY 756_mesa_ColorMaski( GLuint buf, GLboolean red, GLboolean green, 757 GLboolean blue, GLboolean alpha ) 758{ 759 GLubyte tmp[4]; 760 GET_CURRENT_CONTEXT(ctx); 761 762 if (MESA_VERBOSE & VERBOSE_API) 763 _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", 764 buf, red, green, blue, alpha); 765 766 if (buf >= ctx->Const.MaxDrawBuffers) { 767 _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); 768 return; 769 } 770 771 /* Shouldn't have any information about channel depth in core mesa 772 * -- should probably store these as the native booleans: 773 */ 774 tmp[RCOMP] = red ? 0xff : 0x0; 775 tmp[GCOMP] = green ? 0xff : 0x0; 776 tmp[BCOMP] = blue ? 0xff : 0x0; 777 tmp[ACOMP] = alpha ? 0xff : 0x0; 778 779 if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) 780 return; 781 782 FLUSH_VERTICES(ctx, _NEW_COLOR); 783 COPY_4UBV(ctx->Color.ColorMask[buf], tmp); 784} 785 786 787void GLAPIENTRY 788_mesa_ClampColor(GLenum target, GLenum clamp) 789{ 790 GET_CURRENT_CONTEXT(ctx); 791 792 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 793 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 794 return; 795 } 796 797 switch (target) { 798 case GL_CLAMP_VERTEX_COLOR_ARB: 799 if (ctx->API == API_OPENGL_CORE && 800 !ctx->Extensions.ARB_color_buffer_float) { 801 goto invalid_enum; 802 } 803 FLUSH_VERTICES(ctx, _NEW_LIGHT); 804 ctx->Light.ClampVertexColor = clamp; 805 _mesa_update_clamp_vertex_color(ctx, ctx->DrawBuffer); 806 break; 807 case GL_CLAMP_FRAGMENT_COLOR_ARB: 808 if (ctx->API == API_OPENGL_CORE && 809 !ctx->Extensions.ARB_color_buffer_float) { 810 goto invalid_enum; 811 } 812 FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); 813 ctx->Color.ClampFragmentColor = clamp; 814 _mesa_update_clamp_fragment_color(ctx, ctx->DrawBuffer); 815 break; 816 case GL_CLAMP_READ_COLOR_ARB: 817 ctx->Color.ClampReadColor = clamp; 818 break; 819 default: 820 goto invalid_enum; 821 } 822 return; 823 824invalid_enum: 825 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColor(%s)", 826 _mesa_enum_to_string(target)); 827} 828 829static GLboolean 830get_clamp_color(const struct gl_framebuffer *fb, GLenum clamp) 831{ 832 if (clamp == GL_TRUE || clamp == GL_FALSE) 833 return clamp; 834 835 assert(clamp == GL_FIXED_ONLY); 836 if (!fb) 837 return GL_TRUE; 838 839 return fb->_AllColorBuffersFixedPoint; 840} 841 842GLboolean 843_mesa_get_clamp_fragment_color(const struct gl_context *ctx, 844 const struct gl_framebuffer *drawFb) 845{ 846 return get_clamp_color(drawFb, ctx->Color.ClampFragmentColor); 847} 848 849GLboolean 850_mesa_get_clamp_vertex_color(const struct gl_context *ctx, 851 const struct gl_framebuffer *drawFb) 852{ 853 return get_clamp_color(drawFb, ctx->Light.ClampVertexColor); 854} 855 856GLboolean 857_mesa_get_clamp_read_color(const struct gl_context *ctx, 858 const struct gl_framebuffer *readFb) 859{ 860 return get_clamp_color(readFb, ctx->Color.ClampReadColor); 861} 862 863/** 864 * Update the ctx->Color._ClampFragmentColor field 865 */ 866void 867_mesa_update_clamp_fragment_color(struct gl_context *ctx, 868 const struct gl_framebuffer *drawFb) 869{ 870 /* Don't clamp if: 871 * - there is no colorbuffer 872 * - all colorbuffers are unsigned normalized, so clamping has no effect 873 * - there is an integer colorbuffer 874 */ 875 if (!drawFb || !drawFb->_HasSNormOrFloatColorBuffer || 876 drawFb->_IntegerColor) 877 ctx->Color._ClampFragmentColor = GL_FALSE; 878 else 879 ctx->Color._ClampFragmentColor = 880 _mesa_get_clamp_fragment_color(ctx, drawFb); 881} 882 883/** 884 * Update the ctx->Color._ClampVertexColor field 885 */ 886void 887_mesa_update_clamp_vertex_color(struct gl_context *ctx, 888 const struct gl_framebuffer *drawFb) 889{ 890 ctx->Light._ClampVertexColor = 891 _mesa_get_clamp_vertex_color(ctx, drawFb); 892} 893 894/** 895 * Returns an appropriate mesa_format for color rendering based on the 896 * GL_FRAMEBUFFER_SRGB state. 897 * 898 * Some drivers implement GL_FRAMEBUFFER_SRGB using a flag on the blend state 899 * (which GL_FRAMEBUFFER_SRGB maps to reasonably), but some have to do so by 900 * overriding the format of the surface. This is a helper for doing the 901 * surface format override variant. 902 */ 903mesa_format 904_mesa_get_render_format(const struct gl_context *ctx, mesa_format format) 905{ 906 if (ctx->Color.sRGBEnabled) 907 return format; 908 else 909 return _mesa_get_srgb_format_linear(format); 910} 911 912/**********************************************************************/ 913/** \name Initialization */ 914/*@{*/ 915 916/** 917 * Initialization of the context's Color attribute group. 918 * 919 * \param ctx GL context. 920 * 921 * Initializes the related fields in the context color attribute group, 922 * __struct gl_contextRec::Color. 923 */ 924void _mesa_init_color( struct gl_context * ctx ) 925{ 926 GLuint i; 927 928 /* Color buffer group */ 929 ctx->Color.IndexMask = ~0u; 930 memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); 931 ctx->Color.ClearIndex = 0; 932 ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 ); 933 ctx->Color.AlphaEnabled = GL_FALSE; 934 ctx->Color.AlphaFunc = GL_ALWAYS; 935 ctx->Color.AlphaRef = 0; 936 ctx->Color.BlendEnabled = 0x0; 937 for (i = 0; i < ARRAY_SIZE(ctx->Color.Blend); i++) { 938 ctx->Color.Blend[i].SrcRGB = GL_ONE; 939 ctx->Color.Blend[i].DstRGB = GL_ZERO; 940 ctx->Color.Blend[i].SrcA = GL_ONE; 941 ctx->Color.Blend[i].DstA = GL_ZERO; 942 ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; 943 ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; 944 } 945 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 946 ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); 947 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 948 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 949 ctx->Color.LogicOp = GL_COPY; 950 ctx->Color.DitherFlag = GL_TRUE; 951 952 /* GL_FRONT is not possible on GLES. Instead GL_BACK will render to either 953 * the front or the back buffer depending on the config */ 954 if (ctx->Visual.doubleBufferMode || _mesa_is_gles(ctx)) { 955 ctx->Color.DrawBuffer[0] = GL_BACK; 956 } 957 else { 958 ctx->Color.DrawBuffer[0] = GL_FRONT; 959 } 960 961 ctx->Color.ClampFragmentColor = ctx->API == API_OPENGL_COMPAT ? 962 GL_FIXED_ONLY_ARB : GL_FALSE; 963 ctx->Color._ClampFragmentColor = GL_FALSE; 964 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 965 966 /* GLES 1/2/3 behaves as though GL_FRAMEBUFFER_SRGB is always enabled 967 * if EGL_KHR_gl_colorspace has been used to request sRGB. 968 */ 969 ctx->Color.sRGBEnabled = _mesa_is_gles(ctx); 970} 971 972/*@}*/ 973